Definition of Jasmine custom matcher type

I have been working on adding typescript definitions to a custom jasmine matcher library.

Initially, I successfully added matchers for the generic type T. Now, my goal is to specifically add matchers for DOM elements.

While exploring the jasmine type definition code, I came across a similar technique used for ArrayLike (refer here for the expect overload and here for the ArrayLikeMatchers).

Following that example, I created a similar setup.

// 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;
    }
}

Despite the effort, it's currently not functioning as expected.

When testing the following code:

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

The type checker throws an error:

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


The apparent solution would be to include the expect overload before the generic expect (after the ArrayLike overload here) in the core jasmine library.

However, that may not be feasible :)

Any suggestions on how to implement a functional solution effectively?

Answer №1

The issue arises from the fact that Typescript selects overloads based on declaration order, causing the very general

declare function expect<T>(actual: T): jasmine.Matchers<T>;
to be prioritized over your specific overload. Attempting to manipulate the ordering using /// references may be possible, but it is complex and unreliable.

An improved solution would involve incorporating your additional functions directly into Matchers<T>, while restricting this to be a subset of Matchers<HTMLElement>.

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

        // this should be a subset of Matchers<HTMLElement>
        toBeDisabled(this: Matchers<HTMLElement>): boolean;
        // alternatively, make it generic, with T extending HTMLElement if specific type is necessary 
        toBeChecked<T extends HTMLElement>(this: Matchers<HTMLElement>): boolean; 
    }
}

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Error message: Unable to locate Bootstrap call in standalone Angular project after executing 'ng add @angular/pwa' command

Having an issue while trying to integrate @angular/pwa, it keeps showing me an error saying "Bootstrap call not found". It's worth mentioning that I have removed app.module.ts and am using standalone components in various places without any module. Cu ...

Is there a way to access the state value within the reducer function of createSlice?

Currently, I am utilizing redux-toolkit within my react project. A concern arises in a specific reducer inside the createSlice method where I aim to incorporate an existing array of entities from the state and then merge it with a new array before finalizi ...

Unable to bring in Vue component from NPM module

Hello there, I recently developed my own npm package for a navigation bar and I need to incorporate it into my main codebase. Currently, I am utilizing vue @components but I am struggling with integrating the imported component. If anyone has insight on h ...

Tips on how to retrieve a stubbed Observable<void> in RxJS

Currently, I am attempting to stub an API and would like to retrieve a stubbed response from my Service. The method in my service appears as follows: public addItem(item): Observable<void> { this.listOfItems.push(item); return of(); } As f ...

There was an error reported by TypeScript stating that Nest.js is not considered a module

During the development of my project using Nest.js, I came across an error that I couldn't find a solution for. The issue arises when I try to export a function from one file and import it into a controller. Even though the function is exported correc ...

Tips for testing the setTimeout function within the ngOnInit using Jasmine

Could someone please assist me with writing a test for an ngOnInit function that includes a setTimeout() call? I am new to jasmine test cases and unsure of the correct approach. Any guidance would be greatly appreciated. app.component.ts: ngOnInit(): void ...

Encountered 'DatePickerProps<unknown>' error while attempting to develop a custom component using Material-UI and react-hook-form

Currently, I'm attempting to create a reusable component using MUI Datepicker and React Hook Form However, the parent component is throwing an error Type '{ control: Control<FieldValues, object>; name: string; }' is missing the follow ...

Attempting to populate an array with .map that commences with a designated number in Angular using Typescript

Currently, I am attempting to populate an array with a series of numbers, with the requirement that the array begins with a certain value and ends with another. My attempt at this task involved the code snippet below: pageArray = Array(finalPageValue).fil ...

Hovering over the Chart.js tooltip does not display the labels as expected

How can I show the numberValue value as a label on hover over the bar chart? Despite trying various methods, nothing seems to appear when hovering over the bars. Below is the code snippet: getBarChart() { this.http.get(API).subscribe({ next: (d ...

Utilizing node-canvas to import a .ttf file into TypeScript for registering a custom font

I am trying to incorporate locally stored fonts (in ttf format) into a canvas that is generated using node-canvas. To achieve this, I have created a typings file and included it in my tsconfig: fonts.d.ts declare module '*.ttf'; The fonts hav ...

Alert the parent angular component of any changes in the object

I am working with a large object in my component, where the properties of the object are connected to various components and inputs within the template: constructor() { this.data = { identifier: null, isRequired: true, title: ' ...

Tips for managing update logic in the server side with sveltekit

Currently, I am using Sveltekit and I am facing a dilemma regarding updating input data. The actual update process is straightforward, but there is an issue that arises when trying to send an update API request immediately, as it requires an accessToken to ...

"Encountering issues with Angular2's FormBuilder and accessing nested object properties,

As I dip my toes into TypeScript and Angular2, I find myself grappling with a nested object structure in an API. My goal is to align my model closely with the API resource. Here's how I've defined the "Inquiry" model in TypeScript: // inquiry.ts ...

Comprehending the concepts of Observables, Promises, using "this" keyword, and transferring data within Angular with TypeScript

I am trying to figure out why I keep receiving the error message: "Uncaught (in promise): TypeError: this.dealership is undefined" when working with the authentication.service.ts file. export class AuthenticationService { private currentUserSubject: ...

a guide to caching a TypeScript computed property

I have implemented a TypeScript getter memoization approach using a decorator and the memoizee package from npm. Here's how it looks: import { memoize } from '@app/decorators/memoize' export class MyComponent { @memoize() private stat ...

Adjusting the transparency of TabBadge in Ionic 2

I am currently working on a project that involves tabs, and I'm looking to update the style of the badge when the value is 0. Unfortunately, I am unsure how to dynamically change the style of my tabs or adjust the opacity of the badge in the style. M ...

Executing an individual .ts file within a Next.js application using ts-node for the purpose of testing

I'm attempting to execute a single ES module .ts file within a Next.js project using the default configuration for quick debugging: npx ts-node lib/my_module.ts However, I encounter the following error: Warning: To load an ES module, set "type&q ...

Exploring the concept of nested arrays in Angular 2 using Typescript

I'm exploring the possibility of defining an array in Angular 2 that contains multiple other arrays within it. To clarify, here's what I had initially: export class PaymentDetails { account: any[]; bpNumber: number; } The issue with t ...

Restricting number input value in Vue using TypeScript

I have a component that looks like this: <input class="number-input py-1 primary--text font-weight-regular" :ref="'number-input-' + title" @keypress="onKeyPressed" :disabled="disabled& ...

Error: Uncaught TypeError - The function indexOf is not defined for e.target.className at the mouseup event in HTMLDocument (translator.js:433) within the angular

Upon clicking on an SVG to edit my data in a modal bootstrap, I encountered the following error: Uncaught TypeError: e.target.className.indexOf is not a function at HTMLDocument.mouseup (translator.js:433) This is my SVG code: <svg data-dismiss ...