chokola
chokola

Reputation: 13

Typescript interface, using string constants for properties

I recently encountered the following design-issue when trying to describe a Notification-format (and formats in general) with a Typescript interface.

Context: Notifications are exchanged (as JSONs) between the server (running javascript) and a client (that uses a different language).

I have tried to use an Interface like

interface Notification
{
    Text?: string,
    Title?: string,
    Priority?: number
}

But in my scenario I want the properties to be tied to string constants (which are exported from client sourcecode)

const kText = "Text";
const kTitle = "Title";
const kPriority = "Priority";

So if the format changes and we now have kText = "Message", the interface would automatically become

interface Notification
{
    Message?: string,
    Title?: string,
    Priority?: number
}

and ideally all instances of things like

notification.Text

should still stay valid - basically I'd like to have Text as an alias for the property, that is at the same time enforced to actually have kText as its name. Sort of like (not working at all, but maybe illustrates what I want):

type TextType = "Text"; // or "Message" if format changes later
type TitleType = "Title";
type PriorityType = "Priority";
interface Notification
{
    [Text : TextType]?: string,
    [Title : TitleType]?: string,
    [Priority : PriorityType]?: number
}

Is there any way to achieve something like this?

If not, what might be other good ways to implement this?

Upvotes: 0

Views: 6247

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249646

You can use the Record<TKey, TValue> type to define the interface:

type TextType = "Text"; // or "Message" if format changes later
type TitleType = "Title";
type PriorityType = "Priority";
type Notification = Partial<Record<typeof TextType | typeof TitleType, string>
        & Record<typeof PriorityType, number>>;

let notif: Notification;

let t = notif[TextType] // Will be string
let t2 = notif.Text // Also works 

The problem is there is no compiler way to enforce that access happens using the string constant, you could still access with .

Note

On typescript 2.7 and newer you can also do:

const TextType = "Text"; // or "Message" etc
const TitleType = "Title";
const PriorityType = "Priority";

interface Notification {
    [TextType]?: string
    [TitleType]?: string
    [PriorityType]?: number
}

But the same problem still applies of access

Upvotes: 3

Related Questions