在为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
我想出的唯一答案就是让我的自定义选项可选
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