Home > front end >  Typescript generic constraint for type with only properties from another type
Typescript generic constraint for type with only properties from another type

Time:02-10

I'm trying to create a Overwrite type that can overwrite an existing type's properties with a different type. For instance:

type TypeA = { prop1: string; prop2: number };

type OverwrittenType = Overwrite<TypeA, { prop2: string }>;
// OverwrittenType is now equivalent to { prop1: string; prop2: string }

I found this SO answer which does the job nicely, however it's a bit too permissive for my liking, as it allows you to replace properties that were never in the original type to begin with.

type TypeA = { prop1: string; prop2: number };

type OverwrittenType = Overwrite<TypeA, { prop3: string }>;
// OverwrittenType is now equivalent to { prop1: string; prop2: number; prop3: string }

Below is the Overwrite type from that other thread.

type Overwrite<T, U> = Pick<T, Exclude<keyof T, keyof U>> & U;

How do I need to modify it to prohibit replacement keys that are not present in the initial type?

type TypeA = { prop1: string; prop2: number };

type OverwrittenType = Overwrite<TypeA, { prop3: string }>; // Throw some sort of error here, prop3 is not a key of TypeA

CodePudding user response:

You can add a condition on you generic !

type Overwrite<T extends { [key in keyof U]: any }, U> = Omit<T, keyof U> & U;

type TypeA = { prop1: string; prop2: number };

type OverwrittenType = Overwrite<TypeA, { prop1: number }>;  // ok
const foo: OverwrittenType = { prop1: 3, prop2: 3 }

type OverwrittenType2 = Overwrite<TypeA, { prop3: number }>;  // error 
const bar: OverwrittenType = { prop1: 3, prop3: 3 }

Playground

CodePudding user response:

You could achieve this with a mapped type like this:

type TypeA = { prop1: string; prop2: number };

type Overwrite<T, U extends Partial<Record<keyof T, any>>> = { [Key in keyof T]: undefined extends U[Key] ? T[Key] : U[Key] };

type OverwrittenTypeWorks = Overwrite<TypeA, { prop2: string }>; //  { prop1: string, prop2: string }
type WrongOverwrittenType = Overwrite<TypeA, { prop3: string }>; // Throw some sort of error here, prop3 is not a key of TypeA

TypeScript playground

  • Related