繁体   English   中英

Typescript 使用受该值类型约束的键访问泛型类型的值

[英]Typescript access value of generic type using key constrained by the type of that value

我有一个 typescript function ,它采用泛型类型和该泛型类型的键。 我限制该键,以便 function 将仅接受其值属于某种类型的键。 当使用约束键访问通用 object 时,我没有得到预期的类型作为回报。

如何将通用 object 的键约束为特定值类型并在通用 function 中访问该值?

例如:

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")

为什么shouldBeADateButIsNot不是Date 密钥被适当地约束。 我无法将 arguments 传递给 function 导致它不是日期。

onlyTakesADateKey的实现中,编译器无法真正处理依赖于尚未指定的泛型类型参数(如TK )的条件类型 在 function 实现中,评估类型T[K] extends Date? K: never T[K] extends Date? K: never推迟 这就是为什么您会看到有关T[T[K] extends Date? K: never] T[T[K] extends Date? K: never] 编译器无法进行必要的高阶推理来得出结论,它必须可以分配给Date 这是 TypeScript 的设计限制,如microsoft/TypeScript#30728 所示

编译器通常会推迟对依赖于未指定 generics 的类型的评估,但在一些地方它可以做得更好。 一种是:如果您有一个Record<K, V>类型的值并使用K对其进行索引,编译器将理解它是V类型。 所以通用查找并不总是完全延迟。 这建议像这样重写您的TK约束:

function onlyTakesADateKey<T extends Record<K, Date>, K extends PropertyKey>(
  item: T, key: K): void {
    const isActuallyADateNow = item[key]
    isActuallyADateNow.getTime()
}

这可以正常工作,并且您的示例行为类似:

const foo = { key1: "asdf", key2: new Date() }
const baz = onlyTakesADateKey(foo, "key2"); // okay

一个值得注意的例外是,当您犯错时,编译器会抱怨item而不是key

const bar = onlyTakesADateKey(foo, "key1"); // error!
// -------------------------> ~~~
// Types of property 'key1' are incompatible.

如果您真的不想更改有关调用的任何内容,则始终可以使用类型断言来告诉编译器它无法弄清楚的内容: shouldBeADateButIsNotDate

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()
}

Playground 代码链接

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM