Using optional function arguments with destructured arguments in TypeScript can result in throwing an error

interface Type1 {
  attr1: string;
  attr2: string;
}
interface Type2 {
  attr1: string;
  attr2: string;
  attr3: string; // additional attribute
}

function fn(config: Type1 | Type2): void {
  // The error code is displayed above. I am aware that one solution is to add an optional attribute to 'attr3'. However, in my opinion, this solution is not ideal. In reality, there are only two possible situations - either 'Type1' or 'Type2'. Therefore, making the attribute optional does not improve readability. Is there a more advanced way to resolve this issue?</p>

Answer №1

You can easily verify the existence of attr3 in the object.

function fn(config: Type1 | Type2): void {
  if ('attr3' in config) {
    const {
      attr1,
      attr2,
      attr3
    } = config;
  } else {
    const {
      attr1,
      attr2
    } = config;
  }
}

Alternatively, you could utilize a custom type guard

function IsType2(config: Type1 | Type2): config is Type2 {
  return (config as Type2).attr3 !== undefined;
}

function fn(config: Type1 | Type2): void {
  if (IsType2(config)) {
    const {
      attr1,
      attr2,
      attr3
    } = config;
  } else {
    const {
      attr1,
      attr2
    } = config;
  }
}

If we really only wanted to destructure once, we could create a join type, although it would involve coercing the type instead of inferring it.

function fn(config: Type1 | Type2): void {
  const {
    attr1,
    attr2,
    attr3
  } = config as Type1 & Type2;
}

To my knowledge, there isn't a direct way to destructure a union type.

Answer №2

To achieve the same outcome when missing the attr3 attribute as you would with JavaScript code, simply convert the config type to an intersection of types:

interface Type1 {
  attr1: string;
  attr2: string;
}
interface Type2 {
  attr1: string;
  attr2: string;
  attr3: string; // extra attribute
}

type UnionToIntersection<U> = 
  (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never

function fn(config: Type1 | Type2): void {
  // Property 'attr3' does not exist on type 'Type1 | Type2'.ts(2339)
  const { attr1, attr2, attr3 } = config as UnionToIntersection<Parameters<typeof fn>[0]>;
  console.log(attr1);
  console.log(attr2);
  console.log(attr3);
}

fn({ attr1: '', attr2: '' })

Alternatively, you can use

... = config as Type1 & Type2;
if some rigidity is acceptable.

Visit TS playground for more details.

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

Preact: occasional occurrence of a blank page after refreshing

Starting out with Preact & TypeScript, I decided to kickstart my project using the parcel-preact-typescript-boilerplate. Initially, everything seemed to be working smoothly. However, I noticed that occasionally, especially on reload or initial page lo ...

What sets apart the typescript@latest and typescript@next NPM packages from each other?

Can you enlighten me on the disparities between typescript@next and typescript@latest? I understand the functionality of typescript@next, yet I struggle to differentiate it from typescript@latest. From my perspective, they appear to be identical. There is ...

Enhancing data validation and converting strings to dates with Nest.js - DTO approach

Anticipating the upcoming request to adhere to the ISO 8601 standard timestamp format, something similar to "2023-12-04T15:30:00Z" (typically embedded as a string within JSON data that needs conversion to a JavaScript Date object). This is my Data Transfe ...

What is the best way to transform a string into emojis using TypeScript or JavaScript?

Looking to convert emoji from string in typescript to display emoji in html. Here is a snippet of the Typescript file: export class Example { emoji:any; function(){ this.emoji = ":joy:" } } In an HTML file, I would like it to dis ...

Difficulty fetching data on the frontend with Typescript, React, Vite, and Express

I'm currently working on an app utilizing Express in the backend and React in the frontend with typescript. This is also my first time using Vite to build the frontend. While my APIs are functioning correctly, I am facing difficulties fetching data on ...

Learning to utilize the i18n library with React Vite

The developer console is showing the following message: i18next::translator: missingKey en translation suche suche Here is the file structure of my project: vite.config.ts i18n.js test/ src/ components/InputSearch.tsx routes/ public/ de/translation. ...

I need help with querying the date format in Mongoose and MongoDB. The specific date I am trying to query is stored in the field "ticketTimeStartDate" and is in the format: "Mon Oct 18 2021 12:28:59 GMT+0000 (

Can anyone provide guidance on querying this specific date format in moongose and MongoDB? The date field is as follows: "ticketTimeStartDate": "Mon Oct 18 2021 12:28:59 GMT+0000 (Coordinated Universal Time)", ...

Tips for concealing a parent within a complexly nested react router structure

Is there a more efficient way to conceal or prevent the rendering of parent content within a react router object? I could use conditional rendering, but I'm unsure if that's the optimal solution. My setup involves a parent, child, and grandchild, ...

Guide to creating two-way data binding using ngModel for custom input elements like radio buttons

I am currently facing an issue with implementing a custom radio button element in Angular. Below is the code snippet for the markup I want to make functional within the parent component: <form> <my-radio [(ngModel)]="radioBoundProperty" value= ...

TypeScript enables the use of optional arguments through method overloading

Within my class, I have defined a method like so: lock(key: string, opts: any, cb?: LMClientLockCallBack): void; When a user calls it with all arguments: lock('foo', null, (err,val) => { }); The typings are correct. However, if they skip ...

Error message: "Mismatched data types in Formik errors when utilizing TypeScript"

I have a customized input component for formik which includes an error label if one exists. When I print it like this: {errors[field.name]}, it works. However, {t(errors[field.name]?.toLocaleString())} does not work. import { FieldProps, FormikErrors } ...

Experiencing unfamiliar typescript glitches while attempting to compile a turborepo initiative

I have been utilizing the turborepo-template for my project. Initially, everything was running smoothly until TypeScript suddenly started displaying peculiar errors. ../../packages/fork-me/src/client/star-me/star-me.tsx:19:4 nextjs-example:build: Type erro ...

The issue lies within typescript due to process.env.PORT being undefined

I am a newcomer to working with TypeScript. Even after importing and using the dotenv package, I am still encountering issues with getting undefined values. Do I need to declare an interface for the dotenv variables? import express,{Application} from &apo ...

Facing an issue with the TypeScript error in the Tailwind-Styled-Component Npm package. Any suggestions on how to troub

module.styles.ts File import tw from "tailwind-styled-components"; export const Wrapper = tw.div` bg-green-500 `; export const Link = tw.a` text-blue-500 `; home.jsx File import React from "react"; import { Wrapper, Link } from &qu ...

Convert individual packages within the node_modules directory to ES5 syntax

I am currently working on an Angular 12 project that needs to be compatible with Internet Explorer. Some of the dependencies in my node_modules folder are non es5. As far as I know, tsc does not affect node_modules and starts evaluating from the main opti ...

Guide to verifying a value within a JSON object in Ionic 2

Is there a way to check the value of "no_cover" in thumbnail[0] and replace it with asset/sss.jpg in order to display on the listpage? I have attempted to include <img src="{{item.LINKS.thumbnail[0]}}"> in Listpage.html, but it only shows the thumbna ...

Can you provide guidance on how to specifically specify the type for the generics in this TypeScript function?

I've been diving into TypeScript and experimenting with mapped types to create a function that restricts users from extracting values off an object unless the keys exist. Take a look at the code below: const obj = { a: 1, b: 2, c: 3 } fun ...

Can someone show me how to properly set up nested child routes in Angular 2?

My application structure is organized as shown below . ├── photos ├── posts ├── users │   ├── detail │   │   ├── address │   │   ├── family │   │   ├── information │   │   └ ...

Tips for accessing other environment variables within the environment.ts file in an Angular project

Currently, I am working on modifying the 'environment.ts' file within an Angular project to include additional properties. The current setup looks like this: export const environment = { production: false, apiUrl: 'http://example.com&ap ...

Tips for showing a DialogBox when a blur event occurs and avoiding the re-firing of onBlur when using the DialogBox

Using React and Material UI: In the code snippet provided below, there is a table with TextFields in one of its columns. When a TextField triggers an onBlur/focusOut event, it calls the validateItem() method that sends a server request to validate the ite ...