Typescript接口,使用字符串常量作为属性

Typescript接口,使用字符串常量作为属性

问题描述:

我最近在尝试使用Typescript接口描述Notification格式(以及通常的格式)时遇到了以下设计问题.

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

上下文:通知在服务器(运行javascript)和客户端(使用其他语言)之间交换(作为JSON).

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

我尝试使用类似的接口

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";

因此,如果格式更改并且我们现在有了kText ="Message",则界面将自动变为

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

仍应保持有效-基本上,我想将Text用作属性的别名,同时强制将kText作为其名称.有点像(根本不起作用,但也许可以说明我想要的东西):

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?

您可以使用Record<TKey, TValue>类型来定义接口:

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 .

注意

在打字稿2.7及更高版本上,您还可以执行以下操作:

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