为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
答案 0 :(得分:2)
可以使用module augmentation解决该问题:
declare module '@material-ui/core' {
interface Theme {
colors: {
success: {
dark: string,
light: string,
}
}
}
}
此外,您可以在App组件中声明该模块,并将子级包装在ThemeProvider
中:
import { createMuiTheme, ThemeProvider, colors, ThemeOptions } from '@material-ui/core';
declare module '@material-ui/core' {
interface Theme {
colors: {
success: {
dark: string,
light: string,
}
}
}
}
const App = () => {
const theme = createMuiTheme({
colors: {
success: {
dark: colors.green[600],
light: colors.green[300],
},
} as ThemeOptions,
});
return (
<ThemeProvider theme={theme}>
<a href="https://material-ui.com/customization/theming/">Theming</a>
</ThemeProvider>
)
答案 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
1}}类型。当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