gpt4 book ai didi

typescript - 函数中无法识别 props 中的类型限制

转载 作者:行者123 更新时间:2023-12-05 04:19:33 24 4
gpt4 key购买 nike

为什么以下对象提取被编译器标记为不正确? playground link

type SplitTextProps<T, N extends keyof T> = T[N] extends string
? {
object: T
getter: N
}
: never

const splitText = <T, N extends keyof T>({
object,
getter
}: SplitTextProps<T, N>) => {
const value = object[getter]
return value.split(' ')
}

interface Datatype {
value: string
id: number
}

const record: Datatype = { value: 'Green is good', id: 5 }
const result = splitText({ object: record, getter: 'value' })

console.log(result)

value.split(' ') 被标记为不正确,尽管 SplitTextProps 上有类型定义。确切的错误信息是

Property 'split' does not exist on type 'T[N]'


编辑(添加更多信息): 事实上,当尝试传递不正确 props 时,限制实际上起作用,编译器在尝试使用时抛出以下错误 splitText({object: record, getter : 'id'})

Argument of type '{ object: Datatype; getter: string }' is not assignable to parameter type 'never'.

☝️ 因为 interface Datatypeid 属性不是 string。只有快乐路径在 splitText func 😔 中失败。

最佳答案

这里的问题是 TypeScript 编译器通常无法遵循尚未指定的“高阶”逻辑运算 generic类型。在 splitText() 的正文内, 类型 SplitTextProps<T, N>conditional type这取决于泛型类型参数 TN .当编译器尝试评估 object 的类型时和 getter , 它采用将条件类型扩展到 union 的快捷方式它的 true 和 false 分支,所以它变成了 { object, getter } : { object: T, getter: N } .那么value类型为 T[N] , 哪个是正确的。但值得注意的是,关于 T[N] extends string 的任何信息不幸丢失了。所以value.split()是一个错误。

另一方面,splitText()调用者一般不会有这个问题。当您调用 splitText({ object: record, getter: 'value' }) ,编译器可以推断您指定的是 T作为DataTypeN作为"value" .因此输入的类型是 SplitTextProps<DataType, "value">可以直接评估为{ object: DataType, getter: "value" } ,然后输入检查。如果你用一些意想不到的输入来调用它,你可能会得到 SplitTextProps<SomeT, SomeN>评估为 never , 你会得到预期的错误。

简而言之: Unresolved 泛型条件类型很难处理,因此使用特定类型的调用者往往会很高兴,而使用泛型类型的实现者有时会不高兴。


如果你想让事情保持原样,并且你确定你已经正确地实现了事情,你可以 assert给编译器 valuestring :

const splitText = <T, N extends keyof T>(
{ object, getter }: SplitTextProps<T, N>
) => {
const value = object[getter] as string; // <-- assert
return value.split(' '); // okay
}

否则,您需要重构为编译器可以更正确地评估的形式。就个人而言,我会远离条件类型,除非它们是代表您的操作所必需的。对于给出的代码示例,我倾向于这样写:

type SplitTextProps<N extends PropertyKey> = {
object: Record<N, string>, getter: N
}

const splitText = <N extends PropertyKey>(
{ object, getter }: SplitTextProps<N>
) => {
const value = object[getter];
return value.split(' '); // okay
}

在这里,SplitTextProps只直接关心 literal typegetter N , 而你的 T已替换为 Record<N, string> , 使用 the Record<K, V> utility type .编译器能够理解 Record<K, V>[K]可分配给 V ,即使是通用的 K .那么value被视为可分配给 string 的类型, 您可以调用 split()在上面。

当然,您是否可以将条件类型重构为编译器可以理解的其他内容在很大程度上取决于用例,因此有时类型断言可能是您最简单、最直接的解决方案。

Playground link to code

关于typescript - 函数中无法识别 props 中的类型限制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74787616/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com