Reputation: 13
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
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