Home > other >  how do I create a "temporary" type inside a type, in order to be DRY?
how do I create a "temporary" type inside a type, in order to be DRY?

Time:01-04

I can't even know how to search in SO for this question. My generic type FetchOptions is actually this:

type FetchOptions<T> = {
  explode?: string & keyof T | (string & keyof T)[];
}

I can't find a way to create another type string & keyof T in order to avoid the repetition in the subsequent array definition and without extracting the type (inside the type itself):

type Key<T> = string & keyof T;

type Options<T> = {
  explode?: Key<T> | Key<T>[];
}

Example usage:

class Product {
  id: number | string;
  name: string;
  variants?: ProductVariant[];
  attributes?: ProductVariant[];
}

const fetchProducts = (options: FetchOptions<Product> = {}) => {
  // ...
};

fetchProducts({ explode: 'variants' });
fetchProducts({ explode: ['variants', 'attributes'] });

CodePudding user response:

I often see additional generic parameters with default values used to avoid repetition.

type FetchOptions<T, E = string & keyof T> = {
  explode?: E | E[];
}

When used like FetchOptions<Product>, you get the same behaviour as before. But you may have to worry about accidentally providing a second generic parameter. E is not constraint, so any type could be passed to FetchOptions.

We can add a constraint which would guarantee the correct type.

type FetchOptions<T, E extends string & keyof T = string & keyof T> = {
  explode?: E | E[];
}

But since this makes us type out the type twice, it is probably only useful if the type is used more often.


Playground

  • Related