Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to achieve type safety in this example using a generic type?

Consider the following example:

type A = {
  a: string;
  name: string;
}

type B = {
  b: string;
  name: string
}


function update<T extends A | B>(aOrB: T): T {
  return {...aOrB, name: "updated"}
}

const updatedA = update<A>({a: "a", name: "a"})
const updatedB = update<B>({b: "b", name: "B"})

How can we change this so that TypeScript can catch type errors within the update function?

Example type errors below that aren’t being caught:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

function update<T extends A | B>(aOrB: T): T {
  return {...aOrB, b: 2, name: "updated"}
}
function update<T extends A | B>(aOrB: T): T {
  return {...aOrB, foo: 2, name: "updated"}
}

I would expect that in each of the examples above that there would be a type error. In the first example, b is not guaranteed to exist, and if it does exist, it’s a string, not a number. In the second, foo is not a field on either type.

>Solution :

Instead of a generic type in the returned value, you can achieve it with a returned type A|B

Basically, a generic type cannot determine which type you want to have in the returned result, so you need to set a certain type for it

type A = {
  a: string;
  name: string;
}

type B = {
  b: string;
  name: string
}


function update<T extends A | B>(aOrB: T): (A|B) {
   return {...aOrB, b: 2, name: "updated"} //error
}

const updatedA = update<A>({a: "a", name: "a"})
const updatedB = update<B>({b: "b", name: "B"})

Playground

Another way we can try is having hasOwnProperty to check property in the data, and then using them to cast to a proper type. It’s kind of messy, but we would know types beforehand.

type A = {
  a: string;
  name: string;
}

type B = {
  b: string;
  name: string
}


function update<T extends A | B>(aOrB: T): (A|B) {
   if(aOrB.hasOwnProperty("b")) {
     return {...aOrB, a: "new", name: "updated"} as B //error
   }
   return {...aOrB, a: "new", name: "updated"} as A
}

const updatedA = update<A>({a: "a", name: "a"})
const updatedB = update<B>({b: "b", name: "B"})

Playground

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading