我有以下类型检查代码,以验证userInput是否为定义值之一
./src/**
上面的代码效果很好。但是,如果我也对其他属性实现相同的逻辑,则代码会大量堆积,因此我想到了将const variantColorValues = ['primary', 'black', 'green', 'red', 'white'] as const;
export type VariantColor = (typeof variantColorValues)[number];
function isOfTypeVariantColor(selectedColor: string): selectedColor is VariantColor {
return (variantColorValues as readonly string[]).includes(selectedColor);
}
isOfTypeVariantColor('red') //true
isOfTypeVariantColor('purple') //false
变成通用函数。
isOfTypeVariantColor
现在我的问题是我不确定如何将function isOfType(userInput: string, valueList: string[]): userInput is VariantColor {
return (valueList as readonly string[]).includes(userInput);
}
变成userInput is VariantColor
的参数
答案 0 :(得分:2)
您可以使用此:
// Make sure to make valueList readonly so you can use readonly arrays like variantColorValues
function isOfType<T, U extends T>(userInput: T, valueList: readonly U[]): userInput is U {
return (valueList as readonly T[]).includes(userInput);
}
const string: string = 'red';
if (isOfType(string, variantColorValues)) {
string; // VariantColor
}
const number: number = 0
if (isOfType(number, [1, 2, 3] as const)) {
number; // 1 | 2 | 3
}
T
是用户输入类型,您正在检查userInput
是否为U
类型。例如,将isOfType
与variantColorValues
一起使用时,T
将是string
,而U
将是VariantColor
。
编辑:根据Gerrit0的注释,您实际上不需要两个类型参数:
function isOfType2<T>(userInput: unknown, valueList: readonly T[]): userInput is T {
return (value as readonly unknown[]).includes(userInput);
}
但是,它不会对此进行处理:
if (isOfType(number, variantColorValues)) {}
// ~~~~~~~~~~~~~~~~~~
// Argument of type 'readonly ["primary", "black", "green", "red", "white"]' is not assignable to parameter of type 'readonly number[]'.
// Type 'string' is not assignable to type 'number'.
if (isOfType2(number, variantColorValues)) {
number; // never
}
答案 1 :(得分:0)
这是我的做法:
const variantColorValues = ['primary', 'black', 'green', 'red', 'white'] as const;
export type VariantColor = (typeof variantColorValues)[number];
const variantRoleValues = ["teacher", "student"] as const;
export type VariantRole = (typeof variantRoleValues)[number];
// This possibly isn't needed, it could be just strings, but I think it's good to explicitly narrow the types.
type PossibleVariants = VariantColor | VariantRole
function isOfType<T extends PossibleVariants>(value: string, arrayOfPossibleValues: readonly T[]) : value is T {
return (arrayOfPossibleValues as readonly string[]).includes(value);
}
使用演示:
const t1 = "teacher"; // In this scenario typescript knows this is the narrowest type "teacher"
if (isOfType(t1, variantColorValues)){ // No error, this is what we want right?
if (t1 === 'red') { //t1 is of type never, it's annoying that this doesn't give you an error.
//see: https://github.com/microsoft/TypeScript/issues/28982
}
}
const t2 = "teacher" as VariantRole; // For demo purposes, lets say we don't know if this is "teacher" or "student"
if (isOfType(t2, variantColorValues)){ // No error, this is what we want right?
if (t2 === 'red') { // t2 is of type never
}
const t3 = "teacher" as string; // For demo purposes, we don't know what kind of string this is.
if (isOfType(t3, variantColorValues)){ // No error, this is what we want right?
if (t3 === 'red') { // t3 is of type "red" |"black" ...
if (t3 === 'student') { // expected error: This condition will always return 'false' since the types '"primary" | "black" | "green" | "red" | "white"' and '"student"' have no overlap.(2367)
}
}