What is the significance of needing to add a question mark to the TypeScript `never` type when working with

This piece of code effectively enforces the conditional requirement for the isDirty field to be included in a lecture object:

  • If the id is a string, then an isDirty field must be added to the object:
  • If the id is a number, then the object cannot have an isDirty field.
type LectureT = LectureIdT & {
  title: string;
};

/**
 * If `id` is a string, Lecture must have an `isDirty` field. If `id` is a number, there should be no `isDirty` field.
 */
type LectureIdT =
  | { id: string; isDirty: boolean }
  | { id: number; isDirty?: never };
  

const lectureMockWithNumberId: LectureT = {
  id: 1,
  title: 'Lecture 1',
  // isDirty: false, // Uncomment to see error
};

const lectureMockWithStringId: LectureT = {
  id: "1",
  title: 'Lecture 2',
  isDirty: false,
};

You can experiment with this code on the following TS Playground.

The Question: Why is the question mark necessary in isDirty?: never?


My Findings:

After removing the question mark from isDirty?: never to make it isDirty: never, the code stops functioning as expected:

type LectureIdT =
  | { id: string; isDirty: boolean }
  | { id: number; isDirty: never };

An error in TypeScript appears for lectureMockWithNumberId:

Type '{ id: number; title: string; }' is not assignable to type 'LectureT'.
  Type '{ id: number; title: string; }' is not assignable to type '{ id: number; isDirty: never; } & { title: string; }'.
    Property 'isDirty' is missing in type '{ id: number; title: string; }' but required in type '{ id: number; isDirty: never; }'.

The error message indicates that isDirty is required, which seems incorrect since its type is

never</code - meaning it should never be required, right?</p>
<p>I am puzzled by why adding the question mark makes it work. It feels counterintuitive.</p>
<p>To make sense of it, I tried changing it to <code>isDirty: never | undefined
:

type LectureIdT =
  | { id: string; isDirty: boolean }
  | { id: number; isDirty: never | undefined };

To my surprise, the error persists! Doesn't the ? in something like a?: string equate to a: string | undefined?

This confusion arises from:

  1. ...the necessity of the question mark ? in isDirty?: never and the supposed impossibility of isDirty: never;.
  2. ...the different behavior exhibited by ? when used alongside never.

Answer №1

Let's break down these questions individually:

In the last sentence, it states that isDirty is required. However, this doesn't seem accurate to me! The type is never, so shouldn't it never be required?

The never type doesn't have any unique behavior when it comes to optional object properties. You can consider never just like any other type (string, number, etc.). The key distinction is that never cannot have any assignable values. Essentially, a variable of type never can never hold a valid value.

I'm puzzled as to why the error persists! Doesn't the ? in something like a?: string mean a: string | undefined?

No, there is a clear distinction between the objects {} and {a: undefined}. In one scenario, the key is entirely missing, while in the latter, it exists with a value of undefined. The former object can fit into {a?: string} but not {a: string | undefined}.

This brings us to the question:

Why is the question mark ? crucial here, and how is isDirty: never; essentially unattainable?

Similarly to the previous example, excluding the ? on the key name makes the key mandatory within the type. The presence of that key is necessary, yet no valid values can be assigned due to its type being never.

To summarize, it is indeed impossible without the question mark, as it creates conflicting requirements: the key must exist, but no value is permissible for it.

Lastly:

Why does ? exhibit different behavior when paired with never?

This difference stems from the inherent characteristics of never combined with the typical functionality of ?. There isn't anything exceptional about the way these two features interact.

By considering the example of {isDirty?: never}, we reach the conclusion that either:

  • The object doesn't include the isDirty key.
  • The object contains the isDirty key with a value of type never.

Given that the second scenario is implausible (as previously discussed), only the first case remains: an object meeting this type criteria should not feature the isDirty key.

Answer №2

never is referred to as the void type - it signifies that there is no value present within a never set. It is impossible to assign a value to a variable of type never. Even in situations where you declare a function like function f(): never, the return type of the function is not truly never - it is simply used to indicate that the function does not actually return, possibly due to an exception being thrown or getting stuck in an endless loop.

Aside from the scenario where a function doesn't return, there are few other practical applications for the never type.

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

Ways to retrieve all elements, including those that are hidden, within a CSS grid

My goal is to retrieve all the "Available Items" using Javascript in one go. However, I am facing an issue where not all of them are visible at once due to the need to manually scroll through a CSS grid. <div class="gridWrapper" data-dojo-attach-point= ...

Retrieve the JSON response from the server and store it in variables using jQuery's AJAX function with the `done

I am trying to retrieve a JSON response from the server upon clicking a button and then parse it into a div. However, I am struggling with how to accomplish this. <button type="submit" id="btPay" name="btPay"> Go for Pay ...

