Reputation: 5825
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.
Upvotes: 0
Views: 79
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