繁体   English   中英

如何在CSS样式的打字稿中创建递归对象类型?

[英]How do I create recursive object type in typescript for css styles?

我正在使用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 }interface B extends A { b: string }依赖它,其中类型B的值也是类型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@next尝试每晚构建TypeScript

如果您不能等到那时或不能很快升级,可以通过使用映射类型将交集替换为外观更普通的对象来解决此问题:

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" 👍
        }
    }
}

游乐场链接

出现预期的错误,世界一切正常。 希望能有所帮助; 祝好运!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM