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
相关产品推荐
相关产品推荐

