为什么当类型从“Tuple |”缩小时类型缩小不起作用字符串`到`元组`?

问题描述 投票:0回答:1

有时为了简化具有复杂输入的函数签名,我们定义一组“已知”复杂输入,每个输入与一个令牌相关联,并允许用户提供令牌。

我的函数适用于元组(这里简化为三元素元组),并且最初它没有任何编译器错误:

const TUPLE_LENGTH = 3

type Tuple = readonly [unknown, unknown, unknown]

function fn(tuple: Tuple): void {
    if (tuple.length !== TUPLE_LENGTH) {
        throw new Error(`Expected ${TUPLE_LENGTH} items, instead got ${tuple.length}`)
    }
}

尝试一下

…但是添加“已知”输入后,开始出现编译器错误:

const TUPLE_LENGTH = 3

type Tuple = readonly [unknown, unknown, unknown]

const knownTuples = {
    foo: [1, 2, 3],
    bar: ['a', 'b', 'c'],
    baz: [true, false, null],
} satisfies Readonly<Record<string, Tuple>>

type TupleName = keyof typeof knownTuples

function fn(tuple: Tuple | TupleName): void {
    if (typeof tuple === 'string') {
        tuple = knownTuples[tuple]
    }

    if (tuple.length !== TUPLE_LENGTH) {
        throw new Error(`Expected ${TUPLE_LENGTH} items, instead got ${tuple.length}`)
        //                                                                   ^^^^^^
        // Error: Property 'length' does not exist on type 'never'
    }
}

尝试一下

出于某种原因,在第一种情况下,在

if (tuple.length !== TUPLE_LENGTH)
之后是
tuple: Tuple
,但在第二种情况下,它被缩小到
tuple: never
。这是为什么?

我怀疑,这与受歧视的工会有关,因为

Tuple
string
都有财产
length
,但我自己无法从中得出令人信服的答案。

typescript tuples discriminated-union
1个回答
0
投票

该代码已经是类型安全的,因为您无法发送长度不同于 3 的元组。因此,第二个类型防护实际上使

tuple
never
类型,因此错误是合法的。

您不需要此类型防护罩,只需将其移除即可。否则,您需要允许将数组而不是元组 [3] 传递给函数。

© www.soinside.com 2019 - 2024. All rights reserved.