如何让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
相关产品推荐
相关产品推荐

