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

如何让TypeScript检查泛型联合类型的原始类型(泛型丢失时)?

问题解答

你的核心问题是:当前Maybe<T>的Nothing分支不携带泛型信息,导致所有Maybe<T>中的Nothing都被视为同一类型,TypeScript无法区分Maybe<number>和Maybe<string>里的Nothing,因此forceTsTypeError(s)不会触发预期的类型错误。

要让TypeScript能检查这类泛型联合类型的“原始”类型,关键是让Nothing也绑定泛型参数(哪怕这个参数仅用于类型标记,不实际存储值),让不同泛型的Maybe分支成为不兼容的类型。

改造方案示例

const justSymbol: unique symbol = Symbol();
const nothingSymbol: unique symbol = Symbol();

type Just<T> = { [justSymbol]: T };
const just = <T>(x: T): Just<T> => ({ [justSymbol]: x });
const isJust = <T>(x: Maybe<T>): x is Just<T> => (justSymbol in x);

// 让Nothing绑定泛型参数T,用可选属性标记类型
type Nothing<T> = { [nothingSymbol]: null; _typeMarker?: T };
const nothing = <T = never>(): Nothing<T> => ({ [nothingSymbol]: null });
const isNothing = <T>(x: Maybe<T>): x is Nothing<T> => (nothingSymbol in x);

type Maybe<T> = Just<T> | Nothing<T>;

const n: Maybe<number> = nothing<number>();
const s: Maybe<string> = nothing<string>();

function forceTsTypeError(x: Maybe<number>): void {}

forceTsTypeError(n); // 正常通过
forceTsTypeError(s); // 现在触发类型错误,符合预期

原理说明

  • 给Nothing添加泛型参数T后,Nothing<number>和Nothing<string>会被TypeScript视为完全不同的类型,从而让Maybe<number>和Maybe<string>的联合类型不再兼容。
  • 可选属性_typeMarker仅用于类型标记,不会影响运行时逻辑;如果不想添加额外属性,也可以直接把泛型绑定到符号属性上:
    type Nothing<T> = { [nothingSymbol]: T };
    const nothing = <T = never>(): Nothing<T> => ({ [nothingSymbol]: null as unknown as T });
    
    这种方式同样能让不同泛型的Nothing分支产生类型差异,实现预期的类型检查。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 04:27:56