首页 > 解决方案 > 负类型断言返回谓词

问题描述

我正在尝试编写两个 jest 函数,它们期望一个对象是否是某种类型的实例。

正面的例子expectInstanceOf就像一种魅力,但负面的例子expectNotInstanceOf却没有。

export function expectInstanceOf<E, A extends unknown[]>(obj: unknown, type: new (...args: A) => E): asserts obj is E {
  expect(obj).toBeInstanceOf(type);
}

export function expectNotInstanceOf<E, A extends unknown[]>(obj: unknown, type: new (...args: A) => E): asserts obj is Exclude<typeof obj, E> {
  expect(obj).not.toBeInstanceOf(type);
}

class Foo {
  foo() {
    /**/
  }
}
class Bar {
  bar() {
    /**/
  }
}

function foo(obj: Foo | Bar) {
  expectInstanceOf(obj, Foo);
  obj.foo();
}

function notFoo(obj: Foo | Bar) {
  expectNotInstanceOf(obj, Foo);
  obj.bar(); // Property 'bar' does not exist on type 'Foo | Bar'.
}

我该如何解决expectNotInstanceOf

标签: typescript

解决方案


在您的代码中,typeof obj始终unknown类型(您不能使用类型typeof查询运算符来“抽象”特定类型),并且实用 程序Exclude<T, U>类型过滤. 不是联合,所以很可能是(我想它也可能是if is类型)。因此,虽然缩小到, expectNotInstanceOf unknown`,但没有帮助。TunknownExclude<unknown, E>unknownneverEunknownexpectInstanceOfEnarrows to

您想要做的是使其obj拥有自己的泛型类型参数(例如T),然后用T. 例如:

function expectInstanceOf<T, E, A extends unknown[]>(
    obj: T, type: new (...args: A) => E): asserts obj is T & E { }

function expectNotInstanceOf<T, E, A extends unknown[]>(
    obj: T, type: new (...args: A) => E): asserts obj is T & Exclude<T, E> { }

现在示例代码可以按需要工作:

function foo(obj: Foo | Bar) {
    expectInstanceOf(obj, Foo);
    obj.foo(); // okay
}

function notFoo(obj: Foo | Bar) {
    expectNotInstanceOf(obj, Foo);
    obj.bar(); // okay
}

Playground 代码链接


推荐阅读