1

How to type a function that add a property with generics in typescript?

Consider this function:

export function addAge(obj) {
  Object.defineProperty(obj, 'age', {
    value: null,
  });
  return obj;
}

Could I use generics in typescript for know that I will return the object for the parameter with a new property?

Using like so:

interface IPerson {
 name: string;
}

const person: IPerson = { name: 'Juan' };

const result = addAge<IPerson>(person);
// result.age // number | null
// result.name // string

Submitted July 21st 2021 by Admin

Answers
0

You could indeed make addAge generic in the type T of obj, and return a value which is the intersection of T with { age: number | null } or whatever property type you're adding:

function addAge<T>(obj: T) { Object.defineProperty(obj, 'age', { value: null, }); return obj as T & { age: number | null };
}

Note that I have to use a type assertion to tell the compiler that obj actually has a new property; the call signature of Object.defineProperty() doesn't mutate the type of its input, so the compiler has no idea that obj is anything but T at the end of the function.

(Aside: the actual code here makes age a readonly property at runtime, although the type {age: number | null} implies that you should be able to set the property as well as get it. You could use {readonly age: number | null} instead, or you could just use Object.defineProperty() so that the property is writable, or any number of other ways of setting the property. I'll consider any of this stuff out of scope for the question, though.)


Anyway we can now test it:

const result = addAge(person);
/* const result: IPerson & { age: number | null;
} */
console.log(result.name.toUpperCase()); // "JUAN"
console.log((result.age ?? 0).toFixed(2)); // "0.00"

Looks good.

Playground link to code

Admin | 5 days ago



Relevant Questions