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

Improving the clarity of Jest snapshot test logs using styled from MUI

Currently, I am working with MUI v5 along with styled components and Jest snapshot testing. I am looking for a way to improve the logs generated when a snapshot test fails. Below is an example of the component I am dealing with: const styledProperties = n ...

Executing a function to erase the stored value in local storage during an Angular unit test

Looking to verify whether the localStorage gets cleared when I execute my function. Component ngOnInit() { // Logging out when reaching login screen for login purposes this.authService.logout(); } authService logout() { // Removing logged i ...

having difficulties with angular subscribing to an observable

I am currently working on a service that retrieves a post from a JSON file containing an array of posts. I already have a service in place that uses HttpClient to return the contents of a JSON file. The main objective is to display the full content of the ...

Unable to execute OAuth2 with Okta using angular-oauth2-oidc framework

Looking to create an authentication module for an Angular application using Okta as the identity provider and implementing the angular-oauth2-oidc flow. Following a guide here: . However, encountering errors when running the web app. How can I troubleshoot ...

Sharing references in React Native using TypeScript: The (property) React.MutableRefObject<null>.current is potentially null

I'm working on a React Native form with multiple fields, and I want the focus to move from one field to the next when the user validates the input using the virtual keyboard. This is what I have so far: <NamedTextInput name={&apo ...

How come I am unable to fetch classes and enums from a namespace?

When using Typescript with pg-promise, I am facing an issue where I can't import the classes and enums as I normally would. Typically, when working with a library, I import a type, use it, and everything functions properly. However, in the snippet bel ...

Utilizing Array Notation in Typescript to Retrieve Elements from Class

In my programming project, I am working with two classes: Candles and Candle. The Candles class includes a property called list, which is an array containing instances of the Candle class. class Candles { public list: Array<Candle>; } class Candl ...

Creating a split hero section view using a combination of absolute/relative CSS techniques, Tailwind, and React

I'm in the process of creating a website using Nextjs, React, and TailwindCSS, and I aim to design a Hero section that resembles the one on the following website. https://i.sstatic.net/tq3zW.png My goal is to: Have a text title and buttons on the l ...

What causes the "This page isn't responding" error to pop up in Edge and Chrome browsers while attempting to perform consecutive tasks in a web application built with Angular 8?

Trouble with Page Loading Whenever this error occurs, I find myself unable to perform any activities on that page. The only solution is to close the tab and open a new one. My current code allows me to navigate through an array list (Next and Previous) us ...

Having difficulty subscribing to multiple observables simultaneously using withLatestFrom

I am facing an issue where I have three observables and need to pass their values to a service as parameters. I attempted to do this using WithLatestFrom(), but it works fine only when all values are observables. this.payment$.pipe( withLatestFrom(this.fir ...

Nextjs 14 experiences full page loading due to the presence of multiple root layouts

The issue I'm facing involves a full page load when navigating between two root layout pages In my Next.js application (NextJS 14), I have created two root layouts. However, when moving from the first layout to the second layout, it triggers a comple ...

Parent component interacting with child component

In my application, I have a header component along with registration and login components. The selector of the header component is used in both the login and registration components. There is also a button in the header that displays as a login button if t ...

Enhancing native JavaScript types in TypeScript 1.8 with the power of global augmentation

Currently, I am working on expanding the capabilities of native JavaScript types using the new global augmentation feature in TypeScript 1.8, as detailed in this resource. However, I'm encountering difficulties when the extension functions return the ...

Ionic: Automatically empty input field upon page rendering

I have an input field on my HTML page below: <ion-input type="text" (input)="getid($event.target.value)" autofocus="true" id="get_ticket_id"></ion-input> I would like this input field to be cleared eve ...

The state is not being updated immediately when trying to set the state in this React component

Currently, I am working on a React component that is listening to the event keypress: import * as React from "react"; import { render } from "react-dom"; function App() { const [keys, setKeys] = React.useState<string[]>([]); ...

What is the proper way to access the global `angular` variable in Angular and TypeScript when using AngularJS?

I'm currently integrating an Angular 4 component into a large monolithic AngularJS application. The challenge I face lies in the restrictions of the AngularJS project's build system, which limits me to only modifying the project's index.html ...

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 ...

Loading game resources in advance for future or immediate utilization

I'm currently developing a game UI that involves a large number of image files, totaling around 30MB in size. I've been caching these images to the disk using service workers, but some of them are quite large at 3MB each. Even when they are retri ...

Angular Universal involves making two HTTP calls

When using Angular Universal, I noticed that Http calls are being made twice on the initial load. I attempted to use transferState and implemented a caching mechanism in my project, but unfortunately, it did not resolve the issue. if (isPlatf ...

Oops! An error occurred: Uncaught promise in TypeError - Unable to map property 'map' as it is undefined

Encountering an error specifically when attempting to return a value from the catch block. Wondering if there is a mistake in the approach. Why is it not possible to return an observable from catch? .ts getMyTopic() { return this.topicSer.getMyTopi ...