TypeScript 类似元组交集类型可变元素的传播不正确

8yoxcaq7  于 2022-10-29  发布在  TypeScript
关注(0)|答案(6)|浏览(126)

**类型脚本版本:**4.0.3
**检索词:**可变元组、可变元素、交集类型、类元组类型
代码

type T1 = [...unknown[] & []]; // never[]
type T2 = [...number[] & [1, 2, 3]]; // (3 | 1 | 2)[]

**预期行为:**对于T1,我预期它是[](空元组类型),对于T2,我预期它是[1, 2, 3]
实际行为:T1T2不知何故都变成了Array而不是Tuple.(T1被推导为never[]T2被推导为(3 | 1 | 2)[]

详细解释

因此,[unknown]是 * 所有类型级1元组的类型 *,并且直观地,unknown[]是 * 所有类型级n元组的类型
因此[] <: unknown[]为真(即,
所有空类型级元组 * 是 * 所有类型级n元组 * 的子类型),您可以使用以下代码简单地检查它:

type M = [] & unknown[] extends [] ? [] extends [] & unknown[] ? true : false : false; // true

然而,尽管[]unknown[]的子类型,因此[] & unknown[]实际上是[],但[] & unknown[]的变元不知何故传播为never[],这是不正确的和不直观的。

**Playground链接:**Playground

7ajki6be

7ajki6be1#

不正确和不直观
不直观,是的;没有我们能做得那么好,是的;但“不正确”多少有些争议。(顺便说一句,这个问题引发了一场关于never[]在概念上是否与[]相同的讨论,尽管它们在可赋值性上存在特定的差异。)无论如何,由于never[]不能赋值给[],因此这是一个很好的论据,可以证明T1是“不正确的,但是(3 | 1 | 2)[]显然是[1, 2, 3]的有效表示;只是不太好😄
出于好奇,既然有4👍个关于一个似乎有些神秘的问题,这是在实践中出现的地方?

hsvhsicv

hsvhsicv2#

自从TS 4.1终于添加了递归条件类型别名之后,我一直在构建类型级编程库。但是几个小时后,我遇到了这个问题,并在twitter上和其他人聊了几天。这👍似乎是我认识的人添加的,或者和我讨论过这个问题。

ibps3vxo

ibps3vxo3#

我同意T1的说法是正确的,很抱歉用错了词。但是,我想我们都同意(3| 2个|1)此时[]不是一个正确或有用的类型,因为一些重要信息被丢弃,它可能会导致一些意外的问题。🙂
(抱歉格式松散,我用移动的写了这篇评论...)

sqyvllje

sqyvllje4#

自从TS 4.1终于添加了递归条件类型别名之后,我一直在构建类型级编程库。但是几个小时后,我遇到了这个问题,并在twitter上和其他人聊了几天。这👍似乎是我认识的人添加的,或者和我讨论过这个问题。
我也有类似的情况。我试图Map嵌套的元组类型。

pqwbnv8z

pqwbnv8z5#

这也会变成数组型别,即使交集的两边都是以Tuple开始:

type X = [...[1, 2] & [1, 2 | 3]]
//   ^? type X = (2 | 1)[]
qyyhg6bp

qyyhg6bp6#

其实这也是坏的[...[1] & [unknown]]
当我试图从用其他属性扩充的元组中获取元组时,也遇到了类似的“问题”。
通过调查,我发现即使是[...([1,2,3] & unknown[])]也是有损耗的。
你会发现我在取回元组方面的不同尝试。显式地迭代数字键有效,但我很惊讶我不得不走这么远。

type A = [1,2,3] & { foo: unknown };

// -> (3 | 1 | 2)[]
type B = [...A]

// -> { [x: number]: 3 | 1 | 2 }
type C = { [K in keyof A as K extends number ? K : never]: A[K] }

// -> [2 | 1 | 3]
type D = CloneTuple<A>

type CloneTuple<T extends unknown[], R extends unknown[]=[]> =
    T extends [infer A, ...infer Rest]
    ? CloneTuple<Rest, [...R, A]>
    : R

// -> [1, 2, 3]
type E = ToTuple<A>

type ToTuple<
    T extends unknown[],
    L extends number=T['length'],
    C extends number = 0,
    R extends unknown[]=[]
> = C extends L ? R : ToTuple<
    T,
    L,
    [1,2,3,4,5,6,7,8,9,10][C],
    [...R, T[C]]
>

相关问题