如何构建TypeScript映射类型:仅保留含可空属性的子对象并将可空属性转为string类型
解决方案:构建符合需求的TypeScript映射类型
你的需求核心是三个关键点:
- 仅保留原始类型中的对象类型属性
- 仅保留子对象中可空属性,并将其类型转为
string - 排除那些没有任何可空属性的子对象
你的现有代码问题在于:用never标记非可空属性时,TypeScript会保留这些属性(只是类型为never),而不是移除它们;同时也没有过滤掉完全没有可空属性的子对象。下面是完整的可行方案:
分步实现工具类型
1. 提取子对象中的可空属性并转为string
首先创建一个工具类型,专门处理子对象:筛选出所有可以为null的属性,将其类型替换为string,同时直接移除非可空属性:
type NullablePropsToString<T extends object> = { [K in keyof T as null extends T[K] ? K : never]: string; };
这里用到了TypeScript的映射类型过滤(as子句):如果属性T[K]可以为null,就保留该属性键,否则排除它,最终属性类型统一设为string。
2. 判断子对象是否存在可空属性
接下来需要一个类型来判断某个对象是否包含至少一个可空属性,这样我们就能过滤掉那些完全没有可空属性的子对象:
type HasNullableProps<T extends object> = keyof NullablePropsToString<T> extends never ? false : true;
逻辑很简单:如果NullablePropsToString<T>的键集合是never(说明没有可空属性),则返回false,否则返回true。
3. 主映射类型:组合所有逻辑
最后把上面两个工具类型组合起来,构建最终的映射类型:
type RetainNullablesAsString<T> = { [C in keyof T as T[C] extends object ? HasNullableProps<T[C]> extends true ? C : never : never]: NullablePropsToString<T[C]>; };
这个类型的逻辑是:
- 遍历原始类型
T的所有键C - 仅保留那些
T[C]是对象类型,且HasNullableProps<T[C]>为true(即子对象有可空属性)的键 - 对保留的子对象,应用
NullablePropsToString转换,得到仅包含可空属性且类型为string的子类型
验证示例代码
现在用你的测试代码验证:
interface OriginalType { foo: { bar: string | null; baz: number | null; }; bar: { qux: string; quz: boolean | null; wobble: string | null; }; baz: { grault: string; garply: number; flob: boolean; }; version: number; } // 推导出来的类型完全符合你的ExpectedType type ResultType = RetainNullablesAsString<OriginalType>; const sourceRecord: OriginalType = { foo: { bar: 'bar', baz: 0, }, bar: { qux: 'qux', quz: false, wobble: null, }, baz: { grault: 'grault', garply: 1, flob: true, }, version: 1, } // 现在赋值不会有类型错误了 const sourceRecordMetaData: RetainNullablesAsString<OriginalType> = { foo: { bar: 'bar-meta', baz: 'baz-meta', }, bar: { quz: 'quz-meta', wobble: 'wobble-meta', }, }
此时ResultType的结构和你期望的ExpectedType完全一致,并且赋值时不会再出现Property 'qux' is missing的错误。
内容的提问来源于stack exchange,提问作者Robert
相关产品推荐
相关产品推荐

