Typescript:如何声明一个值等于对象键的数组类型



如何在此代码中定义MyInterfaceKeys

interface MyInterface extends Record<string, any> {
Appearance?: "default" | "primary" | "link";
Size?: "small" | "medium" | "large";
Color?: string;
Block?: boolean;
}
type MyInterfaceKeys = (keyof MyInterface)[]
// ok => MyInterfaceKeys === ["Block", "Color"] 
// ok => MyInterfaceKeys === ["Appearance"]
// Error => MyInterfaceKeys === ["UnknownKey"]

事实上,我想将对象道具转换为联合文字:

type MyInterfaceKeys = ("Appearance" | "Size" | "Color" | "Block")[]

TypeScript中的对象类型有一组已知键,这些键对应于单个字符串或数字文本(或符号);和一组索引签名密钥,它们同时对应于多个可能的密钥(这些密钥过去只是stringnumber,但现在您也可以在索引签名中使用模式模板文字和符号)。例如,以下类型:

type Foo = {
[k: string]: 0 | 1
x: 0,
y: 1
}

具有两个已知密钥CCD_ 4和CCD_。您的MyInterface类型有四个已知密钥,但它也有一个string索引签名密钥(因为它扩展了具有string索引签名密钥的Record<string, any>)。


keyof运算符生成所有键的并集。对于Foo,也就是"x" | "y" | string,对于MyInterface,也就是说"Appearance" | "Size" | "Color" | "Block" | string

由于每个字符串文字(如"x""y")都是string的一个子类型,因此字符串文字类型与string的并集仅为string,编译器急切地将其简化为CCD_18。所以CCD_ 21和CCD_。在某种意义上,CCD_;吸收";所有字符串文字键。

因此,如果有任何索引签名密钥吸收了keyof,则不能使用CCD_25仅获取已知密钥


那么,你能做什么?你能做的最干净的事情就是考虑重构你的代码,这样你想要的信息就可以更容易地被捕获:

interface MyKnownInterface {
Appearance?: "default" | "primary" | "link";
Size?: "small" | "medium" | "large";
Color?: string;
Block?: boolean;
}
interface MyInterface extends Record<string, any>, MyKnownInterface { }
type KK = (keyof MyKnownInterface) & string
// type KK = "Appearance" | "Size" | "Color" | "Block"
type MyInterfaceKeys = (keyof MyKnownInterface)[]
// type MyInterfaceKeys = (keyof MyKnownInterface)[]
// type MyInterfaceKeys = ("Appearance" | "Size" | "Color" | "Block")[]

这里的MyInterface与以前相当,但keyof MyKnownInterface是您想要的已知密钥的并集。


您也可以使用类型操作来尝试梳理出已知的键,而不是仅使用keyof,尽管我认为我所知道的所有可能的方法都有一些奇怪的边缘情况(我即将提交一个与symbol键有关的错误)。但希望您不会遇到这种边缘情况(MyInterface示例没有)。

一种方法是在映射类型中使用密钥重映射来抑制索引签名,索引签名可以被识别为任何不需要值的密钥,即使它不是可选的(索引签名表示任何数量的正确类型的密钥,包括零个这样的密钥):

type KnownKeys<T> = keyof {
[K in keyof T as {} extends { [P in K]: any } ? never : K]: never
}

如果我们在你的情况下这样做,你会得到:

type MyInterfaceKeys = (KnownKeys<MyInterface>)[]
// type MyInterfaceKeys = ("Appearance" | "Size" | "Color" | "Block")[]

游乐场链接到代码

相关内容

最新更新