我想创建一个TypeScript函数,该函数接受一个对象和该对象中的一个属性,其值是一个 string
. 使用 <T, K extends keyof T>
的键,以确保只有 T
允许作为属性的值,但我似乎无法缩小范围,使键也必须指向类型为 string
. 这可能吗?
我试了一下
function getKey<T extends {K: string}, K extends keyof T>(item: T, keyProperty: K): string {
return item[keyProperty];
}
但它只是说 Type 'T[K]' is not assignable to type 'string'
. 为什么不 T extends {K: string}
约束 T[K]
其实是 string
或者说,所提供的 K
必须满足这个条件,这样 T[K]
是一个 string
?
为了清楚起见,我希望能够像这样调用这个函数。
getKey({foo: 'VALUE', bar: 42}, 'foo') => return 'VALUE';
getKey({foo: 'VALUE', bar: 42}, 'bar') => should not be allowed since 'bar' is not a string property of the supplied object
getKey({foo: 'VALUE', bar: 'ANOTHER VALUE'}, 'bar') => return 'ANOTHER VALUE'
在。{K: string}
జజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజ K
名正言顺 字符串 键。 这就跟你写的是 {"K": string}
:
type Oops = { "K": string };
// type Oops = { K: string; }
既然你想 K
拟为 类型 的钥匙,你需要用 映射型,它在一些键的联合上迭代... 要么是 {[P in K]: string}
或同等条件 Record<K, string>
使用 Record<K, T>
实用型:
function getKey<T extends { [P in K]: string }, K extends keyof T>(
item: T,
keyProperty: K
): string {
return item[keyProperty]; // no error
}
而你的调用代码的表现(大部分)是你所期望的。
getKey({ foo: 'VALUE', bar: 42 }, 'foo'); // okay
getKey({ foo: 'VALUE', bar: 42 }, 'bar'); // error!
// ----------------> ~~~
// number is not assignable to string
getKey({ foo: 'VALUE', bar: 'ANOTHER VALUE' }, 'bar'); // okay
我说 "大部分 "是因为你可能希望第二行中的错误是发生在 "我 "身上。'bar'
传入 keyProperty
而实际发生的情况是,错误是发生在 bar
的值的属性。item
.
只要再多做一点手脚,你就能实现这个目标。
type KeysMatching<T, V> = { [K in keyof T]: T[K] extends V ? K : never }[keyof T];
function getKey2<T extends { [P in K]: string }, K extends KeysMatching<T, string>>(
item: T,
keyProperty: K
): string {
return item[keyProperty];
}
在这里,我们限制 K
不只是 keyof T
但对具体的键 T
其值为 string
. 我们用我们自己的 KeysMatching<T, V>
工具类型。 这不会改变什么值最终会是有效的,但它确实改变了编译器在无效时的抱怨。
getKey2({ foo: 'VALUE', bar: 42 }, 'foo');
getKey2({ foo: 'VALUE', bar: 42 }, 'bar'); // error!
// -----------------------------> ~~~~~
// "bar" is not "foo"
getKey2({ foo: 'VALUE', bar: 'ANOTHER VALUE' }, 'bar');
好的,希望能帮到你,祝你好运!
function getKey<T>(item: T, keyProperty: {[K in keyof T]: T[K] extends string ? K : never}[keyof T]): string {
return <string> <unknown> item[keyProperty];
}
有点笨重,但我......它的工作原理:)