You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在联合记录类型上使用Pick或Omit并保留类型校验?

问题:联合类型使用Pick/Omit后丢失类型校验的解决方案

问题描述

我有一个由不同记录类型组成的联合类型,这些记录类型拥有相同的键,但部分键的类型限制因记录类型而异。当对该类型使用Pick或Omit时,会丢失部分类型校验功能。

简化示例代码如下:

type A = {
  type: 'a',
  content: 'a-content'
};

type B = {
  type: 'b',
  content: 'b-content'
}

type Full = {id: number} & (A|B);

// 合法代码
const full: Full = {
  id: 1,
  type: 'a',
  content: 'a-content'
}

// 被正确标记为类型错误
const invalidFull: Full = {
  id: 1,
  type: 'a',
  content: 'b-content'
}

// 未被标记为类型错误,但content与type字段不匹配
const invalidFullPartial: Omit<Full, 'id'> = {
  type: 'a',
  content: 'b-content'
}

请问如何设置才能在Full类型上使用Pick或Omit时,仍让TypeScript确保type和content的类型匹配?

解决方案

问题根源在于TypeScript内置的Pick/Omit默认不具备分布式处理能力,当交叉类型与联合类型混合时,无法保留联合成员内部的字段关联约束。以下是两种可行的解决方式:

方法1:调整类型定义顺序

先对原始联合类型应用Omit/Pick操作,再交叉额外字段类型,让联合类型的约束优先保留:

// 先定义联合类型,再交叉id字段
type Full = (A|B) & {id: number};

// 此时Omit<Full, 'id'>等价于A|B,自动保留type与content的关联约束
const invalidFullPartial: Omit<Full, 'id'> = {
  type: 'a',
  content: 'b-content' // 现在会被正确标记为类型错误
}

方法2:自定义分布式Pick/Omit工具类型

如果无法调整原始类型定义,可以自定义支持联合类型的工具类型,利用条件类型的分布式特性对每个联合成员单独处理:

// 自定义支持联合类型的Omit
type DistributiveOmit<T, K extends keyof any> = T extends any ? Omit<T, K> : never;

// 自定义支持联合类型的Pick
type DistributivePick<T, K extends keyof T> = T extends any ? Pick<T, K> : never;

// 使用自定义工具类型替代内置方法
const invalidFullPartial: DistributiveOmit<Full, 'id'> = {
  type: 'a',
  content: 'b-content' // 正确触发类型错误
}

原理说明

TypeScript的条件类型在处理联合类型时,会自动对每个联合成员单独执行条件逻辑。自定义的DistributiveOmit/DistributivePick正是利用这一特性,确保每个联合成员内部的字段关联约束被完整保留,而不是被扁平化处理导致约束丢失。


内容的提问来源于stack exchange,提问作者Drew Pereli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 10:01:04