Typescript 4.1 introduced template-literal-types which now allow us to map strings. Take the following interfaces as example:
interface User {
id: number;
userName: string;
age: number;
}
interface Post {
id: number;
author: User;
subject: string;
body: string;
}
interface Queue {
id: number;
size: number;
posts: Post[];
}
what I now want to do is mapping the Queue
to a type with the property-path as key and the value as type like so:
// I want to do this:
type Properties = MapProperties<Queue>;
// ... to get the same result as this:
type Properties = {
'id': number; // Queue > id
'size': number; // Queue > size
'posts.id': number; // Queue > Post > id
'posts.author.id': number; // Queue > Post > User > id
'posts.author.userName': string; // Queue > Post > User > userName
'posts.author.age': number; // Queue > Post > User > age
'posts.subject': string; // Queue > Post > subject
'posts.body': string; // Queue > Post > body
};
What I've managed so far is extracting the whole set of keys. Just mapping them to the type seems impossible to me:
// Removing the `keyof` won't work...
type MapProperties<T> = keyof {
[
K in keyof T as T[K] extends object ? `${K & string}.${MapProperties<T[K]> & string}` :
T extends Array<infer U> ? MapProperties<U> : K
]?: T[K]
}
Is there a way to achieve what I'm trying to do? I also want to make it recursive so that it's not limited to a certain depth (excluding circular references).