Typescript:仅为对象值类型化,让typescript类型化键

4

我有一个像这样的对象

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 ,这将部分解决我的问题但也会检查值的类型。

所以我的问题是,是否有可能仅手动类型化对象的值?或者是否有其他解决方案?


2
这听起来像是设计上的问题。你真的需要这个来达到你的真正目标吗? - Ricky Mo
我有这两个变量,一个定义页面的对象和一个定义要显示页面顺序的数组,我需要后者具有有效的页面键,并且为此我需要输入它。 - Jonathan de M.
类型并不是验证数据的唯一方式。 - Ricky Mo
2个回答

1
为什么要在此处明确定义“页面”类型?在这种情况下似乎没有用处。
定义类型的原因是您可以在多个文件、函数或其他情况下重复使用它。但是,在保持“页面”的键在所有用法中静态知道的同时,没有办法做到这一点,它必须是字符串。或者,您可以通过为其定义联合类型(如在其他答案中提到的 type pageNames = 'page1' | 'page2' | 'home' | 'about')使其静态知道。
比如,您明确地为“页面”进行类型设置的用例是什么?如果您想将该值传递给函数,那么您将只使用通用函数,"页面"的确切键名将不相关:
function doSomething<MyType extends {[key: string]: PageDef}>(pageObj: MyType) {}

即使如此,只有当从泛型的推断使用中得到的返回以某种有用的方式进行类型化,或者函数上还有其他有用地通过泛型进行了通知的参数时,它才有用。否则,函数体可能并不实际上关心pageObj的键的类型。
唯一一个明确知道“pages”键是什么的地方是在定义它的同一作用域中。在这种情况下,您可以让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"

但是,你为什么要费心呢?你对需要的东西有点模糊。它可能看起来很有用,但我怀疑它实际上并不是。或者如果它确实有用,那么它似乎是一种设计反模式,你需要重新考虑你设计中的其他高级问题。


0
你是指像这样的东西吗?
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}

不,我的意思是具有不可预测的键但可预测的值。 - Jonathan de M.
Partial<Record<pageNames, PageDef>> 中,您可以保留类似于 PageDef 的内容。 - tsamridh86

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接