Tips for explaining the structure of a basic Just functor in TypeScript

I am embarking on my first attempt to create a simple interface in TypeScript, and I find myself questioning every step along the way.

The core question that troubles me is: How can I best describe this straightforward Jest matcher extension?

/**
 * @param {*} v Any value
 */
function just (v) {
  return {
    fmap: f => just(f(v))
  }
}

expect.extend({
  /** Compare the two values inside two functors with Object.is
   * @method
   * @augments jest.Matchers
   * @param {*} actual The functor you want to test.
   * @param {*} expected The functor you expect.
   */
  functorToBe(actual, expected) {
    const actualValue = getFunctorValue(actual)
    const expectedValue = getFunctorValue(expected)
    const pass = Object.is(actualValue, expectedValue)
    return {
      pass,
      message () {
        return `expected ${actualValue} of ${actual} to ${pass ? '' : 'not'} be ${expectedValue} of ${expected}`
      }
    }
  }
})

test('equational reasoning (identity)', () => {
  expect(just(1)).functorToBe(just(1))
})

Although I attempted to implement this, I have uncertainties regarding the usage of generic types:

import { Matchers } from 'jest'

interface Functor<T> {
  (value?: any): {
    fmap: (f: value) => Functor<T>
  }
}

interface Matchers<R> {
  functorToBe(actual: Functor<T>, expected:  Functor<T>): R
}

Reference: JSDoc document object method extending other class

The key point of the Jest type definition for Matchers<R>:

/**
 * The `expect` function is used every time you want to test a value.
 * You will rarely call `expect` by itself.
 */
interface Expect {
    /**
     * The `expect` function is used every time you want to test a value.
     * You will rarely call `expect` by itself.
     *
     * @param actual The value to apply matchers against.
     */
    <T = any>(actual: T): Matchers<T>;
    /**
     * You can use `expect.extend` to add your own matchers to Jest.
     */
    extend(obj: ExpectExtendMap): void;
    // etc.
}

This situation is quite perplexing. The only index.d.ts found in the jest repository is https://github.com/facebook/jest/blob/master/packages/jest-editor-support/index.d.ts, which differs from what I see in vscode, located at https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/jest/index.d.ts#L471.

Answer №1

Addressing the Extension Issue

In examining your integration of Matchers, it appears that there is an issue with how it is structured. After referring to the jest types on Definitely Typed [1], it seems that Matchers should be nested within a jest namespace. The TypeScript handbook delves into this concept through namespace merging.

namespace jest {
    export interface Matchers<R> {
        functorToBe<T>(actual: Functor<T>, expected:  Functor<T>): R;
    }
}

During my testing, I found it necessary to have a tsconfig.json file in place for my JS files to recognize the declaration:

{
    "compilerOptions": {
        "allowJs": true,
        "checkJs": true,
    },
    "include": [
        "test.js",
        "extensions.ts",
    ]
}

A jsconfig.json serves a similar purpose but does not mandate the explicit addition of "allowJs": true. However, be mindful that introducing a tsconfig or jsconfig will disable automatic type downloads from Definitely Typed. Consequently, you will need to manually npm install @types/jest (in addition to any other required types for libraries used). If opting not to include a tsconfig, I managed to manually reference the extensions.ts file at the outset of the JS file:

/// <reference path="./extensions.ts" />

Determining the Type for the New Method

The anticipated structure would resemble:

functorToBe(expected: R): R;

This section may pose some confusion, so feel free to approach me with any queries regarding this aspect of the problem, and I'll do my best to offer assistance.

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

Countdown with precision! This timer will begin at the one-hour mark

Having an issue with my JavaScript stopwatch. When I hit the start button, the stopwatch immediately shows one hour (01:00:00) before counting normally. Any solutions to prevent this instant start at one hour would be highly appreciated. Thank you in adv ...

Tips for aligning the camera to ensure the object maintains a consistent pixel width and height on the screen

I am grappling with a challenge that I'm unsure how to approach, hoping someone can offer me a clue on the solution. My goal is to position the camera at a specific z index so that a cube appears on the screen with consistent pixel dimensions regardl ...

Is Window.navigator malfunctioning on different browsers in Mac OS?

I'm attempting to access the navigator function in my project to share a specific URL, but I'm facing difficulties accessing it on Mac OS when using browsers other than Safari. Is there a solution to this issue? Below is the function I created f ...

Having trouble with Next.js getStaticProps? Getting a TypeError that says "Cannot read properties of undefined (reading 'map')"?

