Mysterious TypeScript bug, encountering ts2367 during value validation

Here is a TypeScript class example:

class Vector3 {
    //-----PUBLIC VARS

    x: number;
    y: number;
    z: number;


    //-----CONSTRUCTORS

    constructor(x?: number, y?: number, z?: number) {
        this.x = x == undefined ? 0 : x;
        this.y = y == undefined ? 0 : y;
        this.z = z == undefined ? 0 : z;
    }


    //-----METHODS

    SetValues(x: number, y: number, z: number): void {
        this.x = x;
        this.y = y;
        this.z = z;
    }
}

Now, let's write a unit test code for the Vector3 class:

function TestVector3() {
    var lhs = new Vector3(1, 2, 3);

    lhs.SetValues(1, 2, 3);
    if (lhs.x != 2 || lhs.y != 6 || lhs.z != 12) {
        throw "a";
    }
    
    lhs.SetValues(-1, 2, 3);
    if (lhs.x != -1 || lhs.y != -2 || lhs.z != -3) {
        throw "b";
    }
}

An error occurs on 'lhs.x != -1' with the message TS2367. Removing the line 'throw "a";' resolves this error. How can we address this issue?

This error should not occur, and I find it quite frustrating...

Answer №1

This particular situation highlights the flaw in the control flow analysis, as it optimistically assumes that SetValues does not alter the class instance.
However, this behavior is intentional and discussed in detail here: Trade-offs in Control Flow Analysis #9998

Additionally, your code logic seems flawed to me. It will consistently throw an error for "a," rendering the rest of the code unreachable.

If this code is meant for testing purposes, it would be advisable to create dedicated test functions for each scenario.

A temporary solution could involve using @ts-ignore

    // @ts-ignore
    if (lhs.x != -1 || lhs.y != -2 || lhs.z != -3) {
        throw "b";
    }

Playground example

Answer №2

if (lhs.x != 2 || lhs.y != 6 || lhs.z != 12) {
  throw "a"
}

The boundaries of static code analysis are evident in this scenario. By performing the aforementioned check, the types of lhs.x, lhs.y, and lhs.z transition from being considered as any number to specific values of 2, 6, and 12 respectively.

Upon proceeding to the next statement, the compiler deduces that the variables x, y, and z hold the fixed values of 2, 6, and 12 by virtue of no error being thrown earlier. However, following a method call such as

lhs.SetValues(-1, 2, 3);

the TypeScript compiler cannot ascertain if this action alters the variables' values, thereby maintaining the initial type narrowing assumption. Consequently, subsequent comparisons appear futile since the compiler perceives x, y, and z as firmly being 2, 6, and 12 respectively.

if (lhs.x != -1 || lhs.y != -2 || lhs.z != -3) {
    throw "b";
}

Answer №3

To avoid the narrowing issue, an alternative solution is to also verify if lhs has a truthy value before proceeding with the operation.

function TestVector3() {
  var lhs = new Vector3(1, 2, 3);

  lhs.SetValues(1, 2, 3); 
  if (lhs && (lhs.x != 2 || lhs.y != 6 || lhs.z != 12)) {
    throw "a";
  }

  lhs.SetValues(-1, 2, 3);
  if (lhs && (lhs.x != -1 || lhs.y != -2 || lhs.z != -3)) {
    throw "b";
  }
}

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

Isolating a type as a constant in Typescript within a .js file?

Within my .js configuration files, I have a tsconfig containing the property checkJs: true. A library called Terser includes the following type options: ecma: 5 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 Despite setting ecma: 2017 in my configuration file ...

Issue arising from the presentation of the main object along with certain dependent objects on the table

