What is the concept of NonNullable in typescript and how can it be understood

In TypeScript, the concept of NonNullable is defined as

type NonNullable<T> = T extends null | undefined ? never : T

For instance,

type ExampleType = NonNullable<string | number | undefined>;

Once evaluated, ExampleType simplifies to

type ExampleType = string | number

How does TypeScript infer ExampleType in this case? One might expect it to result in never, given that string | number | undefined extends null | undefined (isn't that correct?). But why does it give string | number instead?

In connection to this, why doesn't TypeScript use the alternative definition below?

type NonNullable<T> = Exclude<T, null | undefined>

Answer №1

Can you explain how TS infers T0 in this scenario? I was under the impression that it would return never, since string | number | undefined extends null | undefined (isn't that correct?). But how does it end up as string | number?

Consulting the documentation on the NonNullable<Type>, we find that NonNullable:

Constructs a type by excluding null and undefined from Type.

In your specific example:

type T0 = NonNullable<string | number | undefined>;

The type string | number | undefined for NonNullable is not seen as an entire type on its own, but rather a type composed of string or number or undefined. Since NonNullable excludes undefined, the final type becomes string | number.

Why doesn't TS use the alternative definition below?

While they are essentially the same, one reason might be to construct the Utility Types from scratch instead of relying on a composite type. Interestingly, some Utility types are actually built upon other Utility types. This could be for clarity purposes, as hinted in the release notes for version 2.8, where the NonNullable type was initially defined using Diff.

type NonNullable<T> = Diff<T, null | undefined>;

Answer №2

When you have a combination like string | number | never, the type never will automatically be excluded.

For instance, consider having this type: string | number | null.

Now, let's apply it to

type NonNullable<T> = T extends null | undefined ? never : T

Given that T is string | number | null, the expression

T extends null | undefined ? never : T
will result in three separate unions. Here, string, number, and null will replace T respectively, becoming
string extends ... : never : string | number extends ... : never : number | null extends ... : never : null
. The first two cases return string and number. However, the third one gives back never. In the end, we end up with a type of string | number | never, where typescript will promptly eliminate the never option

To delve deeper into this concept, check out the link here:

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

Access PDF document in a fresh tab

How can I open a PDF file in a new tab using Angular 6? I have tried the following implementation: Rest controller: @RestController @RequestMapping("/downloads") public class DownloadsController { private static final String EXTERNAL_FILE_PATH = "/U ...

Underscore.js is failing to accurately filter out duplicates with _uniq

Currently, I am integrating underscorejs into my angular project to eliminate duplicate objects in an array. However, I have encountered an issue where only two string arrays are being kept at a time in biddingGroup. When someone else places a bid that is ...

Access the $event object from an Angular template selector

<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script> <input type="file" #myFile multiple /> <button (click)="onDelete(myFile.event)">DeleteFiles</button> My code snippet is experienci ...

Next.js: Importing from a new endpoint triggers the code execution once more

Here is a simplified example I created for this specific question. Imagine I want to maintain a server-side state. components/dummy.ts console.log('initialize array') let number: number = 0 const incrementValue: () => number = () => numbe ...

React Native: Picker value remains static

I'm encountering an issue where the value of the picker does not change when I select a new value from it. This problem started occurring after I added the onValueChange function. If anyone has any insights or suggestions on how to resolve this, I wou ...

Performing an RxJS loop to retrieve the httpGet response, followed by executing httpPut and httpPost requests based

I am currently working on a UI form that allows users to update or add translation text. To achieve this, I need to create an rxjs statement that will perform the following tasks: Send an httpGet request to the database to retrieve translations in mult ...

The specified type 'IterableIterator<number>' does not belong to either an array type or a string type

Encountering an error while attempting to generate a dynamic range of numbers. Error: Type 'IterableIterator<number>' is not recognized as an array or string type. Use the compiler option '--downlevelIteration' to enable iteratio ...

Angular - optional parameter in route using ngRouter

I have a question regarding using Angular (4) with the @angular/router. I want to be able to include optional parameters in a path style, but am facing some challenges. Currently, my code looks like this: { path: 'cars', component: CarComponent ...

Aligning validation schema with file type for synchronization

Below is the code snippet in question: type FormValues = { files: File[]; notify: string[]; }; const validationSchema = yup.object({ files: yup .array<File[]>() .of( yup .mixed<File>() .required() .t ...

Ways to deduce or implement intellisense for parameter types in overloaded functions

Currently, I am developing an Electron application where numerous events are being passed around with specific listeners assigned to each event. One example is BrowserWindow.on: Electron.BrowserWindow.on(event, listener) The event can take on values such ...

Is it possible to convert a type to a JSON file programmatically?

Recently, I have been tasked with implementing configuration files for my system, one for each environment. However, when it came time to use the config, I realized that it was not typed in an easy way. To solve this issue, I created an index file that imp ...

Exploring the possibilities of TypeScript/angularJS in HTTP GET requests

I am a beginner in typescript and angular.js, and I am facing difficulties with an http get request. I rely on DefinitelyTyped for angular's type definitions. This is what my controller code looks like: module game.Controller { 'use strict& ...

Using @HostBinding based on the @Input() condition

I'm attempting to link the CSS class foo to my parent component by utilizing @HostBinding based on a condition I evaluate against a dynamic variable. However, I am struggling to get it to function as expected. Here are the different approaches I hav ...

Using both withNextIntl and withPlaiceholder simultaneously in a NextJS project causes compatibility issues

I recently upgraded to NextJS 14 and encountered an issue when deploying my project on Vercel. The next.config.mjs file in which I wrapped my nextConfig in two plugins seemed to prevent the build from completing successfully. As a workaround, I decided t ...

Error in Angular integrating with Stripe. No definition found for 'Stripe'. Perhaps you meant 'stripe'?

I'm currently in the process of connecting Stripe to my app with redirection, utilizing Angular and typescript. My component contains the following code snippet: var head = document.getElementsByTagName('head')[0]; var script = document.cre ...

What is the best way to create a TypeScript function similar to a 'map' in React?

I recently started learning TS and am having trouble typing this arrow function: const mapLikeGet = (obj, key) => { if (Object.prototype.hasOwnProperty.call(obj, key)) return obj[key] } ...

Tips for transforming an Observable stream into an Observable Array

My goal is to fetch a list of dogs from a database and return it as an Observable<Dog[]>. However, whenever I attempt to convert the incoming stream to an array by using toArray() or any other method, no data is returned when calling the retrieveDo ...

Typescript: Understanding the question mark usage on arrays

In this example, I have the basic structure of my code: let myArray: (Array<any> | null); if (cnd) { myArray = []; myArray?.push(elt); // Curious about this line myArray[0].key = value; // Questioning this line } else { myArray = null; } Wh ...

React waitforelement fails to work in conjunction with asynchronous calls

I am currently experimenting with a straightforward login form that includes an asynchronous call in React using TypeScript and classes. Here is how my component appears: import * as React from 'react'; import { LoginService } from './servic ...

What is the best way to showcase several images using Sweet Alert 2?

In the process of developing my Angular 2 application, I have incorporated sweet alert 2 into certain sections. I am looking to showcase multiple images (a minimum of two) at the same time in the pop-up. Does anyone have any suggestions on how to achieve ...