TypeScript:嵌套对象属性的联合类型收窄问题
TypeScript 类型收窄问题:通过type属性识别具体类型
我编写了以下TypeScript代码,目标是让TypeScript通过对象的type属性,自动识别values中name属性为DesignValueText类型,但目前访问values.name.text时会报错,提示“类型‘DesignValue’上不存在属性‘text’”和“类型‘DesignValueHtml’上不存在属性‘text’”。
type DesignValueType = "text" | "html" | "image"; type BaseDesignValue<TType extends DesignValueType, TProps> = TProps & { type: TType; }; type DesignValueText = BaseDesignValue<"text", { text: string }>; type DesignValueHtml = BaseDesignValue<"html", { html: string }>; type DesignValueImage = BaseDesignValue<"image", { url: string }>; type DesignValue = DesignValueText | DesignValueHtml | DesignValueImage; type DesignValues<TInitialValues> = Record<keyof TInitialValues, DesignValue>; const initialValues = { name: { type: "text" as const, text: "" }, handler: { type: "text" as const, text: "" }, text: { type: "html" as const, html: "" }, profile: { type: "image" as const, url: "" }, }; const displayName = (values: DesignValues<typeof initialValues>) => { // 类型“DesignValue”上不存在属性“text”。 // 类型“DesignValueHtml”上不存在属性“text”。 return values.name.text; };
解决方案
问题出在DesignValues类型的定义上,原Record类型会将所有属性统一设为DesignValue联合类型,丢失了每个键对应的具体子类型信息。我们需要改用映射类型,根据初始值中每个属性的type来映射到对应的具体DesignValue子类型:
type DesignValues<TInitialValues extends Record<string, DesignValue>> = { [K in keyof TInitialValues]: TInitialValues[K]['type'] extends 'text' ? DesignValueText : TInitialValues[K]['type'] extends 'html' ? DesignValueHtml : TInitialValues[K]['type'] extends 'image' ? DesignValueImage : never; };
原理说明
- 映射类型
[K in keyof TInitialValues]遍历TInitialValues的每个键 - 通过条件类型判断每个键对应的
type属性值,匹配到对应的DesignValueText/DesignValueHtml/DesignValueImage类型 - 这样TypeScript就能准确推断
values.name的类型为DesignValueText,访问values.name.text时不会再报错
修改后的代码中,displayName函数可以正常访问values.name.text,TypeScript会正确识别其类型。
内容的提问来源于stack exchange,提问作者Bruno Quaresma
相关产品推荐
相关产品推荐

