修复TypeScript条件添加对象属性时的类型推导错误
解决TypeScript条件添加对象属性的类型定义问题
问题分析
当前实现的addIf和fancyObject功能逻辑正常,但类型推导存在缺陷:计算属性会被识别为宽泛的字符串索引,最终返回类型无法精准反映条件属性是否存在,不符合预期的明确类型定义。
解决方案
通过调整addIf的泛型条件类型,让TypeScript根据条件字面量判断返回的键类型;再通过映射类型过滤掉标记为移除的属性,实现精准的类型推导。
修改后的完整代码
const REMOVE_CONST = 'removeMe' // 根据条件字面量决定返回的键类型 const addIf = <T extends string, C extends boolean>( condition: C, key: T ): C extends true ? T : typeof REMOVE_CONST => { return (condition ? key : REMOVE_CONST) as any } // 映射类型:过滤掉键为REMOVE_CONST的属性 type FilterRemoveKeys<T> = { [K in keyof T as K extends typeof REMOVE_CONST ? never : K]: T[K] } function fancyObject<T extends Record<string, unknown>>(POJO: T): FilterRemoveKeys<T> { const { [REMOVE_CONST]: _, ...POJO_ } = POJO return POJO_ as FilterRemoveKeys<T> }
效果验证
- 条件为字面量
true:
const myObj = fancyObject({ a: 'apple', b: 'banana', c: 'cajo', [addIf(true, 'd')]: () => 'mew', }) // 推导类型(符合最优预期): // { // a: string; // b: string; // c: string; // d: () => string; // }
- 条件为字面量
false:
const myObj2 = fancyObject({ a: 'apple', [addIf(false, 'd')]: () => 'mew', }) // 推导类型: // { // a: string; // }
- 条件为动态布尔值(非字面量):
const condition = Math.random() > 0.5 const myObj3 = fancyObject({ a: 'apple', [addIf(condition, 'd')]: () => 'mew', }) // 推导类型(符合次优预期): // { // a: string; // d?: () => string; // }
原理说明
addIf通过泛型C extends boolean捕获条件的字面量类型,利用条件类型返回对应的键:条件为true时返回指定键T,为false时返回标记值REMOVE_CONST。FilterRemoveKeys映射类型遍历对象的所有键,仅保留非REMOVE_CONST的键,过滤掉需要移除的属性类型。- 这样TypeScript就能精准识别条件属性的存在性,避免出现宽泛的字符串索引签名。
内容的提问来源于stack exchange,提问作者Islam Y-
相关产品推荐
相关产品推荐

