【问题标题】:Typescript: Only type object values and let typescript type the keys打字稿:只键入对象值并​​让打字稿键入键
【发布时间】:2021-09-27 15:05:04
【问题描述】:

我有一个类似的对象

interface PageDef = {url: string}
const page1Def: PageDef = {url: "page1"}
const page2Def: PageDef = {url: "page2"}
const pages = {page1: page1Def, page2: page2Def}

现在我希望页面类型如下:

{{page1: PageDef, page2: PageDef}}

问题是该页面可以有任何名称,例如我可以有

const pages = {home: page1Def, about: page2Def}

我不想使用以下任何一种,因为我会丢失类型中的键

const pages: {[pageName: string]: PageDef} = {page1: page1Def, page2: page2Def}
const pages: Record<string, PageDef> = {page1: page1Def, page2: page2Def}

我无法执行以下操作来获得联合类型的页面名称

keyof typeof pages
// would be string with above definition

不输入会使 Typescript 动态输入 pages,这将部分解决我的问题,但会输入检查值。

所以我的问题是,是否可以仅手动键入对象的值?还是有其他解决办法?

【问题讨论】:

  • 这听起来像是一个设计问题。你真的需要这个来实现你的真正目标吗?
  • 我有这两个变量,一个定义页面的对象和一个定义页面显示顺序的数组,我需要后者有有效的页面键,为此我需要输入它
  • 键入它不是验证它的唯一方法。

标签: typescript


【解决方案1】:

为什么首先明确定义“页面”的类型?在这种情况下它似乎没有用。

定义类型的原因是您可以在多个文件、函数或其他任何地方重复使用它。但是没有办法做到这一点,同时保持“页面”的键在所有用法中静态知道,它必须string。或者,您可以通过为其定义联合类型来使其静态已知(如在另一个答案中提到的,type pageNames = 'page1' | 'page2' | 'home' | 'about')。

例如,您明确键入“页面”的用例是什么?如果您想将该值传递给函数,则无论如何都只需使用泛型,“页面”的确切键将无关紧要:

function doSomething<MyType extends {[key: string]: PageDef}>(pageObj: MyType) {}

即便如此,只有在 doSomething()return 以某种方式通过泛型推断使用而有用地键入,或者您在函数上有其他通过泛型有用地通知的参数时,它才会有用.否则,函数体可能实际上不关心pageObj 的键的类型。

明确知道“页面”的键是什么可能有用的唯一地方将是在它定义的相同范围内。在这种情况下,你可以让 TypeScript 推断它的键值,这将是实际的键而不是string

interface PageDef = {url: string}
const page1Def: PageDef = {url: "page1"}
const page2Def: PageDef = {url: "page2"}
const pages = {page1: page1Def, page2: page2Def}

type PagesKeys = keyof typeof pages; // "page1" | "page2"

但又一次,你为什么要打扰?您的要求对于您实际上需要它的用途有点模糊。它可能看起来很有用,但我怀疑它实际上是否有用。或者,如果是,它似乎是一种设计反模式,您需要重新考虑设计中的其他一些高级事物。

【讨论】:

    【解决方案2】:

    你的意思是这样的吗?

    interface PageDef {url: string}
    const page1Def: PageDef = {url: "page1"}
    const page2Def: PageDef = {url: "page2"}
    
    type pageNames = 'page1' | 'page2' | 'home' | 'about'
    
    const pages: Partial<Record<pageNames, PageDef>> = {page1: page1Def, page2: page2Def}
    

    【讨论】:

    • 不,我的意思是使用不可预测的键但可预测的值
    • 你可以在Partial&lt;Record&lt;pageNames, PageDef&gt;&gt;中保留类似的东西而不是PageDef
    猜你喜欢
    • 2021-02-02
    • 2021-12-17
    • 1970-01-01
    • 2021-03-04
    • 2020-05-21
    • 2021-05-31
    • 2021-06-28
    • 1970-01-01
    • 2022-01-12
    相关资源
    最近更新 更多