What is the best way to bypass using an if/else statement in TypeScript when dealing with mocha and returning undefined values

A unique spline able to be intertwined and produce a new version of itself, most of the time.

export default class UniqueSpline {
  public intertwinedCount: number;

  constructor(parent?: UniqueSpline) {
    this.intertwinedCount = parent && parent.intertwinedCount + 1 || 0;
  }

  public intertwine(): UniqueSpline | undefined {
    return new UniqueSpline(this);
  }
}
import { assert, expect } from 'chai';
import UniqueSpline from '../src/unique-spline';

describe("UniqueSpline", () => {
  const uniqueSpline = new UniqueSpline();

  it("creates a new intertwined spline", () => {
    const intertwinedSpline = uniqueSpline.intertwine();
    expect(intertwinedSpline).to.not.be.null;
    expect(intertwinedSpline.intertwinedCount).to.eq(1);
  });
});

Encounters

error TS2532: Object is possibly 'undefined'.

/Users/dblock/source/ts/typescript-mocha/node_modules/ts-node/src/index.ts:245
    return new TSError(diagnosticText, diagnosticCodes)
           ^
TSError: ⨯ Unable to compile TypeScript:
test/unique-spline.spec.ts:18:12 - error TS2532: Object is possibly 'undefined'.

18     expect(intertwinedSpline.intertwinedCount).to.eq(1);

To work around this issue in tests, an if statement is used.

  it("creates a new intertwined spline", () => {
    const intertwinedSpline = uniqueSpline.intertwine();
    if (intertwinedSpline) {
      expect(intertwinedSpline.intertwinedCount).to.eq(1);
    } else {
      expect(intertwinedSpline).to.not.be.null;
    }
  });

Is there a solution for this problem without turning off strictNullChecks?

Code available at https://github.com/dblock/typescript-mocha-strict-null-checks.

Answer №1

To ensure a value is not null, you can utilize the non-null (!) operator.

it("can always be reticulated once more", () => {
  const reticulatedSpline = spline.reticulate();
  expect(reticulatedSpline).to.not.be.null;
  expect(reticulatedSpline!.reticulatedCount).to.eq(1);
});

According to the documentation:

[You] may be used to assert that its operand is non-null and non-undefined in contexts where the type checker is unable to conclude that fact

Source

Answer №2

Here is an updated example showcasing the new "assertion signatures" feature in Typescript 3.7:

/**
 * A replacement for `expect(value).to.exist`
 *
 * This function serves as a workaround for Chai assertions not being detected by TypeScript's control flow analysis.
 * @param {any} value
 */
export function expectToExist<T>(value: T): asserts value is NonNullable<T> {
  expect(value).to.exist;
  if (value === null || value === undefined) {
    throw new Error('Expected value to exist');
  }
}

Additional Resources:

Answer №3

In these examples, the usage of .to.not.be.null does not impact the code flow enough for TypeScript to infer any changes made to the passed parameters. However, a solution to this can be implemented using user-defined type guards.

function assertNotNull<T>(v: T | null): v is NonNullable<T> {
    if (!v) throw new Error();
    return true
}

declare const maybeAString: string | undefined

function ex() {
    // TS cannot determine that this function will throw an error
    assertNotNull(maybeAString)
    maybeAString

    // By using control flow analysis, TypeScript understands that this function confirms maybeAString is definitely not null
    if(assertNotNull(maybeAString)) {
        maybeAString // now guaranteed to be a string
    }

    // Control flow analysis knows that if the previous branch doesn't return, then the main path must be non-null
    if(!assertNotNull(maybeAString)) return

    maybeAString // now confirmed to be a string
}

Click here for playground

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

Enhance your FullCalendar experience with React by displaying extra information on your calendar

I am new to using React and FullCalendar, and I have a page layout similar to the image linked below. Additionally, I have a list of events structured as shown: id: "9", eventId: "1", title: "Training Network", st ...

Troubleshooting: Unable to locate .vue.d.ts file during declaration generation with Vue, webpack, and TypeScript

Currently, I am developing a library using Typescript and VueJS with webpack for handling the build process. One of the challenges I'm facing is related to the generation of TypeScript declaration files (.d.ts). In my source code, I have Typescript ...

When the child component's form is marked as dirty, the parent component can access it

I have implemented a feature in my application that notifies users about pending changes on a form before they navigate away. Everything works as expected, but I have a child component with its own form that needs to be accessed by the guard to check if i ...

Having trouble retrieving information from a controller action in .NET Core and Angular 2

My Angular 2 service: private checkEmailAvailabilityUrl = 'api/admin/checkemailavailability'; checkEmailAvailability(email: string): Observable<boolean> { let params = new URLSearchParams(); params.set('email', email); ...

How to open a print preview in a new tab using Angular 4

Currently, I am attempting to implement print functionality in Angular 4. My goal is to have the print preview automatically open in a new tab along with the print popup window. I'm struggling to find a way to pass data from the parent window to the c ...

What is preventing MenuItemLink from being displayed in the menu?

I have created a unique page for users to purchase subscriptions, but I am having trouble accessing that page because the button is not appearing in the menu. I followed the steps outlined in the official guide, but only the dashboard and resources buttons ...

Exception occurs when arrow function is replaced with an anonymous function

Currently, I am experimenting with the Angular Heroes Tutorial using Typescript. The code snippet below is functioning correctly while testing out the services: getHeroes() { this.heroService.getHeroes().then(heroes => this.heroes = heroes); } H ...

The function signature '() => Element' is incompatible with the type 'string'

Greetings! I have a standard function that returns a span with a prop (if I'm not mistaken). In my TS code, I am encountering this error: Error image Below is the code from the file named qCard.tsx: import { QuestionAnswerTwoTone } from "@material- ...

Tips for altering a key within a tree-view:

I am working with a potentially infinite tree-view array: type Tree = { id: number; name: string; email: string; children: Tree[]; }; const tree: Tree[] = [ { id: 1, name: 'Truck', email: '@mail', children ...

Update the TypeScript definitions in the index.d.ts file using the npm command, by overriding it with the reference types

After running npm install, I noticed that the index.d.ts file contains a reference to the wrong path: /// <reference types="[WrongPath]"/>. As someone new to npm, TypeScript, and web development in general, I'm wondering if it's possible t ...

Guide to creating a one-to-one object literal map with a different value type using a function return without explicitly defining the return type

At the moment, I have successfully managed to combine the keys and values of each object literal that is passed into a function. For example: interface StaticClass<T = any> { new (...args: any[]): T } type RecordOfStaticClasses = Record<string, ...

Vuefire encountering an issue with Vue 3 and throwing a Vue.use error

After setting up a Vue app and importing Vue from the vue module, I encountered an issue: ERROR in src/main.ts:4:5 TS2339: Property 'use' does not exist on type 'typeof import("/data/data/com.termux/files/home/ishankbg.tech/node_modules/vue/ ...

Angular production application is experiencing issues due to a missing NPM package import

Objective I am aiming to distribute a TypeScript module augmentation of RxJS as an npm package for usage in Angular projects. Challenge While the package functions correctly in local development mode within an Angular application, it fails to import pro ...

Performing actions simultaneously with Angular 2 directives

My custom directive is designed to prevent a double click on the submit button: import { Directive, Component, OnInit, AfterViewInit, OnChanges, SimpleChanges, HostListener, ElementRef, Input, HostBinding } from '@angular/core'; @Directive({ ...

Converting JSON to string in Typescript is causing an error where type string cannot be assigned to type '{ .. }'

Here's the code snippet I'm working with: interface ISource extends IdModel { source_type_id: number; network_id: number; company_connection_id: number; feed_id: number; connection_id: number; feed_ids: number[]; name: string; tag ...

Error: Unable to locate Angular2 Custom Service

I have implemented a custom service to populate a list of people in my HTML. Below is the code for my custom service: app.peopleListService.ts import { Injectable } from '@angular/core'; import { Person } from "../model/peopleModel"; @Injecta ...

Having difficulty executing the Cypress open command within a Next.js project that uses Typescript

I'm having trouble running cypress open in my Next.js project with Typescript. When I run the command, I encounter the following issues: % npm run cypress:open > [email protected] cypress:open > cypress open DevTools listening on ws: ...

Using TypeScript and controllerAs with $rootScope

I am currently developing an application using Angular 1 and Typescript. Here is the code snippet for my Login Controller: module TheHub { /** * Controller for the login page. */ export class LoginController { static $inject = [ ...

Efficiently process and handle the responses from Promise.all for every API call, then save the retrieved data

Currently, I am passing three API calls to Promise.all. Each API call requires a separate error handler and data storage in its own corresponding object. If I pass test4 to Promise.all, how can I automatically generate its own error and store the data in ...

Struggles with updating app.component.ts in both @angular/router and nativescript-angular/router versions

I have been attempting to update my NativeScript application, and I am facing challenges with the new routing system introduced in the latest Angular upgrade. In my package.json file, my dependency was: "@angular/router": "3.0.0-beta.2" After the upg ...