kmoney12
kmoney12

Reputation: 4480

Typescript Interface for value = key

New typescript user here.

We often declare our redux actions and other static constants like so (js):

export const notificationTypes = {
    WELCOME: "WELCOME",
    LOGGED_IN: 'LOGGED_IN',
    NEW_EMAIL: 'NEW_EMAIL',
};

I am trying to do the same with typescript:

export const notificationTypes = {
    WELCOME: "WELCOME",
    LOGGED_IN: 'LOGGED_IN',
    NEW_EMAIL: 'NEW_EMAIL',
};
export type NotificationType = keyof typeof notificationTypes;

And here is an attempt to use the new type:

import {notificationTypes, NotificationType} from "./notificationTypes"
interface Notification {
   type:NotificationType
}
//no errors
const firstNotificationTest:Notification={
    type:"WELCOME"
}

//error type 'string' is not assignable to type "WELCOME" | "LOGGED_IN" | "NEW_EMAIL"
const secondtNotificationTest:Notification={
    type:notificationTypes.WELCOME
}

As you can see, I can not use notificationTypes.WELCOME, but rather must use "WELCOME". This somewhat defeats the whole purpose of setting up these constants.

Is it possible to interface Notification to allow any notificationTypes value? Or interface notificationTypes itself so it knows that value = key? Or am I just using typescript completely wrong here.

Upvotes: 1

Views: 70

Answers (1)

ford04
ford04

Reputation: 74490

You can add a const assertion to narrow down the properties of notificationTypes to their string literal types.

export const notificationTypes = {
    WELCOME: "WELCOME",
    LOGGED_IN: 'LOGGED_IN',
    NEW_EMAIL: 'NEW_EMAIL',
} as const

This also has the benefit, that the members are marked as readonly, so something like this cannot happen with normal type usage:

notificationTypes.LOGGED_IN = "duuuhh"

, so you effectively can use notificationTypes as replacement for a conventional enum.

Playground

Upvotes: 3

Related Questions