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

如何创建支持两种参数形式的基于对象键的递归函数类型?

解决方案:递归函数类型适配键与对象参数

要实现符合需求的递归函数类型,核心是解决非/${string}键对应的对象参数与键名的关联推断问题。以下是完整的实现方案:

类型定义

// 保留你定义的参数类型约束
type Argument<K> = K extends `/${string}` ? K : { [key in K]: string | number };

// 从参数中提取对应的键(区分键字符串和对象参数)
type ExtractKeyFromArg<Arg, T> = 
  Arg extends `/${string}` ? Arg : keyof Arg extends keyof T ? keyof Arg : never;

// 递归函数类型
type Foo<T extends object> = <Arg>(
  args: Arg extends Argument<infer K> ? K extends keyof T ? Arg : never : never
) => T[ExtractKeyFromArg<Arg, T>] extends object 
  ? Foo<T[ExtractKeyFromArg<Arg, T>]> 
  : T[ExtractKeyFromArg<Arg, T>];

测试验证

const values = {
    '/aaa': {
        '/lorem': {
            foo: 'hello world',
            '/boo': 12345,
        },
    },

    bbb: {
        '/ipsum': {
            '/dolor': 'lorem ipsum',
            amet: 567890,
        },
    },
};

const foo = {} as Foo<typeof values>;

// 正常工作,返回number类型
foo('/aaa')('/lorem')('/boo');
// 正常工作,返回string类型
foo('/aaa')('/lorem')({ foo: '...' });
// 报错:类型"/ipsum"的参数不能赋给类型"/lorem" | { foo: string | number; }的参数
foo('/aaa')('/ipsum');

// 正常工作,返回number类型
foo({ bbb: '...' })('/ipsum')({ amet: '...' });
// 正常工作,返回string类型
foo({ bbb: '...' })('/ipsum')('/dolor');
// 报错:类型"/lorem"的参数不能赋给类型"/ipsum"的参数
foo({ bbb: '...' })('/lorem');

关键逻辑说明

  1. ExtractKeyFromArg类型:

    • 如果参数是/${string}类型的键,直接返回该键;
    • 如果参数是对象,提取对象的键并验证是否属于当前层级的键集合,确保参数合法性。
  2. Foo递归类型:

    • 使用条件类型推断(infer K)从参数中提取对应的键K,并验证K是否属于当前对象T的键;
    • 根据T[K]的类型决定返回下一层递归函数Foo<T[K]>,还是直接返回值类型T[K]。

这个方案完美适配了你需求中的两种参数形式,同时保留了类型校验的严格性,不符合层级的参数会直接触发类型报错。

内容的提问来源于stack exchange,提问作者Stephan D.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 01:00:57