css - 如何在 typescript 中为 css 样式创建递归对象类型?
问题描述
我React.CSSProperties
用于创建 css 变量,所以我可以创建像
let css: React.CSSProperties = {
position: "relative",
display: "inline-block",
background: "red"
}
我正在尝试创建一个主题,该主题将在根级别具有css变量或嵌套在修饰符中,例如 size(sm,md,lg) 或 variant(light,dark) 或其他如下
let theme: MyTheme = {
background: "red", // css
color: "white", // css
button: { // custom: component name Level1
background: "red", // css
color: "white", // css
light: { // custom: modifier variant Level2
background: "red", // css
color: "white", // css
hollow: { // custom: modifier Level3
borderColor: "red",
color: "red",
background: "transparent",
}
}
dark: {
background: "red",
color: "white",
hollow: {
borderColor: "black",
color: "black",
background: "transparent",
modfierLevel4: {
some: "css"
modfierLevel5: {
some: "css"
modfierLevel6: {
some: "css"
}
}
}
}
}
}
}
基本上我正在寻找如下打字稿中的递归对象类型,但最终以循环引用结束?
type Modifiers = 'button' | 'dark' | 'light' | 'otherModifiers'
interface Theme extends React.CSSProperties {
[k in Modifiers]?: Theme;
}
我能够找到接近它的答案(如下)。
type Theme = React.CSSProperties & { [keys in Modifiers]?: Theme }
但面临一些问题。如果给定的修饰符名称无效,例如“btn”而不是“button”
- 在级别 1 正确抛出错误(如预期的那样)
- 但从 2 级及更高级别不会引发错误。(但预计会抛出错误)
我应该如何为上述创建类型?
解决方案
假设您使用的是 TS3.4 或以下版本:
这是一个已知问题的结果,其中未对嵌套的交叉点类型(如Theme
. 从技术上讲,TypeScript 中的类型通常是“开放的”或“可扩展的”,这意味着类型的值可以具有比其类型定义中提到的更多的属性。interface A { a: string }
您可以使用and之类的东西来依赖它interface B extends A { b: string }
,其中 typeB
的值也是 type 的值A
。
但是通常当人们像您一样使用对象文字时,添加额外属性是错误的......尤其是在您的情况下,“额外”属性只是可选属性的印刷错误。所以编译器决定当你将一个新的对象字面量分配给一个类型时,额外的属性是一个错误。也就是说,新鲜对象文字的类型是“封闭的”或“精确的”......
...好吧,或者他们应该是,除了这个带有嵌套交叉点的错误。在 TypeScript 3.4 或更低版本中,行为如下:
type Foo = { baseProp: string, recursiveProp?: Foo };
const foo: Foo = {
baseProp: "a",
recursiveProp: {
baseProp: "b",
extraProp: "error as expected" // error
}
}
type Bar = { baseProp: string } & { recursiveProp?: Bar };
const bar: Bar = {
baseProp: "a",
recursiveProp: {
baseProp: "b",
extraProp: "no error?!" // no error in TS3.4
}
}
幸运的是,TypeScript 3.5 已修复此错误,该版本应于2019 年 5 月 30 日发布,或者您可以通过以下方式试用 TypeScript 的夜间版本typescript@next
如果您不能等到那个时候或者不能很快升级,您可以通过使用映射类型将交集替换为看起来更正常的对象来解决此问题:
type Id<T> = { [K in keyof T]: T[K] };
type Bar = Id<{ baseProp: string } & { recursiveProp?: Bar }>;
const bar: Bar = {
baseProp: "a",
recursiveProp: {
baseProp: "b",
recursiveProp: {
baseProp: "c",
extraProp: "error yay"
}
}
}
出现了预期的错误,世界一切正常。希望有帮助;祝你好运!
推荐阅读
- python - kivy multicolor ListView
- sql - 使用 Multi 运算符从 sql 中选择
- python - 无法在 localhost 中查找文件大小 > 10MB 的视频 - Django
- r - 不良行为 - as.double 舍入小数
- css - 动画背景位置以连续水平移动
- node.js - 如果我禁用 NODE_TLS_REJECT_UNAUTHORIZED,我的请求仍然被拒绝
- ios - 在固定点和我在 iOS 中的当前位置之间行走时计算距离
- json - 如何编写 Elasticsearch 多个必须脚本查询?
- visual-studio - 添加表适配器时未将对象引用设置为对象的实例
- c# - 使用 Linq 从列表中删除两个重复项(如果一个重复项)