2

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>[].

1 Answer 1

5

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>[]
Sign up to request clarification or add additional context in comments.

1 Comment

I've tried that in my code and it wasn't working but for completely different reason. After fixing the other mistake it works great.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.