如何在TypeScript条件类型中避免结构化子类型匹配错误
如何在TypeScript中避免结构化子类型导致的错误类型匹配?
我在编写TypeScript类型匹配逻辑时遇到了结构化子类型的问题。以下是我的代码:
type MatchOutput<T> = T extends EvalError ? EvalError : T extends Error ? Error : { DUMMY: true };
当调用MatchOutput<Error>时,输出被错误解析为EvalError,而我希望MatchOutput<Error>仅返回Error类型。预期的效果是:
declare const a: MatchOutput<EvalError>; // 期望: EvalError declare const b: MatchOutput<Error>; // 期望: Error declare const c: MatchOutput<string>; // 期望: { DUMMY: true }
问题原因
问题出在TypeScript的结构化子类型系统上——因为EvalError继承自Error且没有添加额外属性,两者的结构完全一致,导致Error extends EvalError被判定为true,从而错误触发了第一个条件分支。
解决方案
方法一:精确类型相等判断
通过自定义Equals类型工具来判断两个类型是否完全相等,以此区分EvalError和Error:
// 判断两个类型是否完全相等的工具类型 type Equals<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false; type MatchOutput<T> = Equals<T, EvalError> extends true ? EvalError : T extends Error ? Error : { DUMMY: true };
这个写法的逻辑:
- 当
T与EvalError类型完全相等时,返回EvalError - 否则,若
T是Error的子类型,返回Error - 其他情况返回
{ DUMMY: true }
方法二:兼容子类型的精确匹配
如果需要让EvalError的自定义子类型也返回EvalError,可以结合子类型判断和反向排除:
type MatchOutput<T> = // 匹配EvalError及其子类型,但排除Error本身 T extends EvalError ? (Equals<T, Error> extends true ? never : EvalError) : T extends Error ? Error : { DUMMY: true };
这个写法会让EvalError的所有子类型(除了Error本身)都返回EvalError,同时确保Error类型进入第二个分支。
验证效果
调整后的代码可以满足预期:
declare const a: MatchOutput<EvalError>; // 类型为 EvalError declare const b: MatchOutput<Error>; // 类型为 Error declare const c: MatchOutput<string>; // 类型为 { DUMMY: true }
内容的提问来源于stack exchange,提问作者user-id-14900042
相关产品推荐
相关产品推荐