Displaying images in Dash Python by utilizing external Javascript

Dear audience, I am looking to incorporate an image on a Python Dash webpage that is created by JavaScript code. For more details, you can refer to the documentation here: . To include this script in a static HTML page, one would typically add the followi ...

The Dynamic Duo: Typescript and Knex

I'm new to TypeScript and currently working on a node application using Express, Postgresql, and Knex. I'm a bit confused about when to apply type definitions in my code. Looking at other projects for guidance has left me even more puzzled as to ...

Displaying Modal from a separate component

CardComponent: export class Card extends Component<Prop, State> { state = { isCancelModalOpen: false, }; marketService = new MarketService(); deleteMarket = () => { this.marketService .deleteMar( ...

Angular - Automatically create thumbnails for uploaded images and videos

I am working on an Angular application that allows users to upload files. My goal is to create thumbnail images for uploaded images and videos without saving them locally. Instead, I plan to pass them along with the original file data to another API. Howev ...

Activate the Flexslider when it comes into view

Currently using flexslider, I am attempting to create a smooth transition from the second slide back to the first as soon as the slider is in view. My initial idea was to implement if (scroll >= 500px && scroll < 600px) however, I am uncerta ...

Client-side condition handling in Angular 2

How can I change the icon image on a block/unblock button based on the user's active status? For example, showing an unlock image when the user is active and vice versa. Image https://i.stack.imgur.com/aM0ff.png Html <link href="../../font-aw ...

Radio button is selected but textbox does not display

Struggling to get the radio button to display the textbox as intended, but unfortunately encountering issues. Here is the HTML code in the JSP page: <%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> ...

Error occurred during the Uglify process: Unable to access the 'kind' property as it is undefined

I developed a project using TypeScript (version 3.9.3) and Node (version 10.16.3), but now I want to minify the code by converting it to JavaScript and running UglifyJS. However, after going through this process, the services that were functioning properly ...

Rotating an HTML caret using CSS does not pivot from the center point

Is there a way to adjust my simple caret rotation to make it rotate from the center? What changes should I make? const Wrap = styled.div` width: 100px; background: grey; span { display: block; transform: ${(props) => (props.isOpen ? " ...

Issue reported: "Usage of variable 'someVar' before assignment" ; however, it is being properly assigned before usage

This piece of code showcases the issue: let someVar: number; const someFunc = async () => { someVar = 1; } await someFunc(); if (someVar == 1) { console.log('It is 1'); } As a result, you will encounter ...

Ways to exchange information among Vue components?

My role does not involve JavaScript development; instead, I focus on connecting the APIs I've created to front-end code written in Vue.js by a third party. Currently, I am struggling to determine the hierarchy between parent and child elements when ac ...

How can I display a Skeleton when pressing pagination buttons and then turn it off after 3 seconds?

Here is a snippet of my code featuring the use of a Skeleton as a placeholder for CardMedia: {loading ? ( <Skeleton variant="rectangular" width={308} height={420} animation="wave" /> ) : ( <CardMedia s ...

Uncover concealed images by adjusting the opacity of the cover image during a mouse movement event

As I was working on a project, I came up with a simple code to adjust the opacity of a cover image in order to reveal a hidden image underneath. The setup involved two canvas elements stacked on top of each other, both measuring 500x500 pixels and containi ...

Using Vue.js: Implementing v-model with multiple checkboxes within a v-for loop

I'm seeking clarification on utilizing v-model with a "complex" object. Here's the code snippet in question: <v-list v-for="(facet, facetName) in getFacets" :key="facetName"> <v-list-tile-content v-for='valueFacet in facet" :key=" ...

What are the steps to accessing validation errors using express-validator?

Recently, I delved into the world of express-validator to enhance my skills. Despite going through the documentation thoroughly, there's a query lingering in my mind that might have already been addressed in the docs. My confusion arises from needing ...

Combining different types and "currying" or partial application APIs in a unique way

Here is an interface that I am working with: interface IFactory<T> extends Function { (...args: any[]): (((...args: any[]) => T)|T); } After implementing the following code snippet, an error occurred: ts] Type '((...args: any[]) => ...

How can you utilize jQuery's .post() method to send information as an object?

When I send a .post() request like this var data = $(this).serialize(); $('form').on('submit', function(event) { event.preventDefault(); $.post('server.php', data, function(data) { $('#data').append( ...

What is the process of transforming an xhr request into an angular $http request?

I've been successfully loading images using ajax with the following code. However, when trying to convert it into Angular and use $http, it's not working as expected. Original ajax code var xhr = new XMLHttpRequest(); xhr.open('GET', ...