I am encountering some difficulties with displaying a list of objects retrieved from the back-end. Here is my parent object: export class Regle { itRegle: number; isDemande: boolean; dateCreation: string; dateFinPrevu: string; descriptionRegle: ...

Error message when using TypeScript with useState hook in React for a string value within an

Hello fellow developers I am facing a Type error issue Apologies for the confusion, let me clarify my question Error in Code interface IInfo { name: string; password: string; } useState Declaration const [info, setInfo] = useState<IInfo>({ ...

Incorporate the authorization button into Swagger Documentation using NodeJS

I am looking to integrate a button in Swagger's UI interface that allows testers to easily add the "Bearer token" header and conduct API testing. https://i.sstatic.net/Dyxdc.png The configuration for my Swagger setup is as follows: module.exports = ...

Utilizing TypeScript to define the parameter of a method within a generic interface by extracting a value from the generic type

In search of defining a versatile interface that can manage any Data type, I came up with an idea. This interface includes a dataKey property which simply holds a value of keyof Data. Additionally, it features a handler function where the parameter type sh ...

Issues with displaying an image from a public Google Drive link in NextJS due to img tag not

Hello there, I recently put together my portfolio website, added all the necessary images to my Google Drive, and used the public URL as the src value in the <img /> tag. Initially, the images were loading without any problems. However, I'm now ...

Executing Numerous Post Requests concurrently from a single origin

I am currently working on a project that requires me to utilize a rest API backend server (NodeJs/Typescript) by making multiple simultaneous post requests from my frontend. Although this may seem unusual, it is a specific requirement for the project. Upo ...

Navigating back to the previous page with data in Angular 4 after switching from Angular 2

One scenario to consider is when page C features a Go Back button. On Page A, navigate to Page C with data and click the Go Back button to return to Page A with data. Similarly, on Page B, go to Page C with data and press the Go Back button to go back to ...

When attempting to retrieve and process a JSON from the internet, I encounter "undefined" errors despite the fact that the data appears correctly in the log

I'm having trouble processing the JSON data received from a server. When I attempt to use .forEach on it, I receive an error stating that the data is undefined even though the console.log shows the correct values. What could be causing this issue? Is ...

Tips for ensuring a method is not invoked more than once with identical arguments

I'm grappling with a challenge in JavaScript (or typescript) - ensuring that developers cannot call a method multiple times with the same argument. For instance: const foo = (name: string) => {} foo("ABC") // ok foo ("123") ...

There is a type error in the dynamic assignment in TypeScript. I have various data that need to be fetched from one another

const obj1 = { a: 1, b: "xx" }; const obj2 = { a: 2, b: "3", d: "hello" }; for (const key in obj1) { const _key = key as keyof typeof obj1; obj1[_key] = obj2[_key]; } x[_key] error Type 'string | number' is no ...

Using parameters and data type in Typescript

When I remove <IFirst extends {}, ISecond extends {}> from the declaration of this function, the compiler generates an error. Isn't the return value supposed to be the type after the double dot? What does <IFirst extends {}, ISecond extends { ...

Monitoring the parent's CSS attribute in Angular 2

One of my directives dynamically adds the number of pixels corresponding to its parent element's right CSS attribute. import { Directive, ElementRef, AfterViewInit } from "angular2/core" @Directive({ selector: "[d]" }) export class Positioni ...

Struggling to translate JavaScript code into Typescript

Currently in the process of converting my JavaScript code to Typescript, and encountering an error while working on the routes page stating Binding element 'allowedRoles' implicitly has an 'any' type. ProtectedRoutes.tsx const Protecte ...

Utilizing Regular Expressions in Angular 4 by Referencing Patterns Stored in an Object

I'm facing an issue where my code is functional, but I keep encountering a Tslint error that's proving difficult to resolve. This particular configuration worked fine with Angular 1, but now I'm in the process of migrating the application to ...

What could be causing FormArrayName to consistently display as undefined in my HTML code, even when the safe-navigation operator is employed

Currently, I'm referring to the Angular Material example found at https://angular.io/api/forms/FormArrayName Upon initializing the packageForm formGroup in ngOnInit() and logging it in the console during ngAfterViewInit(), I can see that the translat ...

Getting observable subscriptions results in undefined

One of the services in my application utilizes a dictionary to store HTTP responses, mapping an ID to a specific URL. import { HttpClient} from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable, of ...

Error: Module not found in Visual Studio TypeScript

I am currently utilizing Visual Studio Professional 2015 to work on an application that incorporates Angular 4, TypeScript, and Webpack. Our team's goal was to enable the ability to import from both directories and files. For instance, within our pro ...

How can we send a parameter to a subscribe function for retrieving the contents of an assets file in TypeScript and Ionic 3?

When working in TypeScript, I have discovered a way to retrieve the content of a text file from my assets directory using the following code: this.http.get('assets/data/file_1.txt') .subscribe(data=>{ let obj = data['_body']; ...

What is the best way to merge the results of several runs of an observable function

When working with Firestore, I need to retrieve multiple documents, each with a unique sourceAddressValue. This means for a list of N strings, I may need to fetch N documents. I attempted the following approach: getLocationAddresses(addresses: string[]) { ...