tavoyne
tavoyne

Reputation: 6539

Generic that modifies a type's property

In TypeScript (4.5.2), I'm trying to create a generic that takes a type and modifies some of its properties.

type StrictNumber = {
  doesNotChange: string,
  nullable: false,
  value: number,
};

type MakeNullable<T extends { nullable: false, value: unknown }> = {
  [Property in keyof T]: Property extends 'nullable'
    ? true
    : Property extends 'value'
      ? T[Property] | null
      : T[Property]
};

type NullableNumber = MakeNullable<StrictNumber>;

Here's the resulting type for NullableNumber:

type NullableNumber = {
  doesNotChange: string,
  nullable: true,
  value: number | null,
};

Which is exactly what I want. However the MakeNullable generic is really not an elegant solution, it's very verbose. It would be even more if I added more properties to modify.

Upvotes: 1

Views: 240

Answers (1)

Aleksey L.
Aleksey L.

Reputation: 37938

You could infer the value type using conditional type:

type MakeNullable<T extends { nullable: false, value: unknown }> = T extends { value: infer V }
    ? { nullable: true, value: V | null } : never;

Playground


If you want to carry over all additional properties, you can make an intersection with original type, but omitting the modified properties:

type MakeNullable<T extends { nullable: false, value: unknown }> = T extends { value: infer V }
    ? Omit<T, 'nullable' | 'value'> & { nullable: true, value: V | null } : never;

Playground


Or even simpler (adjusted @captain-yossarian suggestion):

type MakeNullable<T extends { nullable: false, value: unknown }> =
    Omit<T, 'nullable' | 'value'> & { nullable: true, value: T['value'] | null }

Playground

Upvotes: 2

Related Questions