TypeScript:具有除一个以外的任何键的对象

B. *_*ard 15 typescript

我只想要一个这样的类型:

type ObjectWithAnyKey = { [key: string]: string };
Run Code Online (Sandbox Code Playgroud)

允许除钥匙外的所有钥匙foo

怎么做?

jca*_*alz 21

我认为在这种情况下,您可以使用以下定义:

type ObjectWithAnyKeyExceptFoo = {
  [key: string]: string
} & { foo?: never };
Run Code Online (Sandbox Code Playgroud)

该类型{foo?: never}有一个名为 的可选属性foo,其类型为never(实际上与undefined可选属性相同)。因此,如果您有一个名为 的属性foo,则它不能具有定义的值。实际上,因为undefined & stringis never,您根本不能拥有foo财产。让我们确保它有效:

function acceptAnyKeyAcceptFoo(obj: ObjectWithAnyKeyExceptFoo) { }

acceptAnyKeyAcceptFoo({}); // okay
acceptAnyKeyAcceptFoo({ a: "123" }); // okay
acceptAnyKeyAcceptFoo({ a: "123", foo: "oops" }); // error!
//  ----------------------------> ~~~
// Type 'string' is not assignable to type 'undefined'.
acceptAnyKeyAcceptFoo({ a: "123", foo: undefined }); // error!
//  ----------------> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Type 'undefined' is not assignable to type 'string'.
Run Code Online (Sandbox Code Playgroud)

看起来挺好的。


更多技术内容如下:

请注意,这里使用交集( &) 有点奇怪,甚至可能有点作弊。使用索引签名,手动指定的属性foo也需要具有可分配给其索引签名属性类型的值。以下不起作用,因为它违反了:

type BadDefn = {
  [key: string]: string;
  foo?: never; // error!
//~~~ <-- undefined is not assignable to string
}
Run Code Online (Sandbox Code Playgroud)

由于foo可能是undefined,但string不是,编译器不高兴。不要介意来自索引签名的大多数值实际上是undefined和不是string(例如,const obj: ObjectWithAnyKeyExceptFoo = {a: "123"}有一个atype的属性string,但是如果你访问它的b属性呢?你会undefined在运行时得到,但编译器说string)。 我猜这就是索引签名的方式

交集定义与上面不允许的类型本质上是一样的,只是它避开了编译器错误。故意这样做会违反索引签名(请参阅此问题)通常会出现问题,但我们实际上并不想使用该违反属性。我们根本不需要foo属性,而且由于编译器将foo属性视为string & undefined,即never,实际上更适合此用例。

可以制作像这样的非违规单一类型:

type OkayDefnButPossiblyUndefined = {
  [key: string]: string | undefined;
  foo?: never;
}
Run Code Online (Sandbox Code Playgroud)

如果您想表示obj.bisundefined和 not string,这实际上是合理的,但如果您喜欢当前的索引签名行为,则可能不是最合适的。还有这个:

type AlsoOkayButRequiresFoo = {
  [key: string]: string;
  foo: never;
}
Run Code Online (Sandbox Code Playgroud)

更糟糕的是,因为foo成为必需的属性并且很难实际初始化这种类型的东西。

结束技术性的东西


好的,希望有帮助。祝你好运!

代码链接

  • 是的,“any”会关闭类型检查。我假设您希望这些值是字符串。 (2认同)

Gib*_*olt 11

Omit在 TypeScript (3.5+) 中使用关键字

type ObjectWithAnyKey = {
  [key: string]: string
}

type ObjectWithAnyKeyButFoo = Omit<ObjectWithAnyKey, 'foo'> 
Run Code Online (Sandbox Code Playgroud)

对于排除多个属性:

type ObjectWithAnyKeyButFooOrBar = Omit<ObjectWithAnyKey, 'foo' | 'bar'>
Run Code Online (Sandbox Code Playgroud)

重新定义特定属性:

type ObjectWithAnyKeyAndUniqueFooBar = Omit<ObjectWithAnyKey, 'foo' | 'bar'> & {
  bar: number
  foo: Record<string, number>
}
Run Code Online (Sandbox Code Playgroud)

  • 这实际上是行不通的。请参阅 https://github.com/microsoft/TypeScript/issues/43139 (5认同)