我只想要一个这样的类型:
type ObjectWithAnyKey = { [key: string]: string };
允许除
foo
之外的所有键 key 。怎么做?
最佳答案
我认为在这种情况下,您可以使用以下定义:
type ObjectWithAnyKeyExceptFoo = {
[key: string]: string
} & { foo?: never };
型号
{foo?: never}
有一个名为 foo
的可选属性,其类型为 never
(实际上与可选属性的 undefined
相同)。因此,如果您有一个名为 foo
的属性,它不能有一个定义的值。实际上从 undefined & string
是 never
,你不能有 foo
属性(property)。让我们确保它有效: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'.
看起来挺好的。
更多技术内容如下:
请注意,使用 intersection (
&
) 这里有点奇怪,甚至可能有点作弊。与 index signature , 手动指定属性,如 foo
还需要具有可分配给其索引签名属性类型的值。以下不起作用,因为它违反了:type BadDefn = {
[key: string]: string;
foo?: never; // error!
//~~~ <-- undefined is not assignable to string
}
自
foo
可能是 undefined
,但是 string
不是,编译器不高兴。没关系,来自索引签名的大多数值实际上是 undefined
而不是 string
(例如, const obj: ObjectWithAnyKeyExceptFoo = {a: "123"}
有一个 a
类型的属性 string
,但是如果你访问它的 b
属性呢?你会在运行时得到 undefined
,但编译器会说 string
)。 But that's the way index signatures are , 我猜。交集定义与上面不允许的类型本质上是一样的,只是它避开了编译器错误。故意这样做会违反索引签名(请参阅 this question )通常会出现问题,但我们实际上并不想使用该违反属性。我们不要
foo
属性,因为编译器看到 foo
属性为 string & undefined
, 即 never
,它实际上更适合这个用例。可以制作像这样的非违规单一类型:
type OkayDefnButPossiblyUndefined = {
[key: string]: string | undefined;
foo?: never;
}
如果你想代表那个
obj.b
,这个其实是合理的。是 undefined
而不是 string
,但如果您喜欢当前的索引签名行为,则可能不是最合适的。还有这个:type AlsoOkayButRequiresFoo = {
[key: string]: string;
foo: never;
}
更糟的是,因为
foo
成为必需的属性,实际上很难初始化这种类型的东西。结束技术性的东西
好的,希望有帮助。祝你好运!
Link to code
关于TypeScript:具有除一个以外的任何键的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58594051/