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

TypeScript中keyof赋值及自定义MyOmit导致可选属性变必填原因咨询

TypeScript中keyof遍历后可选属性变必填的问题解答

错误产生原因

  • keyof操作符返回的仅为属性名的纯联合类型,不会携带原属性的可选/必填、readonly修饰符信息:keyof Props得到的就是"a" | "b" | "c" | "d",没有任何标记标识a/b/c为可选属性。
  • TypeScript的映射类型仅在[P in keyof T]这种直接遍历源类型key的场景下,会自动读取并保留原属性的修饰符;如果in后面跟随的是提前定义的类型别名、或是Exclude/Extract等类型运算返回的联合类型,TS无法关联到源类型的属性修饰符,默认会将所有映射出的属性设为必填,就会出现可选属性异常变为必填的问题。
  • 内置Omit没有该问题的原因是TS官方对其做了修饰符保留的兼容处理,底层通过键重映射直接遍历源类型的key,完整保留了原属性的修饰符属性。

解决方案

场景1:提前将keyof结果赋值给类型别名后做映射

不要直接遍历类型别名生成映射类型,改用内置Pick工具类型实现,它会自动保留原属性的修饰符:

type Keys = keyof Props;
// Pick会自动继承Props的属性修饰符
type Test1 = Pick<Props, Keys>

const a1: Test1 = {
  d: '1'
} // 运行正常无报错

场景2:自定义MyOmit工具类型

有两种兼容写法可选,都可以保留原属性的修饰符:

  1. 键重映射写法(适用于TS4.1及以上版本)
type MyOmit<T, K extends keyof any> = {
  [P in keyof T as Exclude<P, K>]: T[P]
}
  1. 组合Pick和Exclude写法(全版本兼容)
type MyOmit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>

修改后使用自定义MyOmit就不会再报可选属性缺失的错误:

const o1: MyOmit<Props, 'b' | 'c'> = {
  d: '1'
} // 运行正常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 19:48:03