类型安全需主动约束:vanilla extract 本身无类型安全,须配合 typescript 显式契约;style 返回 string 不校验存在性,stylevariants 要求字面量对象与联合类型键,defineproperties + stylemap 依赖 const 断言,createthemecontract 强制主题结构完整性。

Vanilla Extract 本身不提供类型安全,类型安全必须靠 TypeScript + 显式契约定义来实现;直接用 style 返回的类名是 string,拼错、传错都编译通过,但运行时失效。
为什么 style 函数返回值不是类型安全的
它只生成一个字符串类名,TypeScript 不校验这个字符串是否真实存在或是否被正确使用:
-
div.className = 'btn-prmry'—— 拼错primary为prmry,TS 不报错,但样式不生效 -
const btn = style({ color: 'red' }); button.className = btn + '-hover'—— 动态拼接破坏类型上下文,无法推导 - 组件 props 接收
variant: string,再用于索引variants[variant],TS 无法约束合法键名
用 styleVariants 实现有限枚举态的类型约束
适合按钮、标签等「状态明确、数量固定」的场景,让 TS 推导出 Record 类型:
- 定义时必须用字面量对象,且所有键显式写出:
styleVariants({ primary: {…}, secondary: {…} }) - 不能用动态 key:
styleVariants({ [key]: {…} })会丢失类型,TS 退化为Record<string string></string> - 使用时必须传入联合类型值:
button.className = variants[props.variant]要求props.variant是'primary' | 'secondary',否则报错 - 如果 props 来自 API 或表单输入(运行时字符串),需先做类型守卫或
as const断言
用 defineProperties + styleMap 管理设计 token 类型
当你有一套固定的设计系统(如 spacing、colors、radii),这才是真正可控的类型安全路径:
-
defineProperties的参数必须是const断言对象,否则 TS 无法精确推导键名类型:const tokens = { sm: '4px', md: '8px' } as const -
styleMap基于该对象生成可索引映射,返回类型为Record - 调用
paddingMap['sm']是类型安全的;paddingMap['xl']直接报错 - 注意:
styleMap只接受静态属性名,不支持表达式或变量索引
主题类型安全必须用 createThemeContract
手动写 createTheme 无法约束主题变量结构,容易漏字段或类型错配:
-
createThemeContract返回一个类型契约对象,比如{ color: { bg: null, text: null } } - 后续
createTheme必须完整填充该结构,缺color.text或多出color.border都会 TS 报错 - 动态计算值(如
color: { bg: someFn() })会丢失类型推导,契约中应只放静态值或null占位符 - 主题变量引用必须通过契约导出的
vars对象,不能直接访问原始对象
最易被忽略的一点:类型安全不是开箱即用的,它依赖你主动放弃“字符串自由”,转而用 const 断言、显式联合类型、契约先行这些约束手段。一旦在某个环节松动(比如把 styleVariants 的 key 改成变量),整条类型链就断了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











