Home > Software design >  How to change the name of a type key selected using Pick?
How to change the name of a type key selected using Pick?

Time:11-04

I have this type:

type Item = {
  title: string
}

and I want to Pick the title property as use it in another type definition:

type NewItem = Pick<Item, 'title'>

However, in NewType I want title to be named newTitle. How do I do this?

CodePudding user response:

I wouldn't even use Pick anymore:

type Item = {
  title: string
};

type NewItem = {
    newTitle: Item["title"];
};

Playground

CodePudding user response:

@caTS has the better answer in this simple case. But I'm going to assume this example is contrived, and your real types are more complex.


Typically if you want to change a single prop drastically you are looking at more of a type operation like:

Omit<T, K> & { [newKey in K]: NewTypeHere }

Using that strategy you can make a type that renames a property like so:

type RenameProp<T, K1 extends keyof T, K2 extends string> =
    Omit<T, K1> & { [newKey in K2]: T[K1] }

Which you would use like so:

type Item = {
  title: string
  content: string
}

type NewItem = RenameProp<Item, 'title', 'newTitle'>
const newItem: NewItem = { newTitle: 'testing', content: 'abc123' } // fine

See playground

CodePudding user response:

You can use a mapped type utility to rename all of the picked properties, such as this example:

type PickAndRename<T, PropMap extends Partial<Record<keyof T, string>>> = {
  [
    K in keyof PropMap as K extends keyof T
      ? PropMap[K] extends string
        ? PropMap[K]
        : never
      : never
  ]: K extends keyof T ? T[K] : never;
};

which, when used with the details in your question:

type Item = {
  title: string;
};

type NewItem = PickAndRename<Item, { title: 'newTitle' }>;

results in a type that looks like this:

type NewItem = {
  newTitle: string;
};

An advantage of using a type utility is that you now have the flexibility to pick more than one property (just like with Pick<Type, Keys>) and rename it... all while using exactly the same syntax. For example:

type PersonDetails = {
  age: number;
  name: string;
  nameLast: string;
};

type NewPersonDetails = PickAndRename<PersonDetails, {
  name: 'firstName';
  nameLast: 'lastName';
}>;

/* Looks like:

type NewPersonDetails = {
  firstName: string;
  lastName: string;
};

*/

It can also ignore when you pick invalid properties:

type NewPersonDetails2 = PickAndRename<PersonDetails, {
  name: 'firstName';
  age: 'personAge';
  somePropNotPresent: 'someNewName';
}>;

/* Looks like:

type NewPersonDetails2 = {
  firstName: string;
  personAge: number;
};

*/

Code in TS Playground

  • Related