The data type 'string | number | null | undefined' cannot be assigned to the type 'null'

I am currently working on implementing the concept of initializing C# Class objects in a TypeScript class. However, I encountered an error message from the compiler as follows.

Error: Type 'string | number | null | undefined' is not compatible with type 'null'. Error: Type 'undefined' cannot be assigned to type 'null'

Below you can find the code snippet:

type gender = 'Male' | 'female';

class Person {
    public name: string | null = null;
    public age: number | null = null;
    public gender: gender | null = null;

    constructor(
        param: Partial<Person>
    ) {
        if (param) {

            /**
             * Checks if key exists in Person
             * @param key 
             */
            const keyExists = (k: string): k is keyof Person => k in this;

            /**
             * List of keys
             */
            const keys: string[] = Object.keys(param);

            keys.forEach((k: string) => {
                if (keyExists(k)) {
                    //k: "name" | "age" | "gender"

                    const value = param[k]; //value: string | number | null | undefined

                    //let a = this[k]; //a: string | number | null

                    this[k] = value; //error :  Type 'string | number | null | undefined' is not assignable to type 'null'.
                                    // Error :  Type 'undefined' is not assignable to type 'null'.
                }
            });

        }
    }

}

let a = new Person({
    age: 10
});

console.log(a);

Below is the content of tsconfig.json file:

{
    "compilerOptions": {
      "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
      "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
      "rootDir": "./",                       /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
      "strict": true,                           /* Enable all strict type-checking options. */
      "strictNullChecks": true,              /* Enable strict null checks. */
      "baseUrl": "./",                       /* Base directory to resolve non-absolute module names. */
      "esModuleInterop": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
    }
  }

Answer №1

There are actually two main issues with your problem:

  1. The param variable is of type Partial<Person>, meaning it may not contain all keys present in the object. This could result in encountering undefined when accessing a key that does not exist.
  2. As mentioned by @VLAZ in the comments, the compiler cannot infer the type of value on a key-by-key basis.

To address these problems, you can follow this approach:

  1. Add a type guard check to handle cases where param[k] is undefined.
  2. Manually cast the type of this[k] to match value.

In this scenario, manual type casting is reasonable and safe as you are working with keys that are guaranteed to be members of the Person class. It signals to the compiler that you are aware of the specific types involved.

The updated logic within the Array.prototype.forEach callback can be seen below:

keys.forEach((k: string) => {
  if (keyExists(k)) {
    const value = param[k];

    if (value === void 0)
      return;

    (this[k] as typeof value) = value;
  }
});

You can also refactor the code using guard clauses for better readability:

keys.forEach((k: string) => {
  if (!keyExists(k))
    return;

  const value = param[k];

  if (value === void 0)
    return;

  (this[k] as typeof value) = value;
});

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

Using the useStaticQuery hook outside of a function component is not allowed and will result in an invalid hook call error. Remember to only call

I am currently facing an issue while trying to retrieve values using useStaticQuery from my gatsby-config.js file. Below are snippets of my code. Does anyone have any suggestions on how to resolve this problem? Thank you in advance. Repository: https: ...

Ensure that a particular value is present in an array by using TypeScript

I am facing an issue with the following array: [ about: "INVALID" team: "VALID" ] My goal is to determine if the array contains any value of INVALID and return false if it does. Here is the code snippet I have attempted: if (this.forms.indexOf(& ...

Creating a TypeScript interface that inherits properties from another interface is a powerful way to define

My question pertains to a programming interface I have created called PersonInterface. Within this interface, I have included a property called 'address' which has a type of AddressInterface - another interface that I have defined. I am wondering ...

Combining multiple rows with Exceljs in an Angular application

Recently, I have been utilizing exceljs for generating and downloading Excel files. However, I've encountered a challenge in organizing them in groups similar to this: Check out this example of grouping Is there a way to achieve this using exceljs? I ...

Can a unique intrinsic type be created from scratch?

Ever since template literals were introduced in Typescript (PR), we've had access to various useful functions in our types: Uppercase Lowercase Capitalize Uncapitalize For more information, refer to the official documentation. Although it may seem ...

The close button in Angular 4 is unresponsive until the data finishes loading in the pop-up or table

Having trouble with the Close button in Angular 4 popup/table The Pop Up is not closing after clicking anywhere on the screen. I have added backdrop functionality so that the pop-up closes only when the user clicks on the close icon. However, the close i ...

Using TypeScript with Visual Studio Code to reference a renamed file

I recently changed the name of a file from FooBar.ts to fooBar.ts. Despite updating the file name, VS Code continues to refer back to the old file. In order to resolve this issue, I disabled forceConsistentCasingInFileNames in the tsconfig.json file. Howev ...

The 'toBeInTheDocument' property is not found on the 'Matchers<HTMLElement>' type

Having trouble setting up testing for a components library. Despite trying various examples and similar threads, I have not been successful. I can confirm that my setupTests.ts file is being loaded correctly (verified through a console.log). Additionally, ...

Is it possible to turn off Angular CLI ng build linting for a specific directory?

I am facing an issue with a specific directory in my project template that I want to exclude from linting. Despite excluding it in both tsconfig and eslint, running eslint works fine but when using ng build, the directory is still included in linting and e ...

Easy steps for importing node modules in TypeScript

I'm currently navigating the world of TypeScript and attempting to incorporate a module that is imported from a node module. I have chosen not to utilize webpack or any other build tools in order to maintain simplicity and clarity. Here is the struct ...

Is there a way for Ionic to remember the last page for a few seconds before session expiry?

I have set the token for my application to expire after 30 minutes, and I have configured the 401/403 error handling as follows: // Handling 401 or 403 error async unauthorisedError() { const alert = await this.alertController.create({ header: 'Ses ...

Issue with API and Middleware: unable to access /api/auth/providers

Currently, I am following an educational video tutorial on Next Auth V5. Despite being a beginner in coding, I am doing my best to keep up. I am currently stuck at 2 hours, 9 minutes, and 45 seconds into the 8-hour-long video. The issue arises during th ...

Locate a class using an interface

Consider the code snippet below: interface FirstInterface {} interface SecondInterface {} interface ThirdInterface {} class TheClass { constructor(howdy: FirstInterface) {} } class Foo implements FirstInterface {} class Bar implements SecondInterface ...

Breaking down large reducer into smaller reducers

I am currently working on a feature reducer (slice reducer) called animals. My goal is to separate these reducers into categories such as mammals, birds, fishes, and more. Initially, I thought this would be a smooth process using the ActionReducerMap. How ...

Incorporate a personalized Material UI checkbox within a column of the Material React table

Starting out with React, I decided to incorporate Material React Table v2 into my project. My goal is to include a Material UI checkbox that accurately represents the 'Is Active' data in a disabled state. Despite numerous attempts, I have not bee ...

Typescript's identification of a dispute between RequireJS and NodeJS definitions

I obtained the Typescript RequireJS definition from Definitely Typed. It includes an ambient declaration of Require that clashes with the NodeJs command "require". See below for the declaration and the error message: Declaration: declare var require: Req ...

The function encounters an undefined array when called, despite the array being defined outside of the

Encountering an issue where an array I initiate is suddenly undefined within a function. Here is the code snippet: import { Component, OnInit } from '@angular/core'; import { text } from '@angular/core/src/render3'; import{SheetModel} ...

Retrieve the outermost shell of the VUEjs wrapper test-utils

While working on a VueJS test, I encountered an issue where accessing the outermost layer of HTML seemed impossible. No matter what methods I tried, the outermost layer was always ignored. Is there a way to gain access to this outermost layer so that I c ...

Encountering Error 203 while trying to establish a connection between Angular and Django Rest Api

I'm currently working on a project that involves creating a contacts system, but I've been encountering errors when trying to list them. Interestingly, I can successfully perform CRUD operations using Postman with the API. One of the messages I ...

Disable inline imports when implementing an interface in vscode by selecting the "Implement interface" option

When using TypeScript, if I perform an auto-fix on a class name by selecting "Implement interface", it will generate the methods with inline imports like this: getInbox(): Observable<import('../../model/Message').Interactions[]> { t ...