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

Creating a WebExtension using Angular and TypeScript

I am currently working on creating a WebExtension using Angular and Ionic. The extension successfully loads the application and enables communication between Content Script and Background Script. However, I am facing an issue where the TypeScript code is n ...

What is the reason for a class's attributes being considered undefined even after they have been previously set?

Within my code, there is a class called WorkspaceDatabase that stems from the Dynamic Tree Example. I have incorporated some debugging information to gain a clearer understanding of the issue at hand. The Issue: Upon entering the complete() function, an ...

When I define a type in TypeScript, it displays "any" instead

Imagine a scenario where we have a basic abstract class that represents a piece in a board game such as chess or checkers. export abstract class Piece<Tags, Move, Position = Vector2> { public constructor(public position: Position, public tags = nul ...

Conceal the current component when navigating in Angular 2

When I swipe on the app.component, I am being redirected to another component. However, the content of the other component is not fully displayed as it is also showing the content of the app.component. How can I hide the app.component content and only di ...

Limiting the parameter type in Node.js and TypeScript functions

Currently working on a Node.js project utilizing TypeScript. I'm attempting to limit the argument type of a function to a specific base class. As a newcomer to both Node and TypeScript with a background in C#, I may not fully grasp some of the langua ...

The RemoveEventListener function seems to be malfunctioning within Angular2 when implemented with TypeScript

I am currently incorporating three.js into Angular2. The code I am using is quite straightforward, as shown below. this.webGLRenderer.domElement.addEventListener('mousedown', ()=>this.onMouseDown(<MouseEvent>event), false); this.webGLR ...

A function that takes in a type identifier and a portion of a type, and then outputs the full type

I'm currently facing a challenge with TypeScript generics. I have several types (referred to as Animals) that each have a unique attribute, "type." Additionally, I have a function called createAnimal which takes the type of animal and a partial object ...

Mysterious attributes of angular 6's <table mat-table> tag

This particular question regarding the angular material table has not been duplicated in any other discussions. Other similar questions pertain to angular versions 2-5, not version 6 The issue I am encountering is as follows: Can't bind to 'dat ...

Importing Typescript modules by specifying their namespace instead of using a function

I have been working on a project where I needed to generate typings from graphql using the gql2ts library. In the gql-2-ts file, I initially used a namespace import for glob, which resulted in TypeScript showing me an error as intended. I then switched the ...

Unable to fulfill the pledge

I'm struggling to receive the promise from the backend after making a get request. Can anyone help me figure out what I might be doing wrong? makeLoginCall(_username: string, _password: string) { let promise = new Promise((resolve, reject) => ...

What is the best way to modify a particular internal route parameter within Angular 2?

In the midst of creating a versatile calendar that can showcase various types of data, I have devised a unique URL structure to guide me: todo/2017/01/01 showcases daily todos birthdays/2017/01/01 displays birthdays for that particular day todo/2017/01 g ...

Obtaining an instance of the CKEditor Editor in TypeScript with CKEditor 4: what's the best way?

Can someone explain how to utilize the CKEDITOR 4 plugin in TypeScript for an Angular 9 application? I am looking to set the configuration through TypeScript (specifically for autogrow) and also implement an INSERT HTML function. I have already imported ...

A comparison between Buffer.byteLength and file size

I'm facing an issue with file size discrepancies. I have a file that is reported as 51Mb in Finder, but when uploaded to the server, the byteLength of the Buffer shows a much smaller size. Could this difference be due to the file type or other propert ...

Node.js does not allow the extension of the Promise object due to the absence of a base constructor with the required number of type

I'm trying to enhance the Promise object using this code snippet: class MyPromise extends Promise { constructor(executor) { super((resolve, reject) => { return executor(resolve, reject); }); } } But I keep encou ...

What is the best way to convert a tuple containing key/value pairs into an object?

How can the function keyValueArrayToObject be rewritten in order to ensure that the type of keyValueObject is specifically {a: number; b: string}, instead of the current type which is {[k: string]: any}? const arrayOfKeyValue = [ {key: 'a', val ...

Issue with typings in TypeScript is not being resolved

I have integrated this library into my code Library Link I have added typings for it in my project as follows Typings Link I have included it in my .ts file like this import accounting from "accounting"; I can locate the typings under /node_modules ...

Tips for effectively passing an array to props in Vue when leveraging Typescript and the class component decorator

I'm currently struggling to understand the proper method of passing an array as a prop to a component in Vue, using Typescript and the class component library. Following the official template, I attempted the following approach: <script lang="ts"& ...

Come back to Angular 2 on your return function

Having a problem with an asynchronous function. There is a service that retrieves data from a Firebase database. One of the functions returns a value: historialDeConsumi() { this.item = this.af.database.object('/users/' + this.uid + '/a ...

Mastering the art of Interpolation and Binding in Ionic 3/Angular 4: A step-by-step

My goal is to retrieve data from my Parse Server where MongoDB is installed. Although I have successfully displayed the data in the console, I am facing issues interpolating them in the HTML template. Here is my search.ts file: import { localData } from ...

Ways to determine the number of duplicate items in an Array

I have an array of objects that contain part numbers, brand names, and supplier names. I need to find a concise and efficient way to determine the count of duplicate objects in the array. [ { partNum: 'ACDC1007', brandName: 'Electric&apo ...