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

如何基于对象数组属性值声明类型?含嵌套可选场景

如何从带可选嵌套的数组中推断所有层级的key联合类型?

在普通非嵌套、无可选属性的场景下,我们可以通过as const断言保留数组元素的字面量类型,再提取key的联合类型:

const data = [
    { key: 'name', desc: 'desc...' },
    { key: 'password', desc: 'desc' },
    { key: 'balabala', desc: 'bb.' }
] as const;

type DataKey = typeof data[number]['key']; // "name" | "password" | "balabala"

const fn = (key: DataKey) => {
    switch (key) {
        case 'name':
            break;
        // 其他case会自动提示可选的key值
    }
};

但遇到带可选嵌套属性的结构时,直接用宽泛类型注解会丢失字面量信息,导致无法提取所有层级的key。下面是解决方法:

步骤1:保留字面量类型

首先不要给数组指定Deep[]这类宽泛类型,改用as const断言让TypeScript保留所有具体的字面量细节,包括嵌套结构和可选属性的实际值:

const dataDeep = [
    { key: 'name', desc: 'desc...' },
    { key: 'password', desc: 'desc' },
    { key: 'balabala', desc: 'bb.', child: [{ key: 'deep', desc: 'deep' }] }
] as const;

步骤2:编写递归类型工具

通过递归类型遍历所有层级的结构,提取每个层级的key并合并成联合类型:

// 递归提取所有层级的key类型
type ExtractAllKeys<T> = 
    // 如果是数组,先推断数组元素类型
    T extends readonly (infer Item)[] 
        ? Item extends { key: infer Key; child?: infer Children }
            // 提取当前层级的key,再递归处理子级
            ? Key | ExtractAllKeys<Children>
            : never
        : never;

// 得到所有层级的key联合类型:"name" | "password" | "balabala" | "deep"
type AllDeepKeys = ExtractAllKeys<typeof dataDeep>;

验证效果

使用这个联合类型作为函数参数类型,TypeScript会自动提示所有合法的key值,且不允许传入未定义的key:

const deepFn = (key: AllDeepKeys) => {
    switch (key) {
        case 'name':
            break;
        case 'password':
            break;
        case 'balabala':
            break;
        case 'deep':
            break;
        // 传入其他值会触发类型错误
    }
};

关键说明

  • 为什么原来的写法失效?因为给dataDeep指定Deep[]类型后,TypeScript会把具体的key字面量(如'name')拓宽为string,丢失了精确的类型信息。
  • 递归类型会自动处理可选的child属性:如果元素没有child,Children会是undefined,此时ExtractAllKeys<undefined>返回never,不会影响最终的联合类型。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 22:42:46