如何解决TypeScript中嵌套对象属性访问的类型匹配问题
问题
我实现了一个TypeScript函数,接收primary.500这类格式的字符串颜色参数,返回对应的hex颜色值。所有颜色存储在PALETTE常量对象中,我通过点号拆分字符串,将第一个元素作为PALETTE的键、第二个元素作为子对象的键来取值,但在colorValue = PALETTE[key][value]行出现TypeScript类型错误,该如何修复?
原代码如下:
const PALETTE = { common: { white: "#fff", black: "#000", }, primary: { 500: "#222", 700: "#333", }, secondary: { 500: "#444", 700: "#555", }, } as const; type Palette = typeof PALETTE; type ColorVariant = { [K in keyof Palette]: `${K}.${Exclude<keyof Palette[K], symbol>}`; }[keyof Palette]; type ColorVariantKey = { [K in keyof Palette]: Exclude<keyof Palette[K], symbol>; }[keyof Palette]; type GetColor = ColorVariant | "inherit"; const getColor = (color: GetColor) => { let colorValue = "inherit"; if (color !== "inherit") { const [key, value] = color.split(".") as [keyof Palette, ColorVariantKey]; colorValue = PALETTE[key][value]; // 此处出现TypeScript类型错误 } return colorValue; }; getColor("common.white"); getColor("primary.500"); getColor("secondary.700");
解决方案
错误原因
TypeScript无法确保拆分后的key和value是匹配的:ColorVariantKey是所有子键的联合类型("white" | "black" | "500" | "700"),当key为common时,TypeScript无法排除value是500的可能性,而common对象并没有500这个键,因此触发类型不兼容错误。
修复方式
方式1:类型断言(快速解决)
直接对取值结果做类型断言,告诉TypeScript该操作是安全的:
const getColor = (color: GetColor) => { let colorValue = "inherit"; if (color !== "inherit") { const [key, value] = color.split(".") as [keyof Palette, ColorVariantKey]; // 断言为具体的颜色值类型 colorValue = PALETTE[key][value] as (typeof PALETTE)[keyof typeof PALETTE][keyof (typeof PALETTE)[keyof typeof PALETTE]]; } return colorValue; };
如果只需要确保是字符串类型,也可以简化为:
colorValue = PALETTE[key][value] as string;
方式2:类型守卫(更严谨)
通过分支判断缩小key的范围,让TypeScript明确value对应的子键类型:
const getColor = (color: GetColor) => { let colorValue = "inherit"; if (color !== "inherit") { const [key, value] = color.split(".") as [keyof Palette, ColorVariantKey]; if (key === "common") { colorValue = PALETTE.common[value as keyof typeof PALETTE.common]; } else if (key === "primary") { colorValue = PALETTE.primary[value as keyof typeof PALETTE.primary]; } else if (key === "secondary") { colorValue = PALETTE.secondary[value as keyof typeof PALETTE.secondary]; } } return colorValue; };
方式3:泛型重构(最安全)
使用泛型让TypeScript跟踪key和value的对应关系,从根源上避免类型不匹配:
const PALETTE = { common: { white: "#fff", black: "#000", }, primary: { 500: "#222", 700: "#333", }, secondary: { 500: "#444", 700: "#555", }, } as const; type Palette = typeof PALETTE; type ColorVariant = `${keyof Palette}.${keyof Palette[keyof Palette]}`; type GetColor = ColorVariant | "inherit"; const getColor = <K extends keyof Palette, V extends keyof Palette[K]>(color: `${K}.${V}` | "inherit") => { if (color === "inherit") return "inherit"; const [key, value] = color.split(".") as [K, V]; return PALETTE[key][value]; }; getColor("common.white"); getColor("primary.500"); getColor("secondary.700");
这种方式下,TypeScript会严格校验输入的字符串格式,甚至能在你输入错误的键值对时给出提示。
内容的提问来源于stack exchange,提问作者qweezz
相关产品推荐
相关产品推荐

