使用material-ui @ next和typescript扩展主题 [英] Extending theme with material-ui@next and typescript

查看:127
本文介绍了使用material-ui @ next和typescript扩展主题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

material-ui创建主题时,我添加了两个新的调色板选项,这些选项使我可以使用更好的明暗度.我已经扩展了Theme类型来表明这一点

When creating my theme for material-ui I added two new palette options that give me a better range of lights and darks. I have extended the Theme type to indicate this

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渲染助手中使用这些其他选项时,会发生问题

The problem occurs when I try to use these additional options in the WithStyles render helper

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是样式回调函数的唯一参数:

Functionally my code works fine in pure javascript, but since the types are different it throws the error. The typings for material-ui expect a type of Theme to be the sole argument the the style callback function:

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

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

I thought that extending an interface would work in a polymorphic way so that ExtendedTheme would implement Theme

推荐答案

我想出的唯一答案就是像这样使我的自定义选项成为可选

The only answer I've come up with is to make my custom options optional like so

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

然后在样式回调中,我必须检查这些选项是否存在,这很麻烦,但我认为没有其他解决方法

Then in my styles callback I have to check that those options exist, which is kind of a hassle, but I don't think there is any other workaround

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.基本上,可以将扩展接口传递到期望其父对象的位置,但是不能将其父传递到期望扩展接口的位置,除非以仍然可以遵从父元素的方式扩展了扩展接口.

The reason for this is that the Theme object is passed to the callback when I use withStyles but the typings for this callback use the Theme type because they have no way of knowing about my ExtendedTheme type. The conflict comes in when ExtendedTheme must have options that Theme knows nothing about. By making those extra options optional Theme can still comply with ExtendedTheme. Basically an extended interface can be passed where its parent is expected, but its parent cannot be passed where the extended interface is expected, unless the extended interface is extended in a way that the Parent can still comply.

一个简单的例子是有启发性的.

A simpler example is instructive.

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

getFoo(b) works because Bar is guaranteed to have at least everything that Foo has. getBar(f) and getFooBar(f) both fail because the compiler sees that the type Foo does not have the key bar

通过重新定义Bar

export interface Bar extends Foo {bar? : string}

编译器现在知道Foo符合Bar类型的最低要求,但是您必须检查隐式null.这样就可以了

The compiler now knows that Foo matches the minimum qualifications for the Bar type, but you have to check for an implicit null. So this will work

getBar(f)

但是编译器会大喊隐式空值,这很好,因为f.bar是未定义的.因此,您必须像这样重新定义功能

But the compiler will yell about implicit nulls, which is good, because f.bar is undefined. So you have to redefine your function like so

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

getBar(b) // bar
getBar(f) // foo

这篇关于使用material-ui @ next和typescript扩展主题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