【问题标题】:How to restrict keys of a TS object while keeping all type annotations如何在保留所有类型注释的同时限制 TS 对象的键
【发布时间】:2021-05-01 19:02:55
【问题描述】:

我有一个像这样的常量对象:


const shortcuts = {
    save: {
        label: 'ctrl+s',
        action: (documentId: string) => saveDocument(documentId) 
    },
    open: {
        label: 'ctrl+o',
        action: (name: string, type: string) => loadDocument(documentName, extension),
        thisShouldError: 'thisShouldError' // not allowed property
    },
    // etc...
} as const
   

我想确保所有快捷方式都遵循如下所示的所需形状,并且没有添加多余的属性。

interface DesiredShape {
    label: string,
    action: (...args: any[]) => void
}

特别是,我希望shortcuts 的上述定义出错,因为不允许使用open.thisShouldError。同时,我不想丢失任何类型信息,即当我做shortcuts.save.action时,我想得到函数的实际类型签名为(documentId: string) => saveDocument(documentId),而不仅仅是通用的(...args: any[]) => void

有可能实现吗?

到目前为止我所做的尝试:

我可以使用object literals limitations 来执行此操作,但是我会丢失类型信息。

我还尝试确保键的区别如下never,但似乎 TS 只将无处不在的键带入ActualKeys

type ActualKeys = keyof typeof shortcuts['save' | 'open']
type PermittedKeys = keyof DesiredShape
// does not work because ActualKeys does not include `thisShouldError`
assertNever(null as unknown as Exclude<ActualKeys,PermittedKeys>)

Playground Link

【问题讨论】:

    标签: typescript types


    【解决方案1】:

    我不确定为什么你想这样做,但一种方法是:

    type allKeys<T> = T extends {} ? keyof T: never;
    type ActualKeys = allKeys<typeof shortcuts[keyof typeof shortcuts]>
    type PermittedKeys = keyof DesiredShape
    assertNever(null as Exclude<ActualKeys,PermittedKeys>)
    

    【讨论】:

    • 太好了,谢谢!顺便说一句,你提到这是“这样做的一种方式”,你介意分享你可能有的其他想法吗?我很惊讶阻止用户向界面添加多余的属性一点也不简单。这似乎是一件很基本的事情。
    • 我认为人们主要关心他们需要的属性的正确形状,而不是缺少他们不需要的属性(如果你必须处理一个特别的问题,我只能想象这是一个问题挑剔的 API)。而不是assetNever,我会做let test : PermittedKeys = {} as ActualKeys; 之类的事情,但这并没有太大区别,而且我认为没有办法制造实际的shortcuts错误,因为您需要推断它的类型。跨度>
    猜你喜欢
    • 1970-01-01
    • 2020-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-16
    • 2021-04-13
    • 1970-01-01
    相关资源
    最近更新 更多