简体   繁体   English

文字联合类型的类型保护

[英]A type guard on literal union types

I have two types in TypeScript:我在TypeScript中有两种类型:

type PublicMethods = 'Time' | 'Assets' | 'AssetPairs' ;
type PrivateMethods = 'Balance' | 'TradeBalance';

I would like to use the same api function to handle these types, but the behaviour is different for each.我想使用相同的api function 来处理这些类型,但每种类型的行为都不同。 Something along the lines of:类似的东西:

public api = (method: PublicMethods | PrivateMethods, params: any) => {

  // ...how do I create a type guard here?
  if(method instanceof PublicMethods) { // 😱 Doesn't like this!
    // ...
  }

}

I also tried overloading the function, like this:我还尝试过重载 function,如下所示:

public api(method: PublicMethods | PrivateMethods, params: any, callback: Function);

public api(method: PublicMethods, params: any, callback: Function) {
   // ...implementation
}

public api(method: PrivateMethods, params: any, callback: Function) {
   // ...implementation
}

Didn't like that either.也不喜欢那样。 Any suggestions?有什么建议么?

You can create a type guard like this:你可以像这样创建一个类型保护:

const isPublicMethod = (value: any): value is PublicMethod => {
  return ['Time', 'Assets', 'AssetPairs'].includes(value);
};

and then use it in your API integration function:然后在您的 API 集成 function 中使用它:

public api = (method: PublicMethods | PrivateMethods, params: any) => {
  if(isPublicMethod(method)) {
    ...
  }
}

Warning, Be careful, since TS will not throw if PublicMethod type is updated and type guard is not.警告,小心,因为如果PublicMethod类型更新而类型保护没有更新,TS 将不会抛出。

To handle this better, use the following approach:为了更好地处理这个问题,请使用以下方法:

const PUBLIC_METHODS = ['Time', 'Assets', 'AssetPairs'] as const;

type PublicMethod = typeof PUBLIC_METHODS[number];

const isPublicMethod = (value: any): value is PublicMethod => {
  return PUBLIC_METHODS.includes(value);
};

If you define your types based on a constant array:如果您根据常量数组定义类型:

const PublicMethods = ['Time', 'Assets', 'AssetPairs'] as const;
const PrivateMethods = ['Balance', 'TradeBalance'] as const;

type PublicMethods = typeof PublicMethods[number];
type PrivateMethods = typeof PrivateMethods[number];

You'll now be able to use the name PublicMethods as both a type and a variable that refers to the union of strings and array, respectively.您现在可以将名称PublicMethods用作类型变量,分别引用字符串和数组的联合。 With this, you can create a user-defined type guard using a type predicate :有了这个,您可以使用类型谓词创建用户定义的类型保护:

function isPublicMethod(value: string): value is PublicMethods {
    // some sort of assertion is needed because
    // it will error that type 'string' is not assignable to type '"Time" | "Assets" | "AssetPairs"'
    return PublicMethods.includes(value as any);
}

This allows you to narrow the value to PublicMethods , the type, by checking if PublicMethods , the array, includes value :这允许您通过检查数组PublicMethods是否包含value来将值缩小到类型PublicMethods

function doStuff(method: PrivateMethods | PublicMethods) {
    if (isPublicMethod(method)) {
        method
        // ^? PublicMethods
    }
}

Playground操场

Note that typescript types are not available at runtime, so请注意,typescript 类型在运行时不可用,因此

  if(method instanceof PublicMethods) {
    // ...
  }

does not work, since method will actually be a string.不起作用,因为method实际上是一个字符串。

So a very basic solution is a switch .所以一个非常基本的解决方案是switch

public api = (method: PublicMethods | PrivateMethods, params: any) => {

  switch(method){
    case 'Time': ...
    case 'Assets': ...
    ...
  }

}

If you want to discern between PublicMethods and PrivateMethods without iterating them, you can use enums:如果你想区分PublicMethodsPrivateMethods而不迭代它们,你可以使用枚举:

enum PublicMethods{
  'Time' = 'Time',
  'Assets' = 'Assets'
}

public api = (method: PublicMethods | PrivateMethods, params: any) => {
  if(method in PublicMethods){
    ...
  }

}

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

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