"Exploring the Concept of Tuple Narrowing and Type

Is there anyone who can assist me in comprehending the scenario below:

export function functionThatReturnsTurpleObjects():
  | [{ a: number }, undefined]
  | [undefined, { a: number }]
 {
  if (Math.random() > 0.5) {
    return [undefined, { a: 1 }];
  }
  return [{ a: 1 }, undefined];
}

function execute1() {
  const [res1, res2] = functionThatReturnsTurpleObjects();
  if (res2) {
    return res2;
  }
  // res1 cannot be undefined and TypeScript recognizes it
  res1.a;
}

function functionThatReturnsTurpleObjectAndString():
  | [{ a: number }, undefined]
  | [undefined, string] {
  if (Math.random() > 0.5) {
    return [undefined, "1"];
  }
  return [{ a: 1 }, undefined];
}

function execute2() {
  const [res1, res2] = functionThatReturnsTurpleObjectAndString();
  if (res2) {
    return res2;
  }
  // res1 cannot be undefined but TypeScript throws error "TS18048: res1 is possibly undefined"
  res1.a;
}

Playground

I would anticipate that both scenarios should function identically.

Answer №1

The key distinction between the initial and subsequent examples lies in the return types of the functions.

  • In the first example, the return is
    [{ a: number }, undefined] | [undefined, { a: number }]
  • Conversely, the second example results in:
    [{ a: number }, undefined] | [undefined, string]

Now, your objective is to narrow down the first tuple item (index 0) based on the value of the second item (index 1). This form of control flow analysis for destructured discriminated unions was integrated in microsoft/TypeScript#46266 and unveiled with TypeScript version 4.6.

The narrowing process in the first example proceeds smoothly as examining for a truthy value (if(res2)...) effectively distinguishes { a: number } from undefined. Simply put, an entity that can be assigned to { a: number } cannot be considered as falsy.

On the other hand, an empty string (="") aligns with undefined in a boolean context due to both values being coerced to false. To tackle this scenario, a more specific if condition like res !== undefined is recommended.

function execute2() {
  const [res1, res2] = functionThatReturnsTurpleObjectAndString();
  if (res2 !== undefined) {
    return res2;
  }

  return res1.a;
  //     ^? const res1: {a: number; }
}

TypeScript Playground

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

"Exploring the method to navigate through a nested Firebase collection linked to its parent collection

I have a forum application in development where users can ask questions and receive answers, each answer having its own 'like' feature. I am trying to access the 'likes' subcollection when viewing an answer, but I am unsure of how to do ...

Navigating the thorny dilemma of catch-22 situations when dealing with parser

I'm struggling to incorporate @typescript-eslint/no-floating-promises into my ESLint guidelines. This necessitates the use of parserOptions. Below is my .eslintrc.js configuration: module.exports = { root: true, parser: '@typescript-eslint ...

Why do callbacks in Typescript fail to compile when their arguments don't match?

In my current project, I encountered a scenario where a React callback led to a contrived example. interface A { a: string b: string } interface B { a: string b: string c: string } function foo(fn: (a: A) => void, a: A) { fn( ...

I am looking for guidance on how to effectively utilize a JSON object that is stored in the constructor of my component, particularly when triggering

Below is the object I have in my constructor. I am passing a value from a previous component to the one below. I receive the item json object, but I need to use it when I click. constructor(public navCtrl: NavController, public navParams: NavParams) { ...

Problem encountered during NextJS build: ReferenceError - 'window' is undefined

While I am in the process of developing my app, I have encountered a perplexing issue with a ReferenceError: window is not defined. This error seems to be happening even though I am utilizing 'use client' "use client"; import React, { u ...

Resolve the error message "Class is not a constructor" which arises while utilizing namespaces in TypeScript with WebPack

Issue with TypeScript Namespaces in PIXI.js As I delve into the world of TypeScript and PIXI.js without any framework, I find myself facing a challenge. Previously, at work, we utilized namespaces with the module keyword for a cleaner structure. However, ...

Ways to maximize your final export value

My data file, named data.ts, contains a large dataset: export data = [ ... // huge data ] The lib.ts file only utilizes a portion of the data: import { data } from './data.ts'; const fitteredData = data.splice(0,2) // only use some of them ...

Angular 7: Polyfill required for npm package to support 'Class'

I am encountering an issue where my Angular 7-based app is not functioning in Internet Explorer 11. The npm package I am using begins in index.js: class PackageClass { // code } While the app works as intended in other browsers, it fails to open in ...

Unable to globally override the default font in MUI theme

Objective: My goal is to customize the default font in MUI themes. Issue: Despite reviewing MUI documentation and conducting research on Stack Overflow, I am facing difficulty overriding a custom font globally across my theme. Theme setup: import { creat ...

Make the text stand out by highlighting it within a div using a striking blue

Currently, I am working with Angular2 and have incorporated a div element to display multiple lines of text. Positioned below the text is a button that, when clicked, should select the entirety of the text within the div (similar to selecting text manually ...

typescript set parameter conditionally within a function

For my upcoming app, I am working on an API that will utilize Firebase FCM Admin to send messages. Below is the code snippet: import type { NextApiRequest, NextApiResponse } from "next"; import { getMessaging } from "firebase-admin/messaging ...

Angular2 Animation for basic hover effect, no need for any state change

Can anyone assist me with ng2 animate? I am looking to create a simple hover effect based on the code snippet below: @Component({ selector: 'category', template : require('./category.component.html'), styleUrls: ['./ca ...

Struggling to convert my VueJS component from JavaScript to TypeScript, feeling a bit lost

I am new to VueJS and I am facing a challenge converting my VueJS project to use TypeScript. I have been trying to bind functions to certain variables in JavaScript, but I am struggling with accomplishing the same in TypeScript. Even though there are no er ...

Managing Prisma error handling in Express

Dealing with error handling using ExpressJS and Prisma has been a challenge for me. Anytime a Prisma Exception occurs, it causes my entire Node application to crash, requiring a restart. Despite looking at the Prisma Docs and doing some research online, I ...

How can a child class access this.props within a function that overrides a parent class's function?

I am trying to access this.props.childName in the child function, which is defined within the parent function. However, I am encountering a TypeScript compile error (Property 'name' does not exist...). Strangely, if I use this.props.parentName, i ...

In Angular, you can easily modify and refresh an array item that is sourced from a JSON file by following these steps

Currently, I am working on implementing an edit functionality that will update the object by adding new data and deleting the old data upon updating. Specifically, I am focusing on editing and updating only the comments$. Although I am able to retrieve th ...

What is the best way to perform a query in Angular using Firebase Firestore?

I am attempting to execute queries in Angular 6 using Firebase Firestore. I have this code, and I have already installed the package "npm firebase @angularfire" but it is not working: import { Component } from '@angular/core'; import { A ...

Angular 2 - Dragula for ng2

<div *ngFor="let col of columns"> ... <div [dragula]="'tickets-list'" [dragulaModel]="col.tickets" (drop)="onDrop($event, col)"> <ul> <li *ngFor="let ticket of col.tickets"> {{ ticket }} </li ...

Display a React functional component

Greetings, friends! I recently created a React app using functional components and now I am looking to print a specific page within the app. Each page is its own functional component, so I was wondering if it's possible to print a component individual ...

Using Checkbox from material-UI to add and remove strikethrough on a to-do list task

const Todo: React.FC<ITodoProps> = (props) => { const [textInput, setTextInput] = useState(''); const { addTodo, userId, todosForUser, user, } = props; if (user == null) { return ( <Grid container={true} direction=&apo ...