如何让TypeScript类型所有键为必填,同时保留undefined可选值?
TypeScript中实现特定的类型映射需求
需求规则
需要将类型的键值对按以下规则映射:
required_key: string | undefined保持为required_key: string | undefined(不变)required_key: string保持为required_key: string(不变)optional_key?: string | undefined转为optional_key: string | undefined(移除键的?)optional_key?: string转为optional_key: string | undefined(移除键的?并添加undefined作为可选值)
示例问题
给定如下接口:
interface Person { firstName: string | undefined; middleName?: string; lastName?: string | undefined; }
期望转换后的类型为:
interface Person { firstName: string | undefined; middleName: string | undefined; lastName: string | undefined; }
但使用常规的-?操作符实现的Normalize类型无法满足需求:
type Normalize<T> = { [K in keyof T]-?: T[K] }; // 使用Normalize<Person>得到的结果: // interface Person { // firstName: string | undefined; // middleName: string; // lastName: string; // } const test: Normalize<Person> = { firstName: undefined, middleName: undefined, // TypeScript错误:类型为string,不允许undefined lastName: undefined, // TypeScript错误:类型为string,不允许undefined };
问题在于-?操作符会同时移除键的可选性和值类型中的undefined,需要找到方法为原可选键重新添加undefined值选项。
解决方案
可以通过自定义条件类型实现需求,核心思路是先识别出原类型中的可选键,再对这些键的类型手动添加undefined,同时移除所有键的可选性:
// 提取类型中的所有可选键 type OptionalKeys<T> = { [K in keyof T]: T extends { [P in K]-?: T[P] } ? never : K }[keyof T]; // 实现需求的Normalize类型 type Normalize<T> = { [K in keyof T]-?: K extends OptionalKeys<T> ? T[K] | undefined : T[K] };
测试上述类型:
interface Person { firstName: string | undefined; middleName?: string; lastName?: string | undefined; } type NormalizedPerson = Normalize<Person>; // 结果符合预期: // interface NormalizedPerson { // firstName: string | undefined; // middleName: string | undefined; // lastName: string | undefined; // } const test: NormalizedPerson = { firstName: undefined, middleName: undefined, // 无错误 lastName: undefined, // 无错误 };
原理说明
OptionalKeys<T>通过条件类型判断每个键是否为可选:如果将键K转为必填后,原类型T不再能赋值给这个新类型,说明K原本是可选键。Normalize<T>中,对每个键K先通过-?移除可选性,再判断K是否属于可选键:如果是,则将值类型设置为T[K] | undefined;否则保持原类型不变。
这样既移除了所有键的可选标记,又确保原可选键的类型包含undefined,完全符合需求。
内容的提问来源于stack exchange,提问作者user606521
相关产品推荐
相关产品推荐

