【问题标题】:TypeScript tuples conditional comparison always evaluates to falseTypeScript 元组条件比较总是计算为 false
【发布时间】:2019-08-23 04:56:18
【问题描述】:

这个很直接,这里是the link to playground

正如我所注意到的,当您从If<> 的条件中删除元组类型时,一切都按预期进行。但我不想这样做(t2 断言打击),而且我想了解为什么会发生这种情况。这只是一个错误吗?为什么And<> 类型总是扩展为true

type If<
    TCond extends boolean,
    TIfTrue,
    TElse
> = [TCond] extends [true] ? TIfTrue : TElse; // if you remove tuples, it works 

type Not<T extends boolean> = If<(T), false, true>;

type IsNever<TSuspect> = TSuspect extends never ? true : false;

type AssertFalse<TSuspect extends false> = TSuspect;
type AssertTrue <TSuspect extends true> = TSuspect;

//   V~~ always true 
type And<T extends boolean[]> = Not<Not<IsNever<Extract<T[number], false>>>>;

type AndExpected<T extends boolean[]> = IsNever<Extract<T[number], false>>;


type t0 = AssertFalse<Not<true>>;  
type t1 = AssertTrue<Not<false>>;  
type t2 = AssertTrue<Not<boolean>>;

type t3 = AssertFalse<And<[false]>>; // ????
type t4 = AssertFalse<AndExpected<[false]>>;

【问题讨论】:

  • 不是Extract&lt;T[number], false&gt; - never?所以不是Not&lt;Not&lt;IsNever&lt;Extract&lt;T[number], false&gt;&gt;&gt;&gt; - true
  • @zerkms 并非总是如此,这就是我使用IsNever&lt;&gt;检查它的原因
  • @zerkms Here you are
  • @Veetaha 这可能是一个错误,一个小得多的复制品:typescriptlang.org/play/…
  • 我觉得我也遇到过这样的错误,通常只是通过将中间结果放入默认类型参数来解决它们(例如,And&lt;T, N=Not&lt;T&gt;&gt; = Not&lt;N&gt;

标签: typescript generics typescript-generics conditional-types


【解决方案1】:

首先,我将尝试解释为什么 If with tuples 与 If without tuples 不同:

type If<
    TCond extends boolean,
    TIfTrue,
    TElse
> = [TCond] extends [true] ? TIfTrue : TElse; // if you remove tuples, it works 

type If2<
    TCond extends boolean,
    TIfTrue,
    TElse
> = TCond extends true ? TIfTrue : TElse;  


type Not<T extends boolean> = If<(T), false, true>;
type Not2<T extends boolean> = If2<(T), false, true>;

// with tuples, Not<boolean> is true because that's how you set it up
type A1 = Not<boolean>; // true
type A2 = Not<true>;    // false
type A3 = Not<false>;   // true

// without typles, TCond extends true is distributive over union types,
// and boolean is really just a union of true | false,
// so Not2<boolean> is boolean 
type B1 = Not2<boolean>; // boolean 
type B2 = Not2<true>;    // false
type B3 = Not2<false>;   // true

好的,现在回答问题。这是我(和 Titian Cernicova-Dragomir)发现的奇怪的东西:

type SameAsT<T extends boolean> = Not<Not<T>>;
type X1 = SameAsT<false>; // true !
type X2 = SameAsT<true>; // true again

// but why?

如果展开所有文字类型,它会按预期工作:

type ReallyNotFalse = [false] extends [true] ? false : true; // true
type ReallyNotNotFalse = [([false] extends [true] ? false : true)] extends [true] ? false : true; // false

看起来像是编译器中的一个错误。

顺便说一句,Not 基于 If 没有元组按预期工作

type SameAsT2<T extends boolean> = Not2<Not2<T>>;
type Y1 = SameAsT2<false>; // false
type Y2 = SameAsT2<true>; // true 

因此,可以使用其他方式来抑制条件中的分布式联合类型并使相关代码正常工作。一种方法是添加多余的条件,该条件总是评估为真,并且没有 TCond 作为被检查的类型:

type If<
    TCond extends boolean,
    TIfTrue,
    TElse
> = {} extends TCond ? TCond extends true ? TIfTrue : TElse : never; 

type Not<T extends boolean> = If<(T), false, true>;

type IsNever<TSuspect> = TSuspect extends never ? true : false;

type AssertFalse<TSuspect extends false> = TSuspect;
type AssertTrue <TSuspect extends true> = TSuspect;

//   V~~ always true 
type And<T extends boolean[]> = Not<Not<IsNever<Extract<T[number], false>>>>;

type AndExpected<T extends boolean[]> = IsNever<Extract<T[number], false>>;


type t0 = AssertFalse<Not<true>>;  
type t1 = AssertTrue<Not<false>>;  
type t2 = AssertTrue<Not<boolean>>;

type t3 = AssertFalse<And<[false]>>; 
type t4 = AssertFalse<AndExpected<[false]>>;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-30
    • 1970-01-01
    • 2013-01-25
    • 1970-01-01
    相关资源
    最近更新 更多