TypeScript中如何实现不含unknown的类型互斥?
TypeScript实现{value: T}与{error: Error}的互斥类型
问题根源
你之前的写法type MaybeExclusive<T> = { value: T } | { value?: never, error: Error }之所以会出现value类型不确定的情况,是因为value?: never仅将value标记为可选的never类型,但TypeScript未明确排除该属性在另一个分支中的存在,导致类型收窄不彻底。
解决方案1:明确互斥的联合分支
直接在每个联合分支中显式排除另一个属性,确保两个分支严格互斥:
type MaybeExclusive<T> = | { value: T; error?: never } | { value?: never; error: Error };
- 第一个分支:存在
value: T,同时将error标记为可选的never(无法赋值) - 第二个分支:存在
error: Error,同时将value标记为可选的never(无法赋值)
这种写法既能保证两个类型互斥,又能让TypeScript正确进行类型收窄:
// 合法实例 const success: MaybeExclusive<string> = { value: "操作成功" }; const failure: MaybeExclusive<string> = { error: new Error("操作失败") }; // 非法实例(TypeScript会报错) const invalid: MaybeExclusive<string> = { value: "冲突", error: new Error("同时存在两个属性") };
解决方案2:通用互斥类型工具
如果需要复用这种互斥逻辑,可以封装一个通用的Exclusive类型工具:
type Exclusive<T, U> = | (T & Record<keyof U, never>) | (U & Record<keyof T, never>); // 基于通用工具生成目标类型 type MaybeExclusive<T> = Exclusive<{ value: T }, { error: Error }>;
这个工具通过交叉Record<keyof U, never>,直接禁止另一个类型的所有属性存在,实现更严格的互斥约束。
类型收窄使用示例
在实际代码中,通过简单的存在性检查即可让TypeScript自动收窄类型:
function processResult<T>(result: MaybeExclusive<T>) { if ("error" in result) { // 此处result被收窄为{ error: Error; value?: never } console.error("错误信息:", result.error.message); return; } // 此处result被收窄为{ value: T; error?: never } console.log("返回值:", result.value); }
内容的提问来源于stack exchange,提问作者bohemak2
相关产品推荐
相关产品推荐

