What steps should I take to generate a compiler error when a variable is not of the type "never"?

Imagine having a set of conditions with different possible values and wanting to cover each potential case. In the event of adding a new condition in the future but forgetting to handle it, it is important to have an error detection mechanism—ideally catching errors before deployment rather than at run-time.

The question arises: How does one verify that a variable belongs to the type never?

type Task = { type: 'update'; payload: any } | { type: 'delete'; payload: any }

const handleTask = (task: Task) => {
  const update = (task: Task) => {
    console.log(task)
  }
  const del = (task: Task) => {
    console.log(task)
  }

  if (task.type === 'update') {
    update(task)
  } else if (task.type === 'delete') {
    del(task)
  } else {
    // The variable 'task' is essentially of type 'never' here,
    // This throws an error only if more types are added to the `Task.type` definition.
    throw new Error(`Unhandled task.type "${(task as Task).type}".`)
  }
}

Answer №1

To ensure that a function never returns a value, you can create a function that accepts an argument of the 'never' type. This tells the compiler not to expect the function to be called. Typically, this function is named assertNever(). Here's an example implementation:

function assertNever(x: never, msg?: string): never {
  throw new Error(msg ?? "unexpected value " + String(x));
}

If this function does get called, it will result in a runtime error. You can use assertNever in your code to handle unexpected scenarios.

For instance, if you add a new job type and forget to handle it in your code, the compiler will catch this mistake for you:

type Job =
  { type: 'add'; payload: any } |
  { type: 'send'; payload: any } | 
  { type: 'explode' }; // new job type

Now, when trying to process the new job type without handling it correctly, an error will occur which alerts you to address this issue by adding proper handling mechanisms.

Try out the code on TypeScript Playground

Answer №2

To create a custom error type that expects an argument of type never, you can extend the built-in Error class:

class NeverError extends Error {
  constructor(check: never) {
    super(`NeverError received unexpected value ${check}, type should have been never.`)
    this.name = 'NeverError'
  }
}

In case the code reaches a certain point, you can throw this custom error. If the variable job is not of type never, it will result in a compile-time error:

if (job.type === 'add') {
  add(job)
} else if (job.type === 'send') {
  send(job)
} else {
  throw new NeverError(job)
}

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

navigating through different pages on a react-native application

While building my app in react-native, I encountered some issues with setting up the navigation. I referred to the react-native documentation for guidance, specifically this navigation guide. The guide mentioned passing an object named "navigation" to your ...

Retrieve the product IDs by selecting the checkboxes, then compile a fresh array consisting of the identified IDs

I am currently delving into the realm of typescript/angular2+ as a fledgling student, and I have taken on the task of creating a website to put my newfound knowledge to the test. The view is up and running, but I'm facing some roadblocks as I work on ...

Angular - Executing a function in one component from another

Within my Angular-12 application, I have implemented two components: employee-detail and employee-edit. In the employee-detail.component.ts file: profileTemplate: boolean = false; contactTemplate: boolean = false; profileFunction() { this.profileTempla ...

Can a TypeScript function be structured to return never (or throw) if a generic type extends a subtype without requiring casting?

(This code snippet is purely for demonstration purposes, as no real use-case exists here) I am attempting to create a function that throws an error if the input string is equal to "fish". I have achieved this using the as keyword, but I am curious if ther ...

The protractor tool is unable to recognize an Angular component when it is displayed on the page

I have implemented end-to-end (e2e) testing on my project, but I am facing issues that are causing my tests to fail. Below is a snippet of my app.po.ts file: import { browser, by, element } from 'protractor'; export class AppPage { public b ...

Struggling with TypeScript Errors while Extending Theme Colors in Material UI React using TypeScript

Just started with typescript and feeling a bit lost, can someone offer some guidance? I'm working on a React project using material-ui with typescript. To add a new color the correct way, it needs to be added to a theme: const theme = createMuiTheme({ ...

Typescript's default string types offer a versatile approach to defining string values

Here is an example code snippet to consider: type PredefinedStrings = 'test' | 'otherTest'; interface MyObject { type: string | PredefinedStrings; } The interface MyObject has a single property called type, which can be one of the ...

How to remove a variable definition in Typescript

Is there a way to reset a variable to undefined after assigning it a value? To check, I am using the Underscore function _.isUndefined(). I have attempted both myVariable = undefined and delete myVariable without success. ...

What is the best way to incorporate a @types module into a TypeScript file that is not already a module?

Setting the Stage: In the process of shifting a hefty ~3,000 line inline <script> from a web-page to a TypeScript file (PageScripts.ts) to be utilized by the page through <script src="PageScripts.js" defer></script>. This script entails ...

Leveraging Angular 4-5's HttpClient for precise typing in HTTP requests

Utilizing a helper service to simplify httpClient calls, I am eager to enforce strong typing on the Observable being returned. In my service where I utilize the api Service and attempt to obtain a strongly typed observable that emits: export class ApiU ...

Ways to disperse items within another item

I have an inner object nested inside another object, and I am looking to extract the values from the inner object for easier access using its id. My Object Resolver [ { _id: { _id: '123456789', totaloutcome: 'DONE' }, count: 4 }, { ...

Defining Array Types in TypeScript JSON

My attempt at coding a class in TypeScript has hit a roadblock. Whenever I try to utilize Jsons in an Array, the system crashes due to a TypeScript error. Here's the class I tried to create: class Api { url: string | undefined; credentials: Ar ...

What causes TypeScript to convert a string literal union type to a string when it is assigned in an object literal?

I am a big fan of string literal union types in TypeScript. Recently, I encountered a situation where I expected the union type to be preserved. Let me illustrate with a simple example: let foo = false; const bar = foo ? 'foo' : 'bar' ...

What steps should I take to resolve the issue of my endpoint failing to accept POST requests?

I am in the process of developing a customized API, with an endpoint that is specified as shown below: https://i.stack.imgur.com/sZTI8.png To handle the functionality for this endpoint, I have set up a Profiling Controller. Inside my controller directory ...

Decorator in React that automatically sets the display name to match the class name

Is there a way to create a decorator that will automatically set the static property displayName of the decorated class to the name of the class? Example usage would be: @NamedComponent class Component extends React.Component { \* ... *\ } ...

Validate prop must consist of one of two functional components

I am looking to ensure that a prop can only be one of two different components. Here is what I currently have: MyComponent.propTypes { propA: PropTypes.oneOfType([ PropTypes.instanceOf(ClassComponentA) PropTypes.instanceOf(ClassCompon ...

Displaying a segment of information extracted from a JSON array

I'm currently tackling a project that involves using React, Redux, and TypeScript. Within the JSON file, there is a key-value pair: "data_start": "2022-09-02" Is there a way to display this date in a different format, specifical ...

What is the best way to integrate the Telegram login widget into an Angular application?

Does anyone know how I can integrate the Telegram login widget into my Angular application without resorting to hacks? The required script is as follows: <script async src="https://telegram.org/js/telegram-widget.js?5" data-telegram-login="bot_name" ...

What could be causing my Vue code to behave differently than anticipated?

There are a pair of components within the div. When both components are rendered together, clicking the button switches properly. However, when only one component is rendered, the switch behaves abnormally. Below is the code snippet: Base.vue <templa ...

What is the reason for not requiring checks with Union Types when utilizing a variable, yet necessitating them within a function?

Currently working on some Typescript challenges and encountered a scenario involving a union type. In this example, the function getIstanbulPostalCode is declared to return either a string or a number: function getIstanbulPostalCode(): string | number { ...