You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript仅限定对象值类型并保留键字面量类型的实现方法

解决方案

方案1:使用 TypeScript 4.9+ 内置的 satisfies 操作符(首选)

satisfies 设计的核心作用就是在不覆盖变量原始推导类型的前提下,校验变量是否符合指定类型约束,刚好完全匹配你的需求。

// 注意原写法中interface定义不需要等号,已修正
interface PageDef { url: string }
const page1Def: PageDef = {url: "page1"}
const page2Def: PageDef = {url: "page2"}

// 仅校验所有值符合 PageDef 类型,完全保留原始键的字面量类型
const pages = {page1: page1Def, page2: page2Def} satisfies Record<string, PageDef>

// 此时 keyof typeof pages 得到的是字面量联合类型 'page1' | 'page2',不会退化为string
type PageKeys = keyof typeof pages

// 如果值不符合PageDef类型会直接抛出编译错误,比如:
// const badPages = { page1: { wrongKey: 123 } } satisfies Record<string, PageDef> // 报错

你也可以灵活替换键的约束,比如如果要求键是特定格式的字符串,修改satisfies后面的Record第一个泛型参数即可。

方案2:泛型工具函数(兼容 TypeScript 4.9 以下版本)

如果你使用的TS版本低于4.9没有satisfies支持,可以通过一个简单的泛型工具函数实现同样的效果:

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

// 定义泛型工具函数,约束值为PageDef类型,自动推导键的精确类型
const definePages = <T extends Record<string, PageDef>>(pages: T) => pages

// 调用函数生成pages对象
const pages = definePages({ home: page1Def, about: page2Def })

// keyof typeof pages 得到 'home' | 'about' 联合类型
type PageKeys = keyof typeof pages

两种方案的核心逻辑一致:都没有给变量直接标注宽泛的Record<string, PageDef>类型,避免了类型被拓宽,同时通过额外的校验逻辑保证所有值都符合PageDef的类型要求。

内容的提问来源于stack exchange,提问作者Jonathan de M.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 04:18:02