ima*_*gio 7 typescript typescript-generics
我有一个打字稿函数,它采用通用类型和该通用类型的键。我限制该键,以便该函数仅接受其值属于某种类型的键。当使用约束键访问通用对象时,我没有得到预期的类型作为回报。
如何将通用对象的键限制为特定值类型并在通用函数中访问该值?
例如:
function onlyTakesADateKey<T, K extends keyof T>(item: T, key: T[K] extends Date ? K : never): void {
//I've constrained `key` to ensure that item[key] is a Date but this doesn't get typed as a Date
const shouldBeADateButIsNot = item[key]
//Property 'getTime' does not exist on type 'T[T[K] extends Date ? K : never]'.ts(2339)
shouldBeADateButIsNot.getTime()
}
const foo = { key1: "asdf", key2: new Date() }
//Argument of type 'string' is not assignable to parameter of type 'never'.ts(2345)
const bar = onlyTakesADateKey(foo, "key1")
//It properly constrains the key, but per above can't access the date value in the function
const baz = onlyTakesADateKey(foo, "key2")
Run Code Online (Sandbox Code Playgroud)
为什么不是shouldBeADateButIsNot
一个Date
?键已受到适当约束。我无法将参数传递给函数,导致它不是日期。
编译器实际上无法对依赖于尚未指定的泛型类型参数(例如和 )的实现中的条件类型做太多事情。在函数实现内部,类型的计算被推迟。这就是您看到有关 的错误的原因。编译器无法进行必要的高阶推理来得出它必须可分配给 的结论。这是 TypeScript 的设计限制,如microsoft/TypeScript#30728中所示。T
K
onlyTakesADateKey
T[K] extends Date ? K : never
T[T[K] extends Date ? K : never]
Date
编译器通常会推迟对依赖于未指定泛型的类型的评估,但有一些地方可以做得更好。一是:如果您有一个类型的值Record<K, V>
并使用 对其进行索引K
,编译器将理解它的类型是V
。因此,通用查找并不总是完全延迟。这建议重写您的T
和K
约束,如下所示:
function onlyTakesADateKey<T extends Record<K, Date>, K extends PropertyKey>(
item: T, key: K): void {
const isActuallyADateNow = item[key]
isActuallyADateNow.getTime()
}
Run Code Online (Sandbox Code Playgroud)
这可以正常工作,并且您的示例的行为类似:
const foo = { key1: "asdf", key2: new Date() }
const baz = onlyTakesADateKey(foo, "key2"); // okay
Run Code Online (Sandbox Code Playgroud)
值得注意的例外是,当您犯错误时,编译器会抱怨item
而不是key
:
const bar = onlyTakesADateKey(foo, "key1"); // error!
// -------------------------> ~~~
// Types of property 'key1' are incompatible.
Run Code Online (Sandbox Code Playgroud)
如果您确实不想更改有关调用的任何内容,则始终可以使用类型断言来告诉编译器它无法弄清楚什么:那shouldBeADateButIsNot
就是Date
:
function onlyTakesADateKeyOrig<T, K extends keyof T>(
item: T, key: T[K] extends Date ? K : never): void {
const shouldBeADateButIsNot = item[key] as any as Date;
shouldBeADateButIsNot.getTime()
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
5353 次 |
最近记录: |