TypeScript使用Omit工具类型后force属性丢失的问题
TypeScript中Omit交叉联合类型后属性不被识别的问题
先看定义的类型:
type A = { role: 'admin', force?: boolean } type B = { role: 'regular' } type Req = { data: number } & (A | B);
当用Omit移除Req的data属性后:
type NoData = Omit<Req, 'data'>; const noData: NoData = { role: 'admin', force: true }
会触发报错:
Type '{ role: "admin"; force: boolean; }' is not assignable to type 'NoData'. Object literal may only specify known properties, and 'force' does not exist in type 'NoData'.(2322)
问题原因
Req是{data: number}与A | B的交叉类型,本质等价于({data: number} & A) | ({data: number} & B)。但Omit<T, K>默认不会对联合类型的每个成员单独处理,而是取联合类型所有成员的共同属性进行操作。因为B类型没有force属性,所以Omit<Req, 'data'>最终会被解析为{role: 'admin' | 'regular'},自然不包含可选的force属性,导致赋值时报错。
解决方案
要让Omit对联合类型的每个成员单独生效,有两种实用方式:
方式一:直接对联合类型的每个成员应用Omit
type NoData = Omit<A, 'data'> | Omit<B, 'data'>;
因为A和B本身没有data属性,Omit<A, 'data'>就是A,Omit<B, 'data'>就是B,所以NoData等价于A | B,此时赋值{role: 'admin', force: true}完全符合类型要求。
方式二:使用分发式条件类型实现通用可分发Omit
如果需要更通用的方案(比如后续A或B可能添加data属性),可以定义一个能自动分发到联合类型每个成员的DistributiveOmit:
type DistributiveOmit<T, K extends keyof any> = T extends any ? Omit<T, K> : never; type NoData = DistributiveOmit<Req, 'data'>;
这个类型利用TypeScript的条件类型分发特性,当T是联合类型时,会自动对每个成员单独执行Omit操作,最终结果等价于Omit<{data: number} & A, 'data'> | Omit<{data: number} & B, 'data'>,也就是A | B,同样能解决报错问题。
验证代码
修改后的代码可以正常运行:
type A = { role: 'admin', force?: boolean } type B = { role: 'regular' } type Req = { data: number } & (A | B); // 方式一实现 type NoData1 = Omit<A, 'data'> | Omit<B, 'data'>; const noData1: NoData1 = { role: 'admin', force: true }; // 无报错 // 方式二实现 type DistributiveOmit<T, K extends keyof any> = T extends any ? Omit<T, K> : never; type NoData2 = DistributiveOmit<Req, 'data'>; const noData2: NoData2 = { role: 'admin', force: true }; // 无报错
内容的提问来源于stack exchange,提问作者Raz Luvaton
相关产品推荐
相关产品推荐

