Jasmine 自定义匹配器类型定义

Jasmine custom matcher type definition

我正在尝试将 typescript 定义添加到 jasmine 匹配器 library

我能够为泛型 T 添加匹配器,但现在我只想将匹配器添加到 DOM 元素。

深入研究 jasmine 类型定义代码,我发现了与 ArrayLike 类似的方法(请参阅 here for the expect overload and here 了解 ArrayLikeMatchers)。

所以我创建了一个类似的。

// Overload the expect
declare function expect<T extends HTMLElement>(actual: T): jasmine.DOMMatchers<T>;

declare namespace jasmine {
    // Augment the standard matchers. This WORKS!
    interface Matchers<T> {
        toBeExtensible(): boolean;
        toBeFrozen(): boolean;
        toBeSealed(): boolean;
        // ... other
    }
    // The matchers for DOM elements. This is NOT working!
    interface DOMMatchers<T> extends Matchers<T> {
        toBeChecked(): boolean;
        toBeDisabled(): boolean;
    }
}

但是,不起作用:(

给定以下代码:

const div = document.createElement("div");
expect(div).toBeChecked();

类型检查器给我错误:

[js] Property 'toBeChecked' does not exist on type 'Matchers'.


唯一的解决方案似乎是在 expect 通用 expect 之前添加 expect 重载 (在 ArrayLike 重载 here) 在核心 jasmine 库中。

但是...这是不可行的:)

关于如何正确实施有效解决方案的任何提示?

问题在于 Typescript 按声明顺序选择重载,而非常通用的 declare function expect<T>(actual: T): jasmine.Matchers<T>; 将出现在您的重载之前。您也许可以使用 /// 参考找到一些神奇的顺序,但我无法让它工作,而且它会非常脆弱。

更好的方法是在 Matchers<T> 上添加额外的函数,但将 this 限制为从 Matchers<HTMLElement>

派生
declare namespace jasmine {
    interface Matchers<T> {
        toBeExtensible(): boolean;
        toBeFrozen(): boolean;
        toBeSealed(): boolean;

        // this must be derived from Matchers<HTMLElement>
        toBeDisabled(this: Matchers<HTMLElement>): boolean;
        // or make it generic, with T extending HTMLElement if you really need the actual type for some reason 
        toBeChecked<T extends HTMLElement>(this: Matchers<HTMLElement>): boolean; 
    }
}

// usage
const div = document.createElement("div");
expect(div).toBeChecked(); // ok
expect(10).toBeChecked() // error