I have a type which is the union of two interfaces:
interface Foo {
a: string
}
interface Bar {
b: string
}
type Baz = Foo | Bar;
I want to extend it, but it gives me an error:
interface Qux extends Baz { // error!
// ---------------> ~~~
// An interface can only extend an object type or
// intersection of object types with statically known members.
c: string;
}
interface Qux extends Baz { // error!
c: string;
}
Why do I get that error and what can I do about it?
Original version of question with more context:
I wrote a type file to augment the Palette
type defintion file in an npm library. (Material UI to be specific). If I try to have ODPaletteColorOptions
extend PaletteColorOptions
as shown in my code below, this does not successfully extend the PaletteColorOptions interface. Here is the outcome: apparently, the ODPaletteColorOptions interface only has the additional keys:
createPalette.d.ts
------------------
import { Palette as MuiPalette, PaletteColorOptions } from "@mui/material/styles/createPalette";
declare module "@mui/material/styles/createPalette" {
export interface ODPaletteColorOptions extends PaletteColorOptions {
1000: string,
white: string,
black: string,
0: string,
Search: string
}
export interface Palette extends MuiPalette{
neutrals: ODPaletteColorOptions,
};
}
Here is the definition of PaletteColorOptions
from the existing MUI type definition file.
export type PaletteColorOptions = SimplePaletteColorOptions | ColorPartial;
where
export interface SimplePaletteColorOptions {
light?: string;
main: string;
dark?: string;
contrastText?: string;
}
export type ColorPartial = Partial<Color>;
export interface Color {
50: string;
100: string;
200: string;
300: string;
400: string;
500: string;
600: string;
700: string;
800: string;
900: string;
A100: string;
A200: string;
A400: string;
A700: string;
}
However, if instead of extending PaletteColorOptions, I explicitly extend SimplePaletteColorOptions and ColorPartial, then the extension works.
import { Palette as MuiPalette, SimplePaletteColorOptions, ColorPartial } from "@mui/material/styles/createPalette";
declare module "@mui/material/styles/createPalette" {
export interface ODPaletteColorOptions extends SimplePaletteColorOptions, ColorPartial {
1000: string,
white: string,
black: string,
0: string,
Search: string
}
export interface Palette extends MuiPalette{
neutrals: ODPaletteColorOptions,
};
}
Why does the first approach fail?
In order for the compiler to process interface
types (as well as instances of class
types which can be seen as having an interface
of the same name as the class), they need to have a single set of statically known keys . Union types have multiple sets of keys, so you can't extend them into interfaces. See microsoft/TypeScript#13604 for a description of what types of things can be extended from (eg, object types and intersections of such types) as well as some things that cannot be (eg, generic type parameters).
That's why you would be allowed to extend Foo
or Bar
separately, but not the union Foo | Bar
Foo | Bar
.
Luckily, you can get much the same effect with intersection types , as described in the TS Handbook documentation for differences between type aliases and interfaces :
type Qux = Baz & { c: string }; // okay
Now a Qux
acts like a Baz
with a string
-valued c
property, which is presumably what you wanted to see:
function processQux(q: Qux) {
console.log(("a" in q ? q.a : q.b).toUpperCase() + " " + q.c);
}
const q: Qux = { a: "hey", c: "you" } // okay
processQux(q) // HEY you
processQux({ b: "it's", c: "me" }) // IT'S me
processQux({ c: "oops" }) // error!
// Argument of type '{ c: string; }' is not assignable to parameter of type 'Qux'.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.