TypeScript中const对象类型访问可选属性报错如何解决?
解决TypeScript中访问联合类型属性的类型错误
问题场景
你定义了一个带有as const的只读对象,遍历其键数组时,访问部分键对应的对象的可选属性时触发类型错误,即使使用"optional" in判断也无法解决:
const props = { a: { optional: "foo", mandatory: "bar", }, b: { mandatory: "blaz", }, } as const; const propsICareAbout: (keyof typeof props)[] = []; for (const prop of propsICareAbout) { if (props[prop].optional) { doStuff(props[prop].optional); } }
报错信息:
Property 'optional' does not exist on type '{ readonly mandatory: "blaz"; }'.
原因分析
as const将props的类型锁定为精确的只读字面量联合类型:typeof props['a'] | typeof props['b']。其中typeof props['b']没有optional属性,TypeScript无法通过"optional" in自动缩小联合类型的范围,因此直接访问会触发类型检查错误。
解决方案
方案1:自定义类型守卫(推荐)
编写类型守卫函数,明确告诉编译器当条件满足时,当前对象包含optional属性:
const props = { a: { optional: "foo", mandatory: "bar", }, b: { mandatory: "blaz", }, } as const; const propsICareAbout: (keyof typeof props)[] = []; // 自定义类型守卫,判断对象是否包含optional属性 function hasOptional(obj: typeof props[keyof typeof props]): obj is typeof props['a'] { return "optional" in obj; } for (const prop of propsICareAbout) { const currentProp = props[prop]; if (hasOptional(currentProp)) { doStuff(currentProp.optional); // 类型检查通过 } } function doStuff(str: string) { console.log(str); }
方案2:类型断言(适合逻辑确定的场景)
直接通过类型断言指定当前对象为包含optional属性的类型,跳过类型检查:
const props = { a: { optional: "foo", mandatory: "bar", }, b: { mandatory: "blaz", }, } as const; const propsICareAbout: (keyof typeof props)[] = []; for (const prop of propsICareAbout) { const currentProp = props[prop]; if ("optional" in currentProp) { // 断言为包含optional的类型 doStuff((currentProp as typeof props['a']).optional); } } function doStuff(str: string) { console.log(str); }
方案3:统一类型定义(牺牲精确性换简洁)
提前定义包含可选optional属性的类型,让所有对象都遵循该类型,避免联合类型的问题:
// 定义统一的属性类型,optional为可选属性 type PropItem = { mandatory: string; optional?: string; }; const props: Record<string, PropItem> = { a: { optional: "foo", mandatory: "bar", }, b: { mandatory: "blaz", }, } as const; const propsICareAbout: (keyof typeof props)[] = []; for (const prop of propsICareAbout) { if (props[prop].optional) { doStuff(props[prop].optional); // 类型检查通过 } } function doStuff(str: string) { console.log(str); }
内容的提问来源于stack exchange,提问作者user3064538
相关产品推荐
相关产品推荐

