David Gomes
David Gomes

Reputation: 5825

Use an object as a map's key in the value

I'm trying to create an object as a map type where the value depends on the key:

export const NOTIFICATIONS: { [k: string]: { name: typeof k } } = {
    "upgrade": {
        name: "upgradexxx",
    },
};

(this should error since upgradexxx is not equal to upgrade)

I want to make it so that the keys of this object have to match the name property on each value. I also tried {[k in string]: { name: k} } but that didn't work either. I want to avoid having other arrays/types because I don't want to have to duplicate things. The NOTIFICATIONS object should be the source of truth for all the valid keys.

http://www.typescriptlang.org/play/#src=export%20const%20NOTIFICATIONS%3A%20%7B%20%5Bk%3A%20string%5D%3A%20%7B%20name%3A%20typeof%20k%20%7D%20%7D%20%3D%20%7B%0A%20%20%20%20%22upgrade%22%3A%20%7B%0A%20%20%20%20%20%20%20%20name%3A%20%22upgradexxx%22%2C%0A%20%20%20%20%7D%2C%0A%7D%3B%0A

Upvotes: 0

Views: 79

Answers (1)

jcalz
jcalz

Reputation: 328292

The way to represent such a constraint is with a mapped type over a set of literal keys, but that requires that the type itself be generic and not concrete. To use a generic type, the easiest solution is to have a helper function that infers the generic type for you. Like this:

// enforce constraint 
const asNotifications = <T extends {
    [K in keyof T]: { name: K, [k: string]: unknown }
}>(t: T) => t;

export const BADNOTIFICATIONS = asNotifications({
    upgrade: {
        name: "upgradexxx" // error!
        // Type '"upgradexxx"' is not assignable to type '"upgrade"'.
    }
})

export const NOTIFICATIONS = asNotifications({
    upgrade: {
        name: "upgrade",
    },
    downgrade: {
        name: "downgrade",
        extraPropsAreOkay: true
    },
    lemonade: {
        name: "lemonade",
        brand: "Minute Maid"        
    }
});

NOTIFICATIONS.upgrade.name // "upgrade"
NOTIFICATIONS.downgrade.extraPropsAreOkay // boolean

Hope that helps; good luck!

Upvotes: 2

Related Questions