如何为按钮样式常量对象添加类型,同时通过两类类型检查?
问题:为样式对象指定兼具理论与实际形状的TypeScript类型
我有一个表示样式集合的JavaScript对象,期望其类型符合Record<string, CSSProperties>:
const buttonStyles = { Primary: { color: 'green', fontSize: '18px', }, Secondary: { color: 'grey', } }
第一种错误场景
以下代码会触发类型检查错误:
function getFontSize(btnType: keyof typeof buttonStyles): string | undefined { // 错误:属性 'fontSize' 不存在于类型 [...] return buttonStyles[btnType].fontSize } // 这段代码能正常通过类型检查 const primaryFontSize: string = buttonStyles.Primary.fontSize
第二种错误场景
如果显式将对象类型声明为Record<string, CSSProperties>:
const buttonStyles: Record<string, CSSProperties> = { Primary: { color: 'green', fontSize: '18px', }, Secondary: { color: 'grey', } }
会修复上述错误,但又出现新的类型错误:
function getFontSize(btnType: keyof typeof buttonStyles): string | undefined { // 这段代码现在能通过类型检查 return buttonStyles[btnType].fontSize } // 错误:类型“string | undefined”无法赋值给类型“string” const primaryFontSize: string = buttonStyles.Primary.fontSize
如何为buttonStyles指定类型,使其既符合CSSProperties的“理论形状”,又保留对象自身的“实际形状”,让两段代码都能通过类型检查?
解决方案
核心思路是让TypeScript保留对象的具体结构推导,同时验证每个属性值符合CSSProperties类型,以下是几种可行方案:
方案一:使用satisfies关键字(TypeScript 4.9+ 推荐)
satisfies关键字的作用是验证对象是否符合指定类型,但不会覆盖TypeScript对对象结构的自动推导,完美满足需求:
import type { CSSProperties } from 'react'; // 根据实际环境引入CSSProperties类型 const buttonStyles = { Primary: { color: 'green', fontSize: '18px', }, Secondary: { color: 'grey', } } satisfies Record<string, CSSProperties>; // 两段代码均可通过类型检查 function getFontSize(btnType: keyof typeof buttonStyles): string | undefined { return buttonStyles[btnType].fontSize; } const primaryFontSize: string = buttonStyles.Primary.fontSize;
方案二:泛型辅助函数(兼容旧版TypeScript)
如果你的TypeScript版本低于4.9,可以用泛型函数来同时实现类型约束和结构推导:
import type { CSSProperties } from 'react'; function createStyleCollection<T extends Record<string, CSSProperties>>(styles: T): T { return styles; } const buttonStyles = createStyleCollection({ Primary: { color: 'green', fontSize: '18px', }, Secondary: { color: 'grey', } }); // 同样满足需求 function getFontSize(btnType: keyof typeof buttonStyles): string | undefined { return buttonStyles[btnType].fontSize; } const primaryFontSize: string = buttonStyles.Primary.fontSize;
方案三:手动联合类型(适合结构固定的场景)
如果样式对象的结构不会变动,也可以手动定义具体类型,再与Record<string, CSSProperties>交叉:
import type { CSSProperties } from 'react'; // 手动定义对象的具体结构类型 type ButtonStyleMap = { Primary: { color: string; fontSize: string }; Secondary: { color: string }; }; // 交叉类型确保既符合具体结构,又满足CSSProperties约束 const buttonStyles: ButtonStyleMap & Record<string, CSSProperties> = { Primary: { color: 'green', fontSize: '18px', }, Secondary: { color: 'grey', } }; // 两段代码均可通过检查 function getFontSize(btnType: keyof typeof buttonStyles): string | undefined { return buttonStyles[btnType].fontSize; } const primaryFontSize: string = buttonStyles.Primary.fontSize;
内容的提问来源于stack exchange,提问作者foucdeg
相关产品推荐
相关产品推荐

