type ModifiedType = Modify<OriginalType, { a: number; b: number; }>
Вдохновленный ZSkycat's extends Omit
решение, я придумал это:
type Modify<T, R> = Omit<T, keyof R> & R; // before typescript@3.5 type Modify<T, R> = Pick<T, Exclude<keyof T, keyof R>> & R
Пример:
interface OriginalType {
a: string;
b: boolean;
c: number;
}
type ModifiedType = Modify<OriginalType , {
a: number;
b: number;
}>
// ModifiedType = { a: number; b: number; c: number; }
Движение шаг за шагом:
type R0 = Omit<OriginalType, 'a' | 'b'> // { c: number; }
type R1 = R0 & {a: number, b: number } // { a: number; b: number; c: number; }
type T0 = Exclude<'a' | 'b' | 'c' , 'a' | 'b'> // 'c'
type T1 = Pick<OriginalType, T0> // { c: number; }
type T2 = T1 & {a: number, b: number } // { a: number; b: number; c: number; }
Расширяя ответ @zSkycat немного, можно создать дженерик, который принимает два типов объектов и возвращает объединенный тип с участниками второго переопределения членов первого.
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
type Merge<M, N> = Omit<M, Extract<keyof M, keyof N>> & N;
interface A {
name: string;
color?: string;
}
// redefine name to be string | number
type B = Merge<A, {
name: string | number;
favorite?: boolean;
}>;
let one: A = {
name: 'asdf',
color: 'blue'
};
// A can become B because the types are all compatible
let two: B = one;
let three: B = {
name: 1
};
three.name = 'Bee';
three.favorite = true;
three.color = 'green';
// B cannot become A because the type of name (string | number) isn't compatible
// with A even though the value is a string
// Error: Type {...} is not assignable to type A
let four: A = three;