const merge = <T, U extends T>(obj1: T, obj2: U): T & U => ({
...obj1,
...obj2,
});
override({ a: 1 }, { a: 24, b: 8 });
// override({ a: 2 }, { x: 73 }); /* compile error */
<T, U extends T>
「ここでの extends は、関数 override() の第 2 引数 obj2 の型を定義している型引数 U が第 1 引数 の型 obj1 の型 T と同じか拡張したものでなければならないことを示唆するもの。だからその条件 に従わない引数を渡そうとするとコンパイルで弾かれるの」
TextendsU?X:Y
型 T が 型 U を拡張していた場合は型 X を、それ以外の場合は型 Y となる型の記述
type User = { id: unknown };
type NewUser = User & { id: string };
type OldUser = User & { id: number };
type Book = { isbn: string };
type IdOf<T> = T extends User ? T['id'] : never;
type NewUserId = IdOf<NewUser>; //string
type OldUserId = IdOf<OldUser>; //number
type BookId = IdOf<Book>; // never