Home > database >  Is there a utility type or something similar derive the name of a key from another?
Is there a utility type or something similar derive the name of a key from another?

Time:03-27

This is a long shot but I would like to be able to generate a new interface from an existing one but with key names that are derived for the originals.

Below is an example of the kind of thing I would like to be able to do:

Given this source object:

interface Car {
  brand: Brand;
  model: string;
  year: number;
}

I would like to be able to declare an interface:

interface CarSetters {
  setBrand: (brand: Brand) => any;
  setModel: (model: string) => any;
  setYear: (year: number) => any;
}

but I don't want to have to declare it manually like above. Rather, I would like to be able to use it like:

type CarSetters = Setters<Car>

or

type CarState = Car & Setters<Car>

CodePudding user response:

It looks to be a pretty simple mapping:

type Brand = boolean;
interface Car {
  brand: Brand;
  model: string;
  year: number;
};
type CarSetters = {
    [T in keyof Car as `set${Capitalize<T>}`]: (newValue: Car[T]) => any;
};

To keep symbols from causing issues, you can do:

type CarSetters = {
    [T in keyof Car as T extends symbol ? never : `set${Capitalize<T>}`]: (newValue: Car[T]) => any;
};

or

type CarSetters = {
    [T in keyof Car as T extends symbol ? never : `set${Capitalize<T>}`]: (newValue: Car[T]) => any;
} & {
    [T in keyof Car as T extends symbol ? T : never]: Car[T];
};

CodePudding user response:

I was able to work out a generic that does exactly what I want, mostly thanks to the answer by CertainPerformance, which I have accepted since it does definately answer the question I asked. But I am also sharing the generics I came up with:

type Setters<T> = {
  [K in keyof T as K extends string ? `set${Capitalize<K>}` : never]: (
    value: T[K]
  ) => any;
};

type State<T> = T & Setters<T>
  • Related