Extending Theme With Material-ui@next And Typescript
Solution 1:
The problem can be solved using module augmentation:
declaremodule'@material-ui/core' {
interfaceTheme {
colors: {
success: {
dark: string,
light: string,
}
}
}
}
Furthermore, you may declare the module in your App component as well as wrapping the children in a ThemeProvider:
import { createMuiTheme, ThemeProvider, colors, ThemeOptions } from'@material-ui/core';
declaremodule'@material-ui/core' {
interfaceTheme {
colors: {
success: {
dark: string,
light: string,
}
}
}
}
constApp = () => {
const theme = createMuiTheme({
colors: {
success: {
dark: colors.green[600],
light: colors.green[300],
},
} asThemeOptions,
});
return (
<ThemeProvidertheme={theme}><ahref="https://material-ui.com/customization/theming/">Theming</a></ThemeProvider>
)
Solution 2:
The only answer I've come up with is to make my custom options optional like so
exportinterfaceExtendedPaletteextendsPalette {
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
conststyles = (theme : ExtendedTheme) => {
let light = theme.palette.light[100];
if(light === undefined) light = theme.common.white;
{ root: {color: light }}
};
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) // foogetFoo(b) // foogetBar(f) // Error Incompatible TypegetBar(b) // bargetFooBar(f) // Error Incompatible TypegetFooBar(b) // foo bargetFoo(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
By redefining Bar like so
exportinterfaceBarextendsFoo {bar? : string}
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)
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
functiongetBar(b : Bar) {
let bar = b.barif(bar === undefined) bar = b.foo;
console.log(bar);
}
getBar(b) // bargetBar(f) // foo
Post a Comment for "Extending Theme With Material-ui@next And Typescript"