我正在尝试创建一个泛型函数,它只适用于扩展string[]
的对象类型中的属性。例如,对象类型可能是:
type Thing = {
a: Thing2[],
b: Thing3[],
c: number,
}
const thing2 = ['!', '@', '#'] as const;
type Thing2 = typeof thing2[number];
const thing3 = ['1', '2', '3'] as const;
type Thing3 = typeof thing3[number];
字符串
并且该函数将仅接受密钥a
和b
。
删除了所有不相关的代码,到目前为止,我已经:
type KeysMatching<T, V> = {[K in keyof T]-?: T[K] extends V ? K : never}[keyof T];
function append<O extends object, K extends KeysMatching<O, string[]>>(
obj: O,
key: K,
item: O[K] extends (infer U)[] ? U : never
) {
obj[key].push(item); // Property 'push' does not exist on type 'O[K]'
}
型
但是TypeScript似乎无法识别obj[key]
的类型是string[]
。如果可能的话,我也想避免使用as
关键字。
1条答案
按热度按时间k4emjkb11#
目前TypeScript中没有原生的
KeysMatching<T, V>
类型运算符,编译器实际上理解T[KeysMatching<T, V>]
可分配给V
,用于genericT
和V
。您可以实现您自己的版本,如问题代码所示,但正如您所看到的,它在泛型函数实现中并不像所期望的那样工作。在microsoft/TypeScript#48992上有一个开放的特性请求来支持这类东西,但现在它还不是语言的一部分。除非这种情况改变,否则我们需要解决它。一种解决方法是更改通用约束的方向,使对象类型
O extends Record<K, string[]>
(使用Record<K, V>
实用程序类型)代替现有约束(其中K extends KeysMatching<O, string[]>
),或者在现有约束之外添加O extends Record<K, string[]>
。它们从不同的Angular 代表相同或相似的事物。以下是如果你同时做这两件事的情况:字符串
现在编译器知道
obj[key]
可以赋值给string[]
,因此接受item
。我们也可以将item
的类型更简单地写成O[K][number]
,而不是conditional type;现在编译器知道O[K]
是数组类型,我们可以直接用number
来得到元素类型。让我们确保它仍然像预期的那样从调用者的Angular 工作:
型
看起来不错
Playground代码链接