TypeScript中如何实现同结构嵌套对象的类型推断?
TypeScript 嵌套常量对象结构一致性校验与类型推断实现
问题背景
我希望实现动态对象的类型推断,检索站点内相关内容后未找到完全匹配的解决方案,若问题重复在此致歉。
我的核心需求是定义多个结构一致的全局常量对象,支持切换当前激活的常量对象,所有常量对象内部属性名保持统一,仅属性值存在差异。示例结构如下:
const example = { constant1: { value1: 'value1', value2: 'value2', value3: 'value3', }, constant2: { value1: 'other value1', value2: 'other value2', value3: 'other value3', }, constant3: { value1: 'another value1', value2: 'another value2', value3: 'another value3', }, };
上述example对象可包含任意顶层属性,但所有顶层属性对应的子对象结构必须完全一致:
- 若仅修改某一个子对象内的属性定义需要抛出类型错误
- 若同步修改所有子对象的对应属性则为合法操作
已尝试的方案
方案1:索引签名泛型
最初实现如下,虽可运行但效果不符合预期:
interface TypeTest<T> { [key: string]: T; } const CreateTest = <T>(obj: TypeTest<T>) => obj; const test = CreateTest({ some: { other: 'test', }, thing: { other: 'testing', }, }); type constants = keyof typeof test;
由于接口无法自动获得精准类型推断,采用创建器函数接收对象并返回带类型标注的对象,但该方案存在两个问题:
- TypeScript会将所有内部对象推断为联合类型
- 外层对象的键类型无法正确获取,得到的
type constants = string | number
方案2:映射类型双泛型
为解决外层键推断问题尝试了第二种方案:
type TypeTest<D, T> = { [key in keyof D]: T; }; const CreateTest = <D, T>(obj: TypeTest<D, T>) => obj; const test = CreateTest({ some: { other: 'test', }, thing: { other: 'testing', }, }); type constants = keyof typeof test;
该方案可正确获取外层对象的键类型(type constants = "some" | "thing"),但完全丢失了内部对象的类型推断,内部对象类型为unknown,即使显式使用[key2 in keyof T]: string定义内部对象结构,仍无法得到正确的类型。
方案3:额外类型元组传参
找到的折中方案可实现需求,但开发体验较差:
interface TypeTest<T extends readonly string[], U extends readonly string[]> { outer: T; inner: U; values: { [Property1 in T[number]]: { [Property2 in U[number]]: string; }; }; } const CreateTest = < T extends readonly string[], U extends readonly string[], > (constants: TypeTest<T, U>) => constants.values; const test = CreateTest({ outer: [ 'some', 'thing' ] as const, inner: [ 'other' ] as const, values: { some: { other: 'test', }, thing: { other: 'testing', }, }, }); type constants = keyof typeof test; type values = keyof typeof test[constants];
该方案需要额外传入两个仅用于提取类型、后续会被丢弃的数组,且两个数组必须添加as const断言,否则只能得到string[]类型。
待解决问题
是否存在方案可直接向CreateTest()函数传入目标对象,即可得到正确的类型推导,获得type constants = "some" | "thing"、type values = "other"的正确类型?
补充疑问
- 当前业务场景仅需要2层深度的嵌套类型推断,同时好奇是否可支持更深层级的类型推断?
- 是否可支持不同嵌套深度的场景?例如某个子对象为3层嵌套,另一个子对象为5层嵌套。该场景暂无业务需求,仅出于技术好奇提问。
内容的提问来源于stack exchange,提问作者Gabriel Braz
相关产品推荐
相关产品推荐

