打字稿限制对象属性的数量

WHI*_*LOR 5 typescript

是否可以限制对象属性的数量,例如我想限制对象只有一个字符串属性(具有任何名称),我可以这样做:

{[index: string]: any}
Run Code Online (Sandbox Code Playgroud)

限制属性的类型,但是可以限制属性的数量吗?

Aid*_*din 9

这个问题在 Stackoverflow 上有很多答案(包括这个详细的答案),但没有一个适合我的情况,这与这里发布的类似。

问题

我有一个接受对象的函数。如果传递的对象没有一个键,我希望它抛出一个编译错误(Typescript)。例如

f({}); // Must error here, as it has less than one key!
f({ x: 5 });
f({ x: 5, y : 6 }); // Must error here, as it has more than one key!
Run Code Online (Sandbox Code Playgroud)

解决方案

使用流行的UnionToIntersectionIsUnion,我通过以下实用函数实现了它。

type SingleKey<T> = IsUnion<keyof T> extends true ? never : {} extends T ? never : T;
Run Code Online (Sandbox Code Playgroud)

完整代码:

// From /sf/answers/3526270051/
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;

// From: /sf/answers/3776880201/
type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true;

// Here we come!
type SingleKey<T> = IsUnion<keyof T> extends true ? never : {} extends T ? never : T;

// Usage:
function f<T extends Record<string, any>>(obj: SingleKey<T>) {
    console.log({ obj });
}

f({}); // errors here!
f({ x: 5 });
f({ x: 5, y : 6 }); // errors here!
Run Code Online (Sandbox Code Playgroud)

游乐场链接

  • Playground 链接已损坏,您现在可以在[此处](https://tsplay.dev/mx6Mzw) 找到它 (2认同)
  • @Aidin有没有办法用所有不同的键创建 SingleKey 数组?执行 `Array&lt;SingleKey&lt;T&gt;&gt;` 使得它们都需要相同的密钥。(例如 `[{key1: "value1"},{key2:"value1"}]` 会抛出错误,因为 key1!==key2 。遗憾的是,这与我正在寻找的行为完全相反。 (2认同)
  • @Aidin /sf/ask/5002373071/ different-keys (2认同)

mar*_*tin 3

很可能不会。我想到的最好的解决方案是用方法包装一个Object(或)自定义类,并且在某些情况下可以禁止向底层集合添加新项目。Mapset(key: string, val: any)get(key: string)