使用material-ui @ next和typescript扩展主题

问题描述 投票:2回答:1

在为material-ui创建主题时,我添加了两个新的调色板选项,为我提供了更好的灯光和黑暗范围。我扩展了Theme类型来表明这一点

import {Theme} from "material-ui/styles";
import {Palette} from "material-ui/styles/createPalette";

export interface ExtendedTheme extends Theme {
    palette: ExtendedPalette
}

export interface ExtendedPalette extends Palette {
    light: Color,
    dark: Color,
}

当我尝试在WithStyles渲染助手中使用这些附加选项时,会出现问题

const styles = (theme : ExtendedTheme) => ({ root: {color: theme.light['100'] }});

export interface MyProps {classes: {[index: string] : string}};
const MyComponent = (props : MyProps) => {...};

// Type ExtendedTheme is not assignable to Theme
export default withStyles(styles : StyleRulesCallback)(MyComponent);

功能上我的代码在纯JavaScript中工作正常,但由于类型不同,它会抛出错误。 material-ui的类型期望一种Theme是样式回调函数的唯一参数:

export type StyleRulesCallback<ClassKey extends string = string> = (theme: Theme) => StyleRules<ClassKey>;

我认为扩展接口将以多态方式工作,以便ExtendedTheme实现Theme

javascript typescript material-ui
1个回答
1
投票

我想出的唯一答案就是让我的自定义选项可选

export interface ExtendedPalette extends Palette {
    light?: Color,
    dark?: Color,
}

然后在我的样式回调中我必须检查那些选项是否存在,这有点麻烦,但我不认为还有其他任何解决方法

const styles = (theme : ExtendedTheme) => { 
    let light = theme.palette.light[100];
    if(light === undefined) light = theme.common.white;
    { root: {color: light }}
};

原因是当我使用withStyles时,Theme对象被传递给回调,但是这个回调的类型使用Theme类型,因为他们无法知道我的ExtendedTheme类型。当ExtendedTheme必须拥有Theme一无所知的选项时,冲突就会出现。通过使这些额外的选项可选Theme仍然可以符合ExtendedTheme。基本上,扩展接口可以在其父级所需的位置传递,但是其父级不能在预期扩展接口的位置传递,除非扩展接口以父级仍然可以遵守的方式扩展。

一个更简单的例子是有益的。

export interface Foo {foo: string};
export interface Bar extends Foo {bar: string}

function getFoo(f : Foo) {console.log(f.foo)}
function getBar(b : Bar) {console.log(b.bar)} 
function getFooBar(fb: Bar) {console.log(fb.foo, fb.bar)}

const f : Foo = {foo: 'foo'}
const b : Bar = {foo: 'foo', bar: 'bar'}

getFoo(f) // foo
getFoo(b) // foo
getBar(f) // Error Incompatible Type
getBar(b) // bar
getFooBar(f) // Error Incompatible Type
getFooBar(b) // foo bar

getFoo(b)的作用是因为Bar至少保证了Foo所拥有的一切。 getBar(f)getFooBar(f)都失败了,因为编译器看到类型Foo没有密钥bar

通过像这样重新定义Bar

export interface Bar extends Foo {bar? : string}

编译器现在知道Foo匹配Bar类型的最小限定条件,但您必须检查隐式null。所以这会奏效

getBar(f)

但是编译器会对隐式空值大喊大叫,这很好,因为f.bar是未定义的。所以你必须重新定义你的功能

function getBar(b : Bar) {
    let bar = b.bar
    if(bar === undefined) bar = b.foo;
    console.log(bar);
}

getBar(b) // bar
getBar(f) // foo
© www.soinside.com 2019 - 2024. All rights reserved.