Reputation: 2329
I am working with a normalized data inside redux store (all complex types are just ids referring to real object) and I would like to create a denormalized types using typescript's conditional mapped types feature.
I keep the actual type of the object the id is referring to as it's generic argument and from this I was able to create denormalized type correctly if only non array id attributes are used.
type Id<T extends HandlerBase<any>> = string & { __type: T };
class HandlerBase<T extends HandlerBase<T>> {};
class HandlerA extends HandlerBase<HandlerA> {
str: string;
b: Id<HandlerB>;
bArr: Id<HandlerB>[];
};
class HandlerB extends HandlerBase<HandlerA> {};
type DenormalizedHandler<T> = {
[P in keyof T]: T[P] extends Id<infer U> ? DenormalizedHandler<U> : T[P];
}
const handler: DenormalizedHandler<HandlerA> = undefined;
handler.str; // Is string
handler.b; // Is DenormalizedHandler<HandlerB>
handler.bArr; // Should be DenormalizedHandler<HandlerB>[]
Now I need to figure out how to possibly add second condition to DenormalizedHandler
so it can correctly map Id<U>
to DenormalizedHandler<U>
and Id<U>[]
to DenormalizedHandler<U>[]
.
Upvotes: 2
Views: 9315
Reputation: 249466
You just need to add another condition, conditional types can nest just like ternary expressions could:
type Id<T extends HandlerBase<any>> = string & { __type: T };
class HandlerBase<T extends HandlerBase<T>> {};
class HandlerA extends HandlerBase<HandlerA> {
str: string;
b: Id<HandlerB>;
bArr: Id<HandlerB>[];
};
class HandlerB extends HandlerBase<HandlerA> {};
type DenormalizedHandler<T> = {
[P in keyof T]:
T[P] extends Id<infer U> ? DenormalizedHandler<U> :
T[P] extends Array<Id<infer U>> ? Array<DenormalizedHandler<U>> :
T[P];
}
const handler: DenormalizedHandler<HandlerA> = undefined;
handler.str; // Is string
handler.b; // Is DenormalizedHandler<HandlerB>
handler.bArr; // Is DenormalizedHandler<HandlerB>[]
Upvotes: 5