【发布时间】:2022-07-29 20:11:13
【问题描述】:
背景情况:
// Type to do the validation - not so important.
type Validate<N, S> = [S] extends [N] ? N : never;
// Note that with below line, N will have a circular constraint when using from validateName().
// type Validate<N, S> = S extends N ? N : never;
// The function to validate - how it runs as JS (or even what it returns) is not important.
// .. However, it is important that it must use a Validate type with two arguments like above.
function validateName<N extends string, S extends Validate<N, S>>(input: S) {}
问题:
如何只补充N而不是S到上面的validateName(或Validate)?我们希望 S 保持由实际参数推断。
// Test.
type ValidNames = "bold" | "italic";
// Desired usage:
// .. But we can't do this due to "Expected 2 type arguments, but got 1."
validateName<ValidNames>("bold"); // Ok.
validateName<ValidNames>("bald"); // Error.
// Cannot solve like below due to: "Type parameter defaults can only reference previously declared type parameters."
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); // Ok.
validateName<ValidNames, typeof input2>(input2); // Error.
解决方法 #2:使函数需要额外的参数。
function validateNameWith<N extends string, S extends Validate<N, S>>(_valid: N, input: S) {}
validateNameWith("" as ValidNames, "bold"); // Ok.
validateNameWith("" as ValidNames, "bald"); // Error.
解决方法 #3:使用闭包 - 将函数包装在另一个函数中。
// First a function to create a validator and put N into it.
function createValidator<N extends string>() {
// Return the actual validator.
return function validateName<S extends Validate<N, S>>(input: S) {}
}
const validateMyName = createValidator<ValidNames>();
validateMyName("bold"); // Ok.
validateMyName("bald"); // Error.
编辑:修改了上面的函数,去掉了令人困惑的:N[]返回部分。
更多信息/背景:
我实际上是在尝试构建一个可以使用的字符串验证器,例如。用于 html 类名。其他一切都有效,除了用法很笨拙(请参阅上面的 3 个解决方法)。
// Thanks to: https://github.com/microsoft/TypeScript/pull/40336
export 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 to validate a class name.
type ClassNameValidator<N extends string, S extends string, R = string> =
Split<S, " "> extends N[] ? R : never;
// Function to validate class.
function validateClass<N extends string, S extends ClassNameValidator<N, S>>(input: S) {}
const test3 = "bold italic";
const test4 = "bald";
validateClass<ValidNames, typeof test3>(test3); // Ok.
validateClass<ValidNames, typeof test4>(test4); // Error.
【问题讨论】:
标签: typescript