如何将类型作为函数参数传递

时间:2020-10-01 00:58:35

标签: javascript typescript

我有以下类型检查代码,以验证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的参数

2 个答案:

答案 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类型。例如,将isOfTypevariantColorValues一起使用时,T将是string,而U将是VariantColor

Playground link


编辑:根据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
}

Playground link

答案 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)

    }
}


Playground link