Override the properties of an interface in TypeScript
UPDATE, 2018-08
TypeScript 2.8 introduced Exclude<T, U>
which behaves like the Diff<T, U>
defined below for all types (not just key types). You should definitely use Exclude<>
instead of Diff<>
if you are using TypeScript 2.8 or above.
Also, in TypeScript 2.9, keyof any
was expanded from string
to string | number | symbol
, so the below Diff<T, U>
caused errors which can be fixed by changing Diff<T extends string, U extends string>
to Diff<T extends keyof any, U extends keyof any>
. This change has been made below.
ORIGINAL ANSWER, 2018-03
Yes, conditional types will enable this, although you can get this behavior without them as well.
The idea is to pull properties out of the original interface and then replace them with new ones. Like this:
type Diff<T extends keyof any, U extends keyof any> =
({ [P in T]: P } & { [P in U]: never } & { [x: string]: never })[T];
type Overwrite<T, U> = Pick<T, Diff<keyof T, keyof U>> & U;
interface OriginalInterface {
title?: string;
text?: string;
anotherProperty?: SomeType;
// lots of other properties
}
interface Extension {
title?: string | ReactElement<any>;
text?: string | ReactElement<any>;
}
interface ExtendedInterface extends Overwrite<OriginalInterface, Extension> {};
const ext: ExtendedInterface = {}; // okay, no required properties
ext.text; // string | ReactElement<any> | undefined
ext.title; // string | ReactElement<any> | undefined
ext.anotherProperty; // SomeType | undefined
EDIT: I changed the definition of Overwrite<T,U>
to respect the optional/required status of properties from T
whose keys are not present in U
.
This has the behavior you want, I think. Hope that helps; good luck!
Using TypeScript Omit:
Omit<T,K>
Constructs a type by picking all properties from T and then removing K
// original interface
interface A {
a: number;
b: number; // we want string type instead of number
}
// Remove 'b'
type BTemp = Omit<A, 'b'>;
// extends A (BTemp) and redefine b
interface B extends BTemp {
b: string;
}
const a: B = {
a: 5,
b: 'B'
}
Breaking change since 2.9: https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#keyof-now-includes-string-number-and-symbol-keys
Use
Extract<keyof T, string>
to avoid
Type 'keyof T' does not satisfy the constraint 'string'.
Edit: Would have written a comment for this, but lack the necessary reputation