你当然可以在 TypeScript 中定义这样的类型:
type KeysMatching<T extends object, V> = {
[K in keyof T]-?: T[K] extends V ? K : never
}[keyof T];
type MyType = KeysMatching<MyInterface, number>;
// type MyType = "a" | "c"
在此,KeysMatching<T, V> 返回T 的键集,其属性可分配给V。它使用conditional 和mapped 类型以及属性lookup。对于keyof T 中的每个键K,它检查T[K] 是否可分配给V。如果是,则返回密钥K;如果不是,则返回never。因此,对于您的类型,它类似于{a: "a", b: never, c: "c"}。然后我们查找属性值并得到一个类型的联合,如"a" | never | "c",它减少为"a" | "c",完全符合您的要求。
请注意KeysMatching<T, V> 仅在读取 属性时返回值与V 匹配的那些属性键。那些恰好是V 或V 的子类型:
interface AnotherInterface {
narrower: 1;
exact: number;
wider: string | number;
}
type AnotherType = KeysMatching<AnotherInterface, number>;
// type AnotherType = "narrower" | "exact"
如果您想在编写 T... 的属性时获得与V 匹配的键...也就是说,恰好是V 或超类型 V,那么你需要 KeysMatching 的不同实现:
type KeysMatchingWrite<T extends object, V> = {
[K in keyof T]-?: [V] extends [T[K]] ? K : never
}[keyof T];
type AnotherTypeWrite = KeysMatchingWrite<AnotherInterface, number>;
// type AnotherTypeWrite = "exact" | "wider"
无论如何,希望对您有所帮助。祝你好运!
Link to code