You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何仅联合类型报错,单一类型无错误?

问题描述

为简化复杂输入的函数签名,我们会定义一组关联令牌的「已知」复杂输入,允许用户传入令牌替代。以下是处理三元组的函数:

初始版本无编译错误:

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类型,第二种却被收窄为never类型?

原因分析

第一种情况(仅接受Tuple类型)

Tuple是固定长度的只读三元组类型,TypeScript在编译时明确它的length类型是字面量3,但依然允许编写if (tuple.length !== TUPLE_LENGTH)的运行时检查——因为TypeScript无法阻止你通过类型断言、any等方式传入不符合Tuple类型的值(比如长度不为3的数组)。因此,TypeScript不会把if块内的tuple收窄为never,你依然可以访问tuple.length。

第二种情况(接受Tuple | TupleName类型)

  1. knownTuples中的每个值被TypeScript自动推断为更具体的字面量元组类型(比如foo对应readonly [1,2,3]),而非宽泛的Tuple类型。这些具体元组的length属性都是字面量3。
  2. 在if (typeof tuple === 'string')分支中赋值后,tuple的类型收窄为Tuple | 所有具体字面量元组的联合类型。
  3. 这个联合类型的所有成员,length属性都是字面量3,而TUPLE_LENGTH是值为3的常量,类型同样是字面量3。TypeScript判定tuple.length !== TUPLE_LENGTH这个条件永远不可能成立——没有任何符合联合类型的值会满足该条件。
  4. 因此,if块内部的tuple被收窄为never类型(不存在任何可能的取值),自然无法访问never类型的length属性,从而抛出编译错误。

内容的提问来源于stack exchange,提问作者Parzh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 06:05:58