我希望创建一个函数,该函数接受来自接口Foo
的密钥作为输入,仅限于Foo
是可接受的赋值的string
的密钥
interface Foo {
a: string;
b?: string;
c?: string | boolean;
}
test("a");
test("b"); // Argument of type '"b"' is not assignable to parameter of type 'never'.ts(2345)
test("c"); // Argument of type '"c"' is not assignable to parameter of type 'never'.ts(2345)
function test<K extends keyof Foo>(key: Foo[K] extends string ? K : never) {}
以上(启用严格模式)在b
和c
上失败-有没有办法使用extends string
(或类似的方法)
不必完全匹配属性的类型 ?我对其他潜在类型不感兴趣,仅是类型可以是string
答案 0 :(得分:0)
因此,您显然要寻找的测试是string extends Foo[K]
而不是Foo[K] extends string
:
function test<K extends keyof Foo>(key: string extends Foo[K] ? K : never) {}
test("a"); // okay
test("b"); // okay
test("c"); // okay
如果您在考虑可分配性,T extends U
意味着可以将类型T
的值分配给类型U
的变量。如果将“ Foo
是可接受的分配的string
的属性”转换为“可以将string
类型的值分配给由键{索引的Foo
的属性{1}}”,您得到K
。在这种情况下,如果您拥有类型string extends Foo[K]
的变量foo
,类型Foo
的变量k
和类型{{1}的变量K
},您应该可以编写s
并进行编译。
如果您正在寻找string
的属性,可以将其分配给{em> 类型为foo[k] = s
的变量,则为Foo[K] extends string
,相反:您可以写Foo
。
这也正确拒绝了非string
属性:
s = foo[k]
它拒绝类型比string
更窄的类型:
interface Foo {
d: number;
}
test("d"); // error!
// Argument of type '"d"' is not assignable to parameter of type 'never'.
您无法为任何旧字符串string
写interface Foo {
e: "specificString";
}
test("e"); // error!
// Argument of type '"e"' is not assignable to parameter of type 'never'.
,因此这就是拒绝的原因。 (如果您需要接受它,那么您将要求表达一些更复杂的内容,而且也不清楚为什么有人需要它……因为您既无法读取也无法写入foo.e = s
值在这种情况下)
还请注意,s
似乎不需要通用...您可以使用通用类型别名,例如:
string
,它将采用类型test
和type KeysAssignableFrom<T, V> = {
[K in keyof T]-?: V extends T[K] ? K : never
}[keyof T];
并返回T
的键,其属性可从V
进行分配。然后T
变为:
V
等效于:
test()
好的,希望能有所帮助;祝你好运!