0

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, { prop1: number; prop2: string }>;
// OverwrittenType is now equivalent to { prop1: number; 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, { prop1: number; prop3: string }>;
// OverwrittenType is now equivalent to { prop1: number; 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, { prop1: number; prop3: string }>; // Throw some sort of error here, prop3 is not a key of TypeA
GravlLift
  • 63
  • 6

2 Answers2

0

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

Matthieu Riegler
  • 31,918
  • 20
  • 95
  • 134
  • Apologies, I didn't flesh out my example enough. This solution only works as well as the original solution in the case where you are overwriting both a real and not real property. I've modified my example to include a type change to prop1 as well. – GravlLift Feb 10 '22 at 13:28
0

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

Guerric P
  • 30,447
  • 6
  • 48
  • 86
  • Apologies, I didn't flesh out my example enough. This solution only works as well as the original solution in the case where you are overwriting both a real and not real property. I've modified my example to include a type change to prop1 as well. – GravlLift Feb 10 '22 at 13:29