Exploring the concept of the never type in TypeScript 2

Exploring the latest features in TypeScript 2.0, I came across the never type. It appears to be a clever method for defining the type of functions that do not have a return value.

If I understand correctly, the never type can be assigned to any other type, but only never itself can be assigned to never. While experimenting with a simple test in VS Code, I encountered the following scenario:

function generateError(){
    throw new Error("oops");
}
function do(option: "opt1" | "opt2"){
    if(option === "opt1") return true;
    if(option === "opt2 ) return false;
    generateError();
}
let res = do("blah");

What type is expected for res? The compiler indicates string | undefined, which does make sense although I initially anticipated just string. I wonder about the necessity of introducing a new type solely for functions that never return. Is this concept truly essential? Or is it primarily a tool for the compiler to enhance flow analysis?

Answer №1

It is crucial to note that this specific section should not be accessible. Take, for example, the following code snippet:

function do(): never {
    while (true) {}
}

This code contains an infinite loop, which we want to avoid iterating indefinitely.

However, a pertinent question arises: how can this concept be beneficial to us? One possible application is in defining more advanced types to specify what they are not.

For instance, let's define our own NonNullable type:

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

In this scenario, we check if T is either null or undefined. If it is, we indicate that it should never occur. Subsequently, when utilizing this type:

let value: NonNullable<string>;
value = "Test";
value = null; // error

Answer №2

By utilizing the never keyword, you can guarantee that no function contract goes unnoticed.

function eternal(): never {
    while (true) {
        break; // An error occurs if attempting to exit this function.
    }
}

enum Options {
    X,
    Y
}

function decide(option: Options) {
    switch (option) {
        case Options.X: return "X";
    }

    let y: never = option; // Generates an error as Y is not accounted for in the switch statement.
}

Answer №3

Functions that do not return and functions that may throw exceptions are different concepts.

For instance:

function foo(option: "opt1" | "opt2"): string | undefined {
  if (option === "opt1") return true;
  if (option === "opt2") return false;
  throw new Error("unknown option");
}

function bar(option: "opt1" | "opt2"): never {
  while (true) {
    doOption(option);
  }
}

The first function might return a value, so its return type cannot be never. If it can return something, then it is not considered as never returning.

The second function will truly never return anything. It doesn't matter what conditions you put in, it will not return a value or even undefined.

There are cases where functions seem like the second one but actually belong to the first category, especially when exceptions are thrown or when using process.exit in node.js, which terminates the process.

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

Consolidating repeated data objects found in the response

After receiving an API response, the data looks like this: response = [ { id: 1, val: 'A', date: '28/03/2021', versions: [] }, { id: 1, val: 'B', date: '29/03/2021', versions: [] }, { id: 1, val: 'C', ...

Troubleshooting problem with fetching data from Angular API

Looking to use Angular to extract a specific value from the following API: Current code snippet being utilized: app.controller("api", function($scope, $http) { $scope.home = "This is the homepage"; $scope.getRequest = function() { console. ...

Adapting imports in Typescript for seamless npm distribution

Currently, I'm facing an issue with module resolution while compiling my NPM package written in Typescript for publishing. In my project, I've been using non-relative imports to avoid the hassle of excessive ../../../. However, according to TypeS ...

Encountering issues with managing CometD channels within Angular 2

After dabbling in Angular2 and Typescript, I decided to challenge myself by creating an application using plain javascript with the CometD library. The goal of this app was to retrieve data from a CometD channel and present it to the user in some way. So, ...

Exploring the functionality of multiple checkboxes in Next.js 14, the zod library, shadcn/ui components, and react-hook

I'm currently working on a form for a client where one of the questions requires the user to select checkboxes (or multiple checkboxes). I'm still learning about zod's schema so I'm facing some challenges in implementing this feature. I ...

I'm having trouble configuring the header in my Node/Express route

Using Node and the Express framework for my backend, along with React for my frontend, all coded in Typescript. The elastic search client is responsible for fetching data on the backend, but I don't believe that's where the issue lies. I'm ...

Error in TypeScript: Objects can only specify properties that are known, and 'state' is not found in type 'Partial<Path>'

As I strive to pass props through a React Router Link, my goal is to include all the user props. The code below is causing an error, particularly where state: {...employee} is highlighted. Although I am relatively new to TypeScript, I am actively working ...

Using [file_id] as a dynamic parameter in nextjs pages

I am working with a nextjs-ts code in the pages/[file_id].tsx file. import Head from 'next/head'; import Script from 'next/script'; import Image from 'next/image'; import Link from 'next/link'; import { NextApiReques ...

Is there a feature in VS Code that can automatically update import paths for JavaScript and TypeScript files when they are renamed or

Are there any extensions available for vscode that can automatically update file paths? For example, if I have the following import statement: import './someDir/somelib' and I rename or move the file somelib, will it update the file path in all ...

What is the correct way to interpret a JSON file using TypeScript?

Encountering Error Error TS2732: Cannot locate module '../service-account.json'. It is suggested to use the '--resolveJsonModule' flag when importing a module with a '.json' extension. import serviceAccountPlay from '../ ...

Declaring TypeScript functions with variable numbers of parameters

Is it possible to define a custom type called OnClick that can accept multiple types as arguments? How can I implement this feature so that I can use parameters of different data types? type OnClick<..> = (..) => void; // example usage: const o ...

Exploring ways to exclude a column in a TypeORM entity while also providing the flexibility to make it optional for retrieval using the Find method

import {Entity, PrimaryGeneratedColumn, Column} from "typeorm"; @Entity() export class User { @PrimaryGeneratedColumn() id: number; @Column() name: string; } i prefer not to include the password here as I want it to be returned to the client: ...

Is it possible to integrate TypeScript 5.0 decorators into React components?

Every time I add decorators to my class, they always get called with the arguments specified for legacy decorators: a target, property key, and property descriptor. I am interested in using TypeScript 5.0 decorators. Is this feasible, and if so, how can I ...

Web application experiences freezing issues when utilizing specific components in certain situations

Currently, I am in the process of developing a web application using Angular. In this project, there is a parent component and multiple child components that receive data from an rxjs Subject. One of the child components is being used in another section o ...

Application built with Electron and Typescript encounters module-related crash

While working on developing a client using Electron with Typescript, I encountered the following error: The configuration in tsconfig.json looks like this: { "compilerOptions": { "target": "es5", "lib": [ ...

The function 'makeDecorator' does not support function calls when being accessed

Resolved by @alexzuza. Check out his solution below - major props! The issue was with the node_modules folder in the ng2-opd-popup directory, it needed to be removed and the src/tsconfig.app.json file had to be adjusted accordingly. Make sure to also refer ...

Utilize a function to wrap the setup and teardown code in Jest

I am attempting to streamline some common setup and teardown code within a function as shown below: export function testWithModalLifecycle() { beforeEach(() => { const modalRootDom = document.createElement('div') modalRootDom.id = M ...

When clicking initially, the default input value in an Angular 2 form does not get set

I am currently learning angular2 as a beginner programmer. My goal is to create a form where, upon clicking on an employee, an editable form will appear with the employee's current data. However, I have encountered an issue where clicking on a user f ...

Creating instance methods in a TypeScript object can be accomplished by defining the methods within the object's class definition. When the object is

As a seasoned Java developer, I've recently been dabbling in TypeScript. Let me introduce you to my user object: export class User { id: string; name: string; email?: string; unit: string; street: string; postalcode: string; ...

An optional field has been identified as ng-invalid

In my set-up, I have created a form group using reactive forms. this.transactionForm = fb.group ({ 'location': [null, Validators.required], 'shopper': [null], 'giftMessage': [null], 'retailPrice& ...