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 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
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"