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"];
};
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
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;
};
*/