想象一下您有一个这样的类型:
type Person = {
email: string
name: string
passport: { series: string, number: string } // or just Passport type
}
现在您想在某个地方拥有一组禁用的键,如下所示:
const disabledKeys = {
email: true,
passport: {
series: true
}
}
所以我从该类型开始使用DisabledKeys:
type DisabledKeys = {
[key in keyof Person]?: boolean
}
但是我想描述passport
的正确形状,所以我做了以下工作:
type DisabledKeys = { [key in keyof Person]?: boolean } & {
passport: Record<keyof Passport, boolean>
foo: number // <---- `foo` isn't a part of Person type
}
如何更好地实现此扩展部分?我希望它是类型安全的,并且仅包含Person
类型的键。但目前它可能包含任何键。例如,如果我亲自将passport
重命名为其他名称,我将不会收到编译时错误。
答案 0 :(得分:2)
我认为您可能在这里寻找的是mapped类型的conditional属性类型:
type NestedDisabledKeys<T> = { [K in keyof T]?:
T[K] extends object ? NestedDisabledKeys<T[K]> : true;
}
type DisabledKeys = NestedDisabledKeys<Person>
类型NestedDisabledKeys
递归地遍历所有对象类型的属性。对于非对象属性,它允许缺少属性(因此所有道具都是可选的)或值true
(我假设您从未打算将false
放在其中,但是如果这样做,您可以像在代码中那样将true
更改为boolean
。这样会自动构建您要查找的结构,而不必担心手工正确或不正确地构造。
让我们看看它的作用:
const disabledKeys: DisabledKeys = {
email: true,
passport: {
series: true
}
}
const badDisabledKeys: DisabledKeys = {
email: true,
passpork: { // error! did you mean "passport"?
series: true
}
}
const badDisabledKeys2: DisabledKeys = {
email: true,
passport: {
series: true
},
foo: true; // error! "foo" is not expected in obj literal
}
const badDisabledKeys3: DisabledKeys = {
email: true,
passport: {
series: true,
nomber: true, // error! did you mean "number"?
}
}
这对您有用吗?这里有一个皱纹,甚至可能缺少对象属性键,例如:
const okayDisabledKeys: DisabledKeys = {
email: true
}
我认为这是可以接受的,并且意味着passport
包括所有子属性均未禁用,对吗?如果要要求指定每个对象类型的键,则答案将更加复杂。
无论如何,希望能有所帮助;祝你好运!