如何基于对象值动态创建TypeScript类型?
问题:基于设计令牌对象动态生成TypeScript颜色类型
我有一个包含所有设计令牌的对象,如下所示:
const Tokens = { neutralColor: { dark: { '100': '#123456', '200': '#223456', }, medium: { '100': '#654321', '200': '#876543', }, light: { '100': '#009988', '200': '#334411', } }, feedbackColor: { // 结构和neutralColor类似 }, // 其他颜色分组 }
我需要限制组件的color属性仅接受令牌中的值,比如:
<Typography color={Tokens.neutralColor.dark["100"]}>label</Typography> // 或者直接写对应字符串 <Typography color="#123456">label</Typography> // 因为Tokens.neutralColor.dark["100"]的值就是#123456
常规做法是手动创建联合类型:
type Color = "#123456" | "#223456" | "#654321" | /* 其他所有颜色值 */ type TypographyProps = { color: Color } function Typography(props: TypographyProps) { /* ... */ }
请问是否可以基于该令牌对象动态创建这个TypeScript类型?
解答
完全可以实现,核心是利用TypeScript的const断言和递归类型工具来自动提取所有颜色值:
步骤1:用as const锁定令牌的字面量类型
首先要确保TypeScript能精准推断出每个颜色的具体字符串值,而不是宽泛的string类型,所以需要给令牌对象加上as const断言:
const Tokens = { neutralColor: { dark: { '100': '#123456', '200': '#223456', }, medium: { '100': '#654321', '200': '#876543', }, light: { '100': '#009988', '200': '#334411', } }, feedbackColor: { success: '#00ff00', error: '#ff0000' } } as const;
步骤2:创建递归类型提取所有颜色值
编写一个递归的类型工具,遍历令牌对象的所有嵌套层级,收集所有字符串类型的颜色值:
// 递归提取所有嵌套的字符串值 type ExtractColorValues<T> = T extends string ? T : T extends object ? { [K in keyof T]: ExtractColorValues<T[K]> }[keyof T] : never; // 基于Tokens生成Color类型 type Color = ExtractColorValues<typeof Tokens>;
此时Color类型会自动生成为所有颜色值的联合类型,等价于:
type Color = "#123456" | "#223456" | "#654321" | "#876543" | "#009988" | "#334411" | "#00ff00" | "#ff0000";
步骤3:在组件Props中使用该类型
直接把生成的Color类型应用到组件属性上即可:
type TypographyProps = { color: Color; }; function Typography(props: TypographyProps) { return <span style={{ color: props.color }}>{props.children}</span>; }
这样就能实现需求:既可以传入令牌对象的属性值,也可以直接写对应的颜色字符串,同时TypeScript会自动校验值是否在令牌范围内。
内容的提问来源于stack exchange,提问作者Lai32290
相关产品推荐
相关产品推荐