My latest project was built using create-next-app as a base. In the Blog.js page, I attempted to fetch data from https://jsonplaceholder.typicode.com/posts by utilizing the getStaticProps() function. I followed the instructions provided in this guide: htt ...

Moving from one page to another

I am attempting to create a transition effect between sections within a single-page application. All the sections are contained on the same page, with only one section displayed at a time while the rest are set to display none. When a specific event is tri ...

My draggable item seems stuck in place. Any ideas on how to get it moving again?

I have been trying to implement some code I found on this link. Despite adding all the necessary file links, the code is not functioning as expected. It should be able to move within the bounds of a container, but it's not working properly. var max ...

Guide to sending parameters to the method function of the Vue.js router

I am encountering an issue while trying to pass 'joke.id' as a parameter to the router: edit: function(joke) { this.$router.push({ '/edit/' + joke.id }); } The specific route in question is: {path: '/edit/:id', compone ...

Looking to eliminate curly braces from a string?

Despite my efforts to search through the site, I am still unable to resolve the issue at hand. var blah2 = JSON.stringify({foo: 123, bar: <x><y></y></x>, baz: 123}); This is what I attempted: blah2.replace(/[{}]/g, ""); Here&apo ...

IE8 is proving to be a major hurdle for the successful operation of AngularJS $http

Currently, I am faced with the challenge of creating an Angular application that needs to be compatible with IE8. However, I'm encountering difficulties in establishing a connection with the server. Surprisingly, whenever I attempt a $http.get, the en ...

What is the equivalent of specifying globalDevDependencies for npm @types packages in typings?

I am looking to update a project using tsc@2 and remove typings from my toolchain. Updating common dependencies is easy as they are listed in my typings.json file: "dependencies": { "bluebird": "registry:npm/bluebird#3.3.4+20160515010139", "lodash": ...

What is preventing the text of the elements from being updated?

My attempt to use JavaScript to change the text of this element has not been successful. The header I am trying to modify is enter image description here var elem = document.getElementsByClassName("headertext"); elem.innerHTML = "hello world"; <ul cl ...

What are the steps to create an object from an array?

Is it possible to create an object from an array in TypeScript? { A: {H: 10, W: 20, S: 30}} using the following data: [ { group: A, name: H, value: 10 }, { group: A, name: W, value: 20}, { group: A, name: S, value: 30} ] L ...

SignalR does not include cookies in the connection request

While working on a web application using ASP.NET Web API and SignalR, I encountered an issue that is proving to be quite challenging despite my understanding of HTTP. Currently, I have successfully set a cookie on all AJAX requests to the API, and subsequ ...

NextJS is currently unable to identify and interpret TypeScript files

I am looking to build my website using TypeScript instead of JavaScript. I followed the NextJS official guide for installing TS from scratch, but when I execute npm run dev, a 404 Error page greets me. Okay, below is my tsconfig.json: { "compilerOption ...

What could be the reason for express-validator's inability to identify missing fields during the validation of XML input

My server, based on Express, is set up to parse XML instead of JSON using body-parser-xml. To validate the input body, I am using express-validator as shown in the following simplified example: router.post("/", body('session.credential[0].$.usern ...

The ngModel directive automatically clears the checkbox's Checked status

Currently, my Angular code is set up to validate a checkbox using ng-model: <input type="checkbox" name="news1" value="news1" ng-model="news" <c:if test="${xxxx == yes'}">checked="checked"></c:if>> <label ng-click="news1();"&g ...

Error: JSON encountered circular structure when attempting to serialize an object of type 'ClientRequest' with a property 'socket' that references an object of type 'Socket'

Encountering an error while attempting to make a POST request to my TypeORM API using axios: TypeError: Converting circular structure to JSON --> starting at object with constructor 'ClientRequest' | property 'socket' -&g ...

I am experiencing an issue in my React application where the component is not being rendered when using a nested route with React Router Dom v6. Despite the

On my main page, I have a sidebar and a content display area that shows the selected option. The issue arises when I click on a link in the sidebar - it doesn't change anything in the content display section, only the URL changes. If I define the rout ...

How can I interact with a v-dialog component within a child component in Vue.js using Vuetify?

Exploring Vue.js for the first time and hoping to display a login dialog upon button click. To maintain cleanliness in my code, I shifted the dialog to a child component within a parent component with nested LoginDialog. Below are snippets of the parent co ...

Dynamic SVG circles with timer and progress animation

Is there a way to modify the following: var el = document.getElementById('graph'); // get canvas var options = { percent: el.getAttribute('data-percent') || 25, size: el.getAttribute('data-size') || 220, lineW ...