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

TypeScript递归模板字面量类型:保留自动补全且接受实际参数值

问题描述

MCVE

(尝试在函数f的参数上使用自动补全,查看效果)

我尝试创建一个递归模板字面量类型,用于校验传入函数的字符串是否符合我的API的REST规范。

目前已实现简单路由(如version和health/check)的校验。我希望支持带参数的路由:

在提供的代码中,路由users/[PARAM]可正常被接受并出现在参数自动补全中,但users/12不被接受。

我认为问题出在Dive类型的末尾:

`${k & DiveKey}/${typeof param | string}`

若使用${k & DiveKey}/${typeof param},能得到正确的自动补全但无法接受实际参数值;若使用${k & DiveKey}/${string},可接受实际参数值,但users/[PARAM]不会出现在自动补全中,导致开发者无法看到该路径提示。

我的问题是:是否有办法既保留users/[PARAM]的自动补全,又能让users/12作为参数被接受?

提前感谢您的解答。

代码

export type RestEndpoint = Dive;

const param = '[PARAM]' as const;
type DiveKey = string | number;

type Dive<T = typeof API_REST_STRUCTURE> = keyof {
    [k in keyof T as T[k] extends Record<any, any>
        ? `${k & DiveKey}/${Dive<T[k]> & DiveKey}`
        : T[k] extends typeof param
        ? `${k & DiveKey}/${typeof param | string}`
        : k]: any;
};

const API_REST_STRUCTURE = {
  version: false,
  health: { check: false },
    users: param,
};

function f(p: RestEndpoint) {}

f('version');
f('health/check');
f('users/[PARAM]');
f('users/12');

编辑1

  • 使用${string}时的效果:自动补全无users/[PARAM]提示
  • 使用typeof param时的效果:users/12报错不被接受

解决方案

可以通过拆分带参数路由的类型分支,同时保留明确补全提示和任意字符串匹配能力,代码修改如下:

export type RestEndpoint = Dive;

const param = '[PARAM]' as const;
type DiveKey = string | number;

// 单独定义带参数的路由分支:同时包含补全占位符和任意参数值
type ParamRoute<K extends DiveKey> = `${K}/${typeof param}` | `${K}/${string}`;

type Dive<T = typeof API_REST_STRUCTURE> = keyof {
    [k in keyof T as T[k] extends Record<any, any>
        ? `${k & DiveKey}/${Dive<T[k]> & DiveKey}`
        : T[k] extends typeof param
        ? ParamRoute<k & DiveKey> // 替换原有分支逻辑
        : k]: any;
};

const API_REST_STRUCTURE = {
  version: false,
  health: { check: false },
    users: param,
};

function f(p: RestEndpoint) {}

f('version'); // ✅ 正常
f('health/check'); // ✅ 正常
f('users/[PARAM]'); // ✅ 自动补全可见,类型校验通过
f('users/12'); // ✅ 类型校验通过
f('users/abc123'); // ✅ 类型校验通过

原理说明

  • ParamRoute类型明确声明了两种情况:users/[PARAM]用于提供自动补全提示,users/${string}用于匹配任意实际参数值。
  • 让Dive类型在处理参数路由时复用该类型,TypeScript会同时保留明确的字符串字面量(补全提示)和任意字符串的匹配规则,完美满足需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 04:32:45