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

TypeScript类型层面:如何将对象类型转为名称/类型对列表?

对象类型与键值对元组的双向转换问题

正向转换:元组转对象(已实现)

把名称/类型对的元组列表转换为对象类型并不难,实现代码如下:

type PropertySpec<K extends string|number|symbol, V> = readonly [K, V];
type UnknownProp = PropertySpec<string|number|symbol, unknown>;
type PropSet = ReadonlyArray<UnknownProp>;
type CreateObject<Props extends PropSet, OutObj extends Record<string|number|symbol, unknown> = {}> =
Props extends []
    ? OutObj
    : Props extends readonly [infer Prop, ...infer Props]
        ? Prop extends readonly [infer K, infer V]
            ? Props extends PropSet
                ? K extends string|number|symbol
                    ? CreateObject<Props, OutObj & Record<K, V>>
                    : readonly [`Bad Key`, K]
                : "Bad props"
            : readonly ["Bad prop", Prop]
        : "Bad prop list";

type Q1 = CreateObject<readonly [readonly ["a", string], readonly ["b", number]]>;
const q1a: Q1 = {a: "foo", b: 3}; // OK!
const q1b: Q1 = {a: "foo"}; // 正确提示缺少b属性
const q1c: Q1 = {b: 3}; // 正确提示缺少a属性
const q1d: Q1 = {a: "foo", b: 3, c: null}; // 正确提示存在多余的c属性

反向转换的疑问

但反向转换(把对象类型转成名称/类型对的元组)却难住了我。这似乎得用到那种经典的、“不推荐使用”的联合类型转元组的变种方法——这类方法在相关讨论里出现过很多次。

我有两个问题:

  • 这是不是实现对象转元组的唯一途径?
  • 我觉得这种方法的弊端在这里可能不适用(毕竟元组的顺序对我来说无关紧要),这个想法对吗?

补充背景

我做这个是为了处理带对象映射的尾递归条件类型。元组可以逐个拆解处理,通过构建输出缓冲区实现尾递归(避开TypeScript的50层栈大小限制),但映射类型没法干净实现这种逻辑。把对象转成元组就能解决这个问题,之后再转回去就像上面的正向转换一样简单。


问题解答

核心结论

  1. 目前在TypeScript中,对象类型转键值对元组确实绕不开联合类型转元组的思路——因为对象的键值对本质上是一个联合类型,要把这个联合转成有序的元组结构,只能依赖联合类型的分发特性实现;
  2. 你的判断是对的:这类方法的核心弊端(比如元组顺序不可控、依赖TS内部实现细节)在你的场景里几乎没有影响。

具体实现方案

基于联合转元组的思路,这里给出适配需求的实现:

// 第一步:将对象类型转换为键值对的联合类型
type ObjectToPropUnion<T> = {
    [K in keyof T]: readonly [K, T[K]]
}[keyof T];

// 第二步:将联合类型转换为元组类型
type UnionToTuple<U, Acc extends unknown[] = []> = 
    U extends never 
        ? Acc 
        : UnionToTuple<Exclude<U, U extends infer X ? X : never>, [...Acc, U extends infer X ? X : never]>;

// 最终:对象类型转键值对元组的入口类型
type ObjectToPropTuple<T> = UnionToTuple<ObjectToPropUnion<T>>;

// 测试验证
type TestObj = {a: string, b: number};
type TestTuple = ObjectToPropTuple<TestObj>;
// TestTuple 会是 readonly ["a", string] 和 readonly ["b", number] 组成的元组,顺序可能随机,但不影响后续转对象

方案适配性说明

  • 尾递归友好:元组的拆解逻辑可以复用你之前CreateObject的尾递归写法,轻松避开TS的栈大小限制;
  • 顺序无关:不管元组内键值对的顺序如何,最终转成对象类型时,交叉类型会自动合并成正确的结构;
  • 稳定性:只要你的对象类型是常规的结构化类型(键为确定的字面量或已知类型),这个方案就能稳定工作,不会出现意外问题。

内容的提问来源于stack exchange,提问作者David Durschlag

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 06:55:01