TypeScript类型推断疑问:map返回对象属性类型为何从联合类型变string
问题分析与解决
原因
TypeScript 对对象字面量的属性类型存在类型拓宽行为:当你在回调中返回匿名对象时,TS 默认认为该对象后续可能被修改,因此会把原本的字面量联合类型 'not'|'and' 拓宽为更宽泛的 string 类型,导致最终 foo 的类型不符合预期。
解决方案
以下几种方式可以保留 logic 的联合类型:
方案1:使用 as const 断言
在返回的对象上添加 as const,强制 TS 保留字面量类型(此时 logic 会变为只读属性):
const foo = [1,2].map((item) => { const logic = item === 1 ? 'not' : 'and'; return { logic, } as const; }); // foo 类型:readonly { readonly logic: "not" | "and"; }[]
如果不需要只读属性,可以结合类型工具去除只读:
type Mutable<T> = { -readonly [K in keyof T]: T[K] }; const foo = [1,2].map((item): Mutable<{ readonly logic: 'not' | 'and' }> => { const logic = item === 1 ? 'not' : 'and'; return { logic, } as const; }); // foo 类型:{ logic: "not" | "and"; }[]
方案2:显式指定 map 的泛型参数
直接给 map 方法指定返回值的类型,约束 TS 按照指定类型推断:
const foo = [1,2].map<{ logic: 'not' | 'and' }>((item) => { const logic = item === 1 ? 'not' : 'and'; return { logic, }; }); // foo 类型:{ logic: "not" | "and"; }[]
方案3:定义类型别名并指定返回类型
先定义目标类型,再在回调中明确返回该类型:
type LogicItem = { logic: 'not' | 'and' }; const foo = [1,2].map((item): LogicItem => { const logic = item === 1 ? 'not' : 'and'; return { logic, }; }); // foo 类型:LogicItem[](等价于 { logic: "not" | "and"; }[])
内容的提问来源于stack exchange,提问作者octkun
相关产品推荐
相关产品推荐

