typescript 文本联合类型上的类型保护

btxsgosb  于 2023-01-27  发布在  TypeScript
关注(0)|答案(3)|浏览(122)

我在TypeScript中有两种类型:

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

我希望使用相同的api函数来处理这些类型,但每种类型的行为都不同。

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

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

}

我也尝试过重载这个函数,如下所示:

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
}

我也不喜欢。有什么建议吗?

whhtz7ly

whhtz7ly1#

您可以像这样创建类型保护:

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

然后在API集成函数中使用它:

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

警告!小心,因为如果PublicMethod类型被更新而类型保护没有被更新,TS将不会抛出。
要更好地处理此问题,请使用以下方法:

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

ngynwnxp2#

如果基于常数数组定义类型:

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

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

现在你可以将名称PublicMethods用作类型和变量,变量分别表示字符串和数组的并集,这样你就可以使用类型 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);
}

这允许您通过检查PublicMethods(数组)是否包含value,将值范围缩小到PublicMethods(类型):

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

Playground

xoefb8l8

xoefb8l83#

请注意,typescript类型在运行时不可用,因此

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

不起作用,因为method实际上是字符串。
因此,一个非常基本的解决方案是switch

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

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

}

如果你想区分PublicMethodsPrivateMethods而不用迭代它们,你可以使用枚举:

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

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

}

相关问题