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

无法在联合复合类型中使用never的TypeScript问题求助

问题:联合类型构造函数赋值报错

我尝试用对象作为构造函数输入初始化类,该对象仅能填充两个字段中的一个,但在构造函数内解析时触发了错误。期望以下简化代码可以正常运行:

type Props = { name: string; age: never } | { name: never; age: number };

class Person {
  data: Props;

  constructor(data: Props) {
    if (data.name !== undefined) {
      this.data = data;
    } else {
      this.data = { // 此行触发错误
        ...data,
        age: data.age * 1.5, // 即使直接写"data.age"仍会触发错误
      };
    }
  }
}

遇到的错误:

Type '{ age: number; name: string; }' is not assignable to type '{ name: never; age: number; }'.
Types of property 'name' are incompatible.
Type 'string' is not assignable to type 'never'.

问题原因

TypeScript 对联合类型的收窄在这里没有正确生效:当判断 data.name !== undefined 进入 else 分支后,理论上应该推断出 data 是 { name: never; age: number } 类型,但展开 ...data 时,never 类型的 name 字段被错误保留,导致新对象的类型被推断为包含 name: string(来自联合类型的另一分支),从而与 Props 类型冲突。

解决方法

方法1:调整 Props 类型定义(推荐)

将 never 替换为可选的 never(即字段不存在),让 TypeScript 能更准确地进行类型收窄:

// 修改后的 Props 类型
type Props = { name: string; age?: never } | { name?: never; age: number };

class Person {
  data: Props;

  constructor(data: Props) {
    if (data.name !== undefined) {
      this.data = data;
    } else {
      // 此时 TypeScript 明确知道 data 只有 age 字段,无需处理 name
      this.data = {
        age: data.age * 1.5
      };
    }
  }
}

方法2:使用类型断言明确类型

在 else 分支中手动断言 data 的类型,避免类型推断错误:

type Props = { name: string; age: never } | { name: never; age: number };

class Person {
  data: Props;

  constructor(data: Props) {
    if (data.name !== undefined) {
      this.data = data;
    } else {
      // 断言为仅含 age 的分支类型
      const ageData = data as { name: never; age: number };
      this.data = {
        age: ageData.age * 1.5
      } as { name: never; age: number };
    }
  }
}

方法3:自定义类型守卫函数

通过类型守卫函数让 TypeScript 更清晰地识别联合类型分支:

type Props = { name: string; age: never } | { name: never; age: number };

// 自定义类型守卫,判断是否为含 age 的分支
function isAgeProps(data: Props): data is { name: never; age: number } {
  return typeof (data as { name: never; age: number }).age === 'number';
}

class Person {
  data: Props;

  constructor(data: Props) {
    if (data.name !== undefined) {
      this.data = data;
    } else if (isAgeProps(data)) {
      this.data = {
        age: data.age * 1.5
      };
    } else {
      throw new Error('无效的 Props 参数');
    }
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 21:42:38