Supposed I have the following interface:
interface Person {
name: string;
age: number;
location: string;
}
I want to extend it to have 3 additional properties, one for each of the interfaces’ original properties.
So final outcome I want is:
interface Person {
name: string;
nameHidden: boolean;
age: number;
ageHidden: boolean;
location: string;
locationHidden: boolean;
}
I was looking into mapped types by TypeScript: https://www.typescriptlang.org/docs/handbook/2/mapped-types.html
But I am unable to figure out how I can achieve this behavior. It only shows examples of how to re-map the existing properties, but not add new ones on top of the existing ones.
>Solution :
You’ve said you don’t need it to be the same interface. If so, you can do this:
type WithFlags<T> = T & {
[Key in keyof T as Key extends string ? `${Key}Hidden` : never]: boolean;
};
type PersonWithFlags = WithFlags<Person>;
That creates a new type that is the passed-in type T plus a property for every property in it (at least the ones whose names extend string) with Hidden added to the name and the type boolean.
Titian Cernicova-Dragomir points out in a comment (thanks!) that we can avoid the conditional in that key mapping by using & string instead, which is a bit shorter:
type WithFlags<T> = T & {
[Key in keyof T & string as `${Key}Hidden`]: boolean;
// −−−−−−−−−−−−−−−−^^^^^^^^^
};
pilchard points out in a comment that the documentation has virtually this same example. They do the remapping like Titian, but in a different place:
type WithFlags<T> = T & {
[Key in keyof T as `${Key & string}Hidden`]: boolean;
// −−−−−−−−−−−−−−−−−−−−−−−−−−^^^^^^^^^
};