首页 > 解决方案 > 打字稿:只键入对象值并​​让打字稿键入键

问题描述

我有一个像

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

解决方案


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

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

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

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

即使这样,它也只有在返回fromdoSomething()是通过泛型从其推断使用中以某种方式有用地键入,或者您在函数上有其他通过泛型有用地通知的参数时才有用。否则,函数体可能实际上并不关心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"

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


推荐阅读