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

TypeScript泛型函数:如何仅指定N类型参数,让S自动推断

背景情况
// 用于验证的类型——不太重要。
type Validate<N, S> = [S] extends [N] ? N : never;

// 注意,若使用下面这行代码,在调用validateName()时N会出现循环约束。
// type Validate<N, S> = S extends N ? N : never;

// 用于验证的函数——其在JS中的运行逻辑(甚至返回值)不重要。
// 但重要的是,它必须使用上述带两个参数的Validate类型。
function validateName<N extends string, S extends Validate<N, S>>(input: S) {}
问题

如何为上述validateName(或Validate)仅指定N类型参数,而让S由实际传入的参数自动推断?

// 测试用例。
type ValidNames = "bold" | "italic";

// 期望用法:
// 但会报错“应为2个类型参数,实际传入1个”
validateName<ValidNames>("bold");   // 合法。
validateName<ValidNames>("bald");   // 报错。

// 无法通过以下方式解决,会报错:“类型参数默认值只能引用已声明的前置类型参数”
function validateName<N extends string, S extends Validate<N, S> = Validate<N, S>>(input: S) {}
可行的解决方案
  • 方案1:将输入值存入变量,使用其类型
const input1 = "bold";
const input2 = "bald";
validateName<ValidNames, typeof input1>(input1);  // 合法。
validateName<ValidNames, typeof input2>(input2);  // 报错。
  • 方案2:为函数添加额外参数
function validateNameWith<N extends string, S extends Validate<N, S>>(_valid: N, input: S) {}
validateNameWith("" as ValidNames, "bold");  // 合法。
validateNameWith("" as ValidNames, "bald");  // 报错。
  • 方案3:使用闭包——将函数嵌套在另一个函数中
// 先创建一个用于生成验证器的函数,传入N类型。
function createValidator<N extends string>() {
    // 返回实际的验证器函数。
    return function validateName<S extends Validate<N, S>>(input: S) {}
}
const validateMyName = createValidator<ValidNames>();
validateMyName("bold");  // 合法。
validateMyName("bald");  // 报错。

编辑说明

修改了上述函数,移除了易混淆的:N[]返回值部分。

补充信息/上下文

实际正在构建一个可用于HTML类名等场景的字符串验证器。除使用方式较为繁琐(见上述3种方案)外,其余功能均正常。

// 字符串分割类型实现
type Split<S extends string, D extends string> =
    string extends S ? string[] :
    S extends '' ? [] :
    S extends `${infer T}${D}${infer U}` ? [T, ...Split<U, D>] :
    [S];

// 用于验证类名的类型。
type ClassNameValidator<N extends string, S extends string, R = string> =
    Split<S, " "> extends N[] ? R : never;

// 验证类名的函数。
function validateClass<N extends string, S extends ClassNameValidator<N, S>>(input: S) {}

const test3 = "bold italic";
const test4 = "bald";
validateClass<ValidNames, typeof test3>(test3);  // 合法。
validateClass<ValidNames, typeof test4>(test4);  // 报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 12:45:43