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

