如何在Typescript中定义泛型类型保护?

2w2cym1i  于 2023-11-20  发布在  TypeScript
关注(0)|答案(3)|浏览(154)

我想为我的类定义一个接口,它包含一个isValidConfig函数作为类型保护。但是我不确定如何声明它。
我这样做了:

type AnyConfig = ConfigA | ConfigB | ConfigC;

public abstract isValidConfig<T extends AnyConfig>(config: AnyConfig): config is T;

字符串

public abstract isValidConfig<T = AnyConfig>(config: T): config is T;


但我总是在实现中遇到错误,比如:

public isValidConfig<T extends ConfigA >(config: T): config is T {
    return config.type === TrainingTypes.A;
} /// Types of parameters 'config' and 'config' are incompatible.
      Type 'T' is not assignable to type 'ConfigA '.


有可能吗?我还没找到方法。

k7fdbhmy

k7fdbhmy1#

这个错误是因为你不能有一个对泛型强制执行的防护。https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards
你可以做这样的事情来防止一个单独的类型:

enum ConfigTypes {
  a = 'a',
  b = 'b',
  c = 'c'
}

interface ConfigA {
  field: number;
  type: ConfigTypes.a;
}

interface ConfigB {
  otherField: string;
  type: ConfigTypes.b;
}

interface ConfigC {
  yetAnotherField: string[];
  type: ConfigTypes.c;
}

type AnyConfig = ConfigA | ConfigB | ConfigC;

export function isValidConfigA(config: AnyConfig): config is ConfigA {
  return config.type === ConfigTypes.a;
}

字符串
值得补充的是,类型必须在编译时强制执行,因为TypeScript根本无法执行运行时检查(到那时它已经被编译为JavaScript,它执行动态(运行时)检查)。换句话说,您只能防范特定的已知类型。
如果你想检查一个给定的预期配置是一个配置,那么从上面的例子继续,你可以这样做:

export function isValidConfig(config: AnyConfig): config is AnyConfig {
  return (
    config.type === ConfigTypes.a ||
    config.type === ConfigTypes.b ||
    config.type === ConfigTypes.c
  );
}

kpbpu008

kpbpu0082#

如果你使用多个泛型,我认为这将工作得很好。

interface A {
  a: number
}
interface B {
  b: string
}

function isTypeA<TA extends A, TB extends B>(val: TA | TB): val is TA {
  return typeof (val as any).a === 'number'
}

const a: A = {a: 1}
if (isTypeA(a)) {
    console.log(a.a) // okay
}

字符串

u59ebvdq

u59ebvdq3#

在另一个帖子中有this answer--原始的主题更广泛,但我已经在长长的回复列表中找到了你可能一直在寻找的东西。
基本的想法是使用你正在检查的对象的一些唯一属性-所以你必须将它作为第二个参数传递给你的检查函数。听起来“crutchy”,但我还没有找到更好的方法。当他们的语言没有提供适当的方法时,一个纯粹的开发人员能做什么,对吗?
我想对上述解决方案补充两点:

  • 命名你的方法instanceOf()对我来说感觉有点不对劲,我至少会叫它instanceOfInterface()或类似的东西,
  • 你可能需要为你的泛型类型提供一个正确的扩展名,比如:instanceOfInterface<T extends object>

所以最终你会有:

public instanceOfInterface<T extends object>(
  entity: T,
  uniqueProperty: string,
): entity is T {
  return uniqueProperty in entity;
}

字符串

相关问题