根据下面的代码,是否可以告诉TypeScript检查"origin"泛型联合类型的类型,即使泛型是"lost"?
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);
type Nothing = { [nothingSymbol]: null };
const nothing = ({ [nothingSymbol]: null });
const isNothing = <T>(x: Maybe<T>): x is Nothing => (nothingSymbol in x);
/* ... */
type Maybe<T> = Just<T> | Nothing;
const n: Maybe<number> = nothing;
const s: Maybe<string> = nothing;
function forceTsTypeError(x: Maybe<number>): void {}
forceTsTypeError(n); // Correct
forceTsTypeError(s); // Incorrect, but it doesn't matter for TS
编辑:添加代码将其转换为最小的可重现示例
我在这里找到了一个解决方案。
不同的是,nothing
现在也是一个函数。所以我要明确地写const s = nothing() as Maybe<string>;
这样做的一个优点是__brand
只是类型信息,不包含在输出代码中。
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);
type Nothing<T> = ({ [nothingSymbol]: null } & { __brand: T });
const nothing =<T>() => ({ [nothingSymbol]: null }) as Maybe<T>;
const isNothing = <T>(x: Maybe<T>): x is Nothing<T> => (nothingSymbol in x);
/* ... */
type Maybe<T> = Just<T> | Nothing<T>;
const n = nothing() as Maybe<number>;
const s = nothing() as Maybe<string>;
function forceTsTypeError(x: Maybe<number>): void {}
forceTsTypeError(n); // Correct
forceTsTypeError(s); // Incorrect
----------------^^^
错误:
Argument of type 'Maybe<string>' is not assignable to parameter of type 'Maybe<number>'.
Type 'Just<string>' is not assignable to type 'Maybe<number>'.
Type 'Just<string>' is not assignable to type 'Just<number>'.
Type 'string' is not assignable to type 'number'.