Jef*_*kin 4 typescript conditional-types
下面的代码试图定义一个函数的类型,当它的泛型参数是 时不带参数调用undefined,但对于任何其他参数类型有 1 个参数。(很可能有更好的方法来实现这一点,我很想在评论中看到链接,但问题是为什么 Typescript 的工作方式与我预期的不同。)
当T extends undefined为 false 时,在 else 分支中T出现变成 into never,但只在一个函数参数列表中......
type OptionalArgBroken<Arg> = Arg extends undefined ?
() => void :
(arg: Arg) => void;
const suppressArgBroken:OptionalArgBroken<undefined> = function() { };
suppressArgBroken(); // Fine
const haveArgBroken:OptionalArgBroken<boolean> = function(b:boolean) { };
haveArgBroken(true); // Type error
Run Code Online (Sandbox Code Playgroud)
正如您在Playground上看到的,上面的最后一行给出了类型错误
“true”类型的参数不能分配给“never”类型的参数。(2345)
阅读https://github.com/microsoft/TypeScript/issues/31751 后,我尝试在s 中包装Arg和,这似乎解决了问题:undefined[]
type OptionalArgWorks<Arg> = [Arg] extends [undefined] ?
() => void :
(arg: Arg) => void;
const suppressArgWorks:OptionalArgWorks<undefined> = function() { };
suppressArgWorks(); // Fine
const haveArgWorks:OptionalArgWorks<boolean> = function(b:boolean) { };
haveArgWorks(true); // Fine
Run Code Online (Sandbox Code Playgroud)
即使该修复有效,这也不是同一个问题:
type MakesSenseT = undefined extends undefined ? 'yes' : 'no'
const MakesSense:MakesSenseT = 'yes';
type ExtendsUndefined<T> = T extends undefined ? 'yes' : 'no'
const MakesSenseToo : ExtendsUndefined<undefined> = 'yes';
const MakesSenseThree : ExtendsUndefined<boolean> = 'no';
Run Code Online (Sandbox Code Playgroud)
为什么我的原始代码不起作用?
jca*_*alz 11
正如所写,
type OptionalArgBroken<Arg> = Arg extends undefined ?
() => void :
(arg: Arg) => void;
Run Code Online (Sandbox Code Playgroud)
是分布式条件类型,因为被检查的类型Arg是一个裸泛型类型参数。
“分布式”意味着如果Arg传入的是union,那么将分别为 union 的每个成员评估类型,然后重新组合在一起(因此操作分布在 union 中)。换句话说,OptionalArgBroken<A | B | C>将与 相同OptionalArgBroken<A> | OptionalArgBroken<B> | OptionalArgBroken<C>。
这可能不是您的意图,事实证明,您在办理登机手续时对结果感到满意[](这使得已选中的类型不再因“衣服”而“裸露”)。
此外,TypeScript 编译器将boolean类型视为trueand 并集的简写,即false所谓的布尔文字类型:
type Bool = true | false;
// type Bool = boolean
Run Code Online (Sandbox Code Playgroud)
如果您Bool使用 IntelliSense 将鼠标悬停在 IDE 中,您将看到Bool上面显示为boolean.
如果您将其boolean视为单一类型而不是其他两种类型的并集,这可能会令人惊讶。出现的一个地方是当您传递boolean给分配条件类型时:OptionalArgBroken<boolean>is OptionalArgBroken<true | false>which is OptionalArgBroken<true> | OptionalArgBroken<false>which is
type OABBool = OptionalArgBroken<boolean>;
// type OABBool = ((arg: false) => void) | ((arg: true) => void)
Run Code Online (Sandbox Code Playgroud)
你传入了你认为是单一类型的东西,并得到了一个函数类型的联合。哎呀。(参见microsoft/TypeScript#37279)
并且只能使用它们的参数的交集来安全地调用函数类型的联合。阅读关于支持调用函数联合的TS3.3 发行说明,了解为什么会这样。
但这意味着 type 的值OptionalArgBroken<boolean>只能用 type 的参数调用true & false,它被简化为never(参见microsoft/TypeScript#31838),因为没有值既是true又是false。
并且因此,当您尝试调用haveArgBroken,它希望传递的参数为类型never:
const haveArgBroken: OptionalArgBroken<boolean> = function (b: boolean) { };
// haveArgBroken(arg: never): void
Run Code Online (Sandbox Code Playgroud)
并且true不是 type never,所以它失败了:
haveArgBroken(true); // Type error
Run Code Online (Sandbox Code Playgroud)
这就是为什么您的原始代码不起作用的原因。
请注意,同样的事情发生在
type ExtendsUndefined<T> = T extends undefined ? 'yes' : 'no'
Run Code Online (Sandbox Code Playgroud)
但它是良性的,因为ExtendsUndefined<boolean>变成ExtendsUndefined<true> | ExtendsUndefined<false>which is 'no' | 'no'which 减少到 just 'no'。这正好是你想要的,但仅仅是因为没有办法区分'no',从来到true与来自的一个false。
好的,希望有帮助;祝你好运!
| 归档时间: |
|
| 查看次数: |
2110 次 |
| 最近记录: |