简体   繁体   English

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

[英]How to pass type as a function parameter

I have the below types checking code to verify if userInput is one of the defined value我有以下类型检查代码来验证 userInput 是否是定义的值之一

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

The code above works great.上面的代码效果很好。 However the code will bulk up if I implement same logic to other properties too, so I thought of turning isOfTypeVariantColor into a generic function.然而,如果我对其他属性也实现相同的逻辑,代码会变大,所以我isOfTypeVariantColor变成一个通用函数。

function isOfType(userInput: string, valueList: string[]): userInput is VariantColor {
  return (valueList as readonly string[]).includes(userInput);
}

And my problem now is that I'm not sure how to turn userInput is VariantColor where VariantColor becoming a parameter我现在的问题是我不确定如何将userInput is VariantColor ,其中VariantColor成为参数

You could use this:你可以用这个:

// 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 is the user input type and you are checking if userInput is type U . T是用户输入类型,您正在检查userInput是否为U类型。 For example, when using isOfType with variantColorValues , T would be string and U would be VariantColor .例如,当使用isOfTypevariantColorValuesT将是stringU将是VariantColor

Playground link 游乐场链接


Edit: Per Gerrit0's comment, you don't actually need two type parameters:编辑:根据 Gerrit0 的评论,您实际上并不需要两个类型参数:

function isOfType2<T>(userInput: unknown, valueList: readonly T[]): userInput is T {
  return (value as readonly unknown[]).includes(userInput);
}

However, it won't pick up on this:但是,它不会注意到这一点:

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 游乐场链接

Here's how I've done it:这是我如何做到的:

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);
}

Demo of use:使用演示:


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 游乐场链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM