代码之家  ›  专栏  ›  技术社区  ›  Xunnamius

为什么TypeScript在有条件地推断数组末尾的可选元素时遇到困难?

  •  0
  • Xunnamius  · 技术社区  · 4 月前

    我曾考虑直接针对TypeScript仓库打开一个问题,但我希望答案是显而易见的。

    为什么以下条件类型会导致 'BAD' ?

    type X = [string[], string[], {
      a?: boolean;
      b?: boolean;
    }?] extends [...infer A, infer B] ? B : 'BAD';
    
    // A == 'BAD'
    // B == 'BAD'
    

    但是,如果我将最后一个元素设置为非可选元素,或者将可选元素移动到数组的中间或开头(这是不健全的(TS1257),但仍然满足本例的条件),它会按预期进行扩展和推断:

    type Y = [string[], string[], {
      a?: boolean;
      b?: boolean;
    }] extends [...infer A, infer B] ? B : 'BAD';
    
    // A == [string[], string[]]
    // B == { a?: boolean; b?: boolean; }
    
    // This triggers TS1257 (as mentioned above) but mousing over Z in the playground
    // still yields the correct inference:
    type Z = [string[], {
      a?: boolean;
      b?: boolean;
    }?, string[]] extends [...infer A, infer B] ? B : 'BAD';
    
    // A == [string[], { a?: boolean; b?: boolean; } | undefined]
    // B == string[]
    

    Playground link

    1 回复  |  直到 4 月前
        1
  •  1
  •   Alexander Nenashev    4 月前

    它虽然很黑客,但很有效,基本上你可以在可选元素之后用一个必需元素来模仿你的“无效”案例,TS不会抱怨。发生了什么:当最后一个元素是可选的时,TS无法推断出正确的元组长度,因为它是动态的。给定最后一个必需的元素,元组将获得一个静态长度:

    Playground

    type X = ExtractLast<[string[], string[], {
      // ^?
      a?: boolean;
      b?: boolean;
    }?]>
    
    type ExtractLast<T extends unknown[]> = [...T, unknown] extends [...unknown[], infer B, unknown] ? B : 'BAD';