47ndr
47ndr

Reputation: 633

Typescript how to infer type from a constant property value

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

Upvotes: 3

Views: 3361

Answers (1)

nbl7
nbl7

Reputation: 551

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

Upvotes: 1

Related Questions