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

为何TypeScript返回含不可能可选键的判别式联合?

问题原因

TypeScript推断返回多个对象的函数类型时,默认会统一所有返回值的结构:它会把所有返回对象的键都收集起来,给每个对象里不存在的键加上?: undefined标记,确保联合类型的每个成员都能兼容一个包含所有键的基础结构。这就是你看到额外可选键的原因。

你第二个例子能得到纯净联合类型,是因为两个返回值(对象和数组)结构完全不兼容,TypeScript没法统一它们的结构,所以直接保留了各自的原始类型。

不用显式定义返回类型的解决办法

办法1:用never标记不存在的键

在每个返回对象里,给另一个分支的键赋值为undefined as never——never类型和任何类型都不兼容,TypeScript就不会再尝试统一结构:

export const testFn = () => {
  if (Math.random() > 0.5) 
    return { valid: true, data: { your: 1 }, error: undefined as never } as const;

  return { valid: false, error: { my: "error" }, data: undefined as never } as const;
};

type T1 = ReturnType<typeof testFn>
// 最终类型:
// {
//     readonly valid: true;
//     readonly data: {
//         readonly your: 1;
//     };
//     readonly error: never;
// } | {
//     readonly valid: false;
//     readonly error: {
//         readonly my: "error";
//     };
//     readonly data: never;
// }

实际使用时完全不用担心never字段:用valid判别后,TypeScript会自动忽略不存在的字段,比如:

const res = testFn();
if (res.valid) {
  console.log(res.data.your); // 正常访问,不会提示error存在
} else {
  console.log(res.error.my); // 正常访问,不会提示data存在
}

办法2:人为制造结构差异

给其中一个返回对象加一个唯一的符号键,让TypeScript认为两个返回值结构不同,从而停止合并键:

const tempKey = Symbol();

export const testFn = () => {
  if (Math.random() > 0.5) 
    return { valid: true, data: { your: 1 }, [tempKey]: true } as const;

  return { valid: false, error: { my: "error" } } as const;
};

type T1 = ReturnType<typeof testFn>
// 最终类型:
// {
//     readonly valid: true;
//     readonly data: {
//         readonly your: 1;
//     };
//     readonly [tempKey]: true;
// } | {
//     readonly valid: false;
//     readonly error: {
//         readonly my: "error";
//     };
// }

这个办法会多一个无用的符号键,但符号键不会被意外访问,也不影响判别式联合的正常使用。

总结

不想显式定义返回类型的话,核心就是让TypeScript没法统一两个返回对象的结构——要么用never标记不该存在的键,要么人为制造结构差异,阻止它自动合并键。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 20:47:47