Typescript how to infer type from a constant property value

Viewed 1050

I want to get the type of a property from a constant previously defined.

const my_constant = {
    user: {
        props: {
            name: {
                type: 'string'
            }
        }
    },
    media: {
        props: {
            id: {
                type: 'number'
            }
        }
    }
} as const;

type Name = keyof typeof my_constant;

type Constructed<T extends Name> = {
    [K in keyof typeof my_constant[T]['props']]: typeof my_constant[T]['props'][K]['type']

                                     // ~~~ Type '"type"' cannot be used to index type ...
}

I don't understand why I cannot use "type" as index but I can use "props".

If typescript can infer that there is always "props" attribute why it cannot infer that there is always "type"?

Is there another way maybe to get the type?

What I want to achieve is something like this:


const user:Constructed<'user'> = {
    name: 'John'
}

const media:Constructed<'media'> = {
    id: 123
}

const user2:Constructed<'user'> = {
    name: 444
    // ~~~ Error
}

const media2:Constructed<'media'> = {
    id: 'something'
    // ~~~ Error
}

Here is the playground link with the exact error:

Playground Link

1 Answers

Typescript cannot use a string to index the constant. It needs the proper key. You can check if the object has the attribute type and also maybe use a Mapped type to get the real type instead of just "string".

const my_constant = {
    user: {
        props: {
            name: {
                type: 'string'
            }
        }
    },
    media: {
        props: {
            id: {
                type: 'number'
            }
        }
    }
} as const;

type Name = keyof typeof my_constant;

type InferType<T> = T extends {type: infer I} ? I : never;

interface Mapped {
    string: string;
    number: number;
}

type Constructed<T extends Name> = {
    [K in keyof typeof my_constant[T]['props']]: 
        InferType<typeof my_constant[T]['props'][K]> extends keyof Mapped ?
            Mapped[InferType<typeof my_constant[T]['props'][K]>] : never
}

Playground Link

Related