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

TypeScript Extend a dynamically generated type by an additional property

Based on this question, I have implemented my custom types:

export enum Category {
  car = 'car',
  truck = 'truck',
}

export interface Property {
  readonly name: string,
  readonly label: string,
  readonly type: 'number' | 'string',
}


export interface CategoryDefinition {
  readonly category: Category,
  readonly label: string,
  readonly properties: readonly Property[]
}

type TypeMap = {
  string: string;
  number: number;
};

type FromDefinition<D extends CategoryDefinition> = {
  [T in D['properties'][number] as T['name']]: TypeMap[T['type']];
};

For this (roughly):

const car = {
      category: Category.car,
      label: 'Car',
      properties: [
      {
        name: 'weight',
        label: 'Weight',
        type: 'number',
      }
    ],
} as const satisfies CategoryDefinition; 

export type Car = FromDefinition<typeof car>;

correctly creates

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

type Car = {
    weight: number;
}

Let’s say, I would have to expand this type, so that it includes the category, looking like that:

type Car = {
    category: 'car';
    weight: number;
}

The closest I could come up with, is this:

export type CategoryExtension= {
  category: Category
};

type FromDefinition<D extends CategoryDefinition> = {
  [T in D['properties'][number] as T['name']]: TypeMap[T['type']];
} & CategoryExtension; // <----

export type Car = FromDefinition<typeof car>;

which kind of results in what I want, but looks odd:

type Car = {
    height: number;
} & CategoryExtension // <---- 

How can I create the following?:

type Car = {
    height: number;
    category: 'car' // or Category
} 

>Solution :

Traditionally this is done by making TS infer the result and a homomorphic mapped type:

type FromDefinition<D extends CategoryDefinition> = ({
  [T in D['properties'][number] as T['name']]: TypeMap[T['type']];
} & CategoryExtension) extends infer O ? { [K in keyof O]: O[K] } : never;
//                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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