gpt4 book ai didi

TypeScript 无法在函数类型中派生类型约束

转载 作者:行者123 更新时间:2023-12-05 03:22:18 25 4
gpt4 key购买 nike

假设我有一个约束类型函数 type Foo<T extends string>只接受扩展 string 的类型.我希望编译以下代码。相反,它会给出类型错误。

type Foo<T extends string> = T;

type UseFoo1<T> = NonNullable<T> extends string
? (param: Foo<NonNullable<T>>) => void
^^^^^^^^^^^^^^
: () => void;
Type 'NonNullable<T>' does not satisfy the constraint 'string'.
Type 'T' is not assignable to type 'string'.

为什么 TypeScript 不能导出 NonNullable<T>延伸string


在以下情况下,它确实有效。

type UseFoo2<T> = T extends string
? (param: Foo<T>) => void
: () => void;

type UseFoo3<T> = NonNullable<T> extends string
? Foo<NonNullable<T>>
: never;

最佳答案

一般中,通过跟踪 conditional type 逻辑上隐含的每个类型事实所获得的有用性之间存在权衡。检查并通过跳过它们获得的有用性。跟踪它们可以为您提供更多信息,而跳过它们可以为您提供更好的编译器性能。跟踪也很难正确进行。当你有 WWW extends XXX ? YYY : ZZZ , 传播新的 XXX 并不总是正确的对 WWW 的约束表达式一直向下到 YYY类型表达式,面对variance ;如果WWW出现在 YYY 中的协变位置那么就可以传播约束,但是如果它出现在逆变 位置,那么这样做并不总是可取的。所以我想说,无论 TS 团队如何决定实现这种约束传播,都会有未满足的用例。

特别是,您似乎看到了 microsoft/TypeScript#43427 错误修复的副作用,其中以下代码出现错误:

type Q<T> = number extends T ? (n: number) => void : never;
function fn<T>(arg: Q<T>) {
arg(10); // error in TS 4.2-, okay in TS 4.3+
}

编译器正在缩小 numberintersection number & T ,然后提示 10显然不能分配给 number & T .因为number出现在 (n: number) => void 中的逆变位置,number缩小使函数类型更宽并且用处不大。

修复已在 microsoft/TypeScript#43439 中实现不要将约束传播到逆变位置,在 microsoft/TypeScript#43599 中进行了另一个修复如果检查的类型是类型参数(如 T 而不同于 numberNonNullable<T> ),则专门重新启用此传播。这修复了 TypeScript 4.3 及更高版本中的上述错误,但引入了您遇到的错误。


这就是它发生的原因。由于类型参数不受此约束,您可以使用 conditional type inference 解决它。将您的类型复制到新的类型参数中,在 TS4.7 及更高版本中,您甚至可以 re-constrain the checked type这样重构实际上不会对您的代码进行太多更改:

type UseFoo2<T> = NonNullable<T> extends infer NNT extends string ?
(param: Foo<NNT>) => void : () => void; // okay

此副本 NonNullable<T>进入NNT类型参数,但我们只在 NNT 时才进入真正的分支被限制为 string .你可以使用 NNT在任何需要类型限制为 string 的位置.

Playground link to code

关于TypeScript 无法在函数类型中派生类型约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72754856/

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