使用material-ui @ next和typescript扩展主题 [英] Extending theme with material-ui@next and 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屋!