Using .map() with a union type of string[] or string[][] results in a syntax error

interface Props {
    data: string[] | string[][];
}

function Component({ data }: Props) {
    return data.map(v => v);
}

map() is causing an error: The expression is not callable. Each member of the union type '((callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[]) | ((callbackfn: (value: string[], index: number, array: string[][]) => U, thisArg?: any) => U[])' has signatures, but none of them are compatible with each other. (2349)

What could be the reason for this and how can I resolve it?

TypeScript Playground Link

Answer №1

One drawback of TypeScript is its limitation when working with a union of two arrays:

string[] | number[]

In this scenario, it is not possible to execute any method on the union. The solution is to separate the union into distinct arrays.

Approach one

interface Props {
    data: string[] | string[][];
}

function isString(arg: any): arg is string {
    return typeof arg === 'string'
}

function isStringArray(arg: any): arg is string[] {
    return Array.isArray(arg) && arg.every(isString);
}

function Component({ data }: Props) {
    if (isStringArray(data)) {
        data.map(str => str)
    } else {
        data.map(strArr => strArr);
    }
}

Approach two

Consider utilizing a generic version.

interface Props<T> {
    data: T[];
}

function Component<T extends string | string[]>({ data }: Props<T>) {
    return data.map(v => v);
}

Answer №2

The challenge lies in the fact that the Array<T>.map function has a union type, which means it can be:

function foo({ data }: Props) {
  // x has the type:
  // (<U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[]) | 
  // (<U>(callbackfn: (value: string[], index: number, array: string[][]) => U, thisArg?: any) => U[])
  let x = data.map;
}

This union represents different functions, not a single function with unioned parameters.

If the definition were structured like this:


function otherMap<U>(
  data: string[] | string[][],
  callbackfn:
    (value: string | string[], index: number, array: string[] | string[][]) => U,
  thisArg ?: any
): U[] {
  // ...
}

You could consider implementing a type guard or creating a custom function tailored to your specific needs, instead of relying on Array.map.

One approach using a type guard is demonstrated below:


function bar({ data }: Props) : string[] | string[][] {
  if (isMultiDimArray(data)) {
    return data.map(z => z);
  }

  return data.map(z => z);
}

function isMultiDimArray<T>(data: T[] | T[][]): data is T[][] {
  if (data.length == 0) return false;

  var firstItem = data[0];
  return Array.isArray(firstItem);
}

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

Is there a way for me to showcase a particular PDF file from an S3 bucket using a custom URL that corresponds to the object's name

Currently, I have a collection of PDFs stored on S3 and am in the process of developing an app that requires me to display these PDFs based on their object names. For instance, there is a PDF named "photosynthesis 1.pdf" located in the biology/ folder, and ...

Possible undefined object in React Redux

I'm encountering a Typescript issue where Redux object I am utilizing is potentially undefined, even though I have not specified its type as potentially being undefined or set it to be undefined anywhere in my code. /redux/globalSettings/actions.ts ...

The table component in Primeng is encountering issues when being used with ngFor

I'm attempting to iterate through an array where each object represents a table in HTML, and it should be displayed like this: <p-table [value]="section" *ngFor="let section of sections"> <ng-template pTemplate="header"> <t ...

Tips for Dealing with Empty Rows in Arrays

How can I remove rows from an array in Alasql where all key values are null? Here is the array data: [ 0:{Name:"ABC1",No:5,BalanceDue:5000,Notes1:null,Notes2:null,CurrencyId:"2",Date:"06/01/2018"} 1:{Name:"ABC2",No:6,BalanceDue:6000,Notes1:null,Notes2: ...

Are React component properties enclosed in curly braces?

I have a new component configured like this: type customType = differentType<uniqueType1, uniqueType2, uniqueType3>; function customComponent({q}: customType) When called, it looks like this: <customComponent {...myCustomVar} />, where myCus ...

Is there a way for me to determine when a user has signed in for the first time?

Issue at Hand I am facing an obstacle in detecting when a user initially connects to Google on my app using Firebase. The method I am currently utilizing is auth.signInWithPopup(googleProvider);. To address this query, I delved into the documentation and ...

The type 'NextApiRequest' lacks the following attributes compared to type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'

An error has been identified in the code for a Next.js project below. The error message reads: Argument of type 'NextApiRequest' is not assignable to parameter of type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any ...

Create a Typescript index signature that incorporates individual generic types for each field

Many times, the keys of a record determine its value. For instance: const record = { [2]: 5, ["string"]: "otherString", ["there is"]: "a pattern" } In these instances, each key of type K corresponds to the ...

Tips for configuring the Index column within an Angular Mat-table (when the dataIndex displays 'NaN')

My Mat-Table is working perfectly, but I am looking for a way to add an auto-increment index. Below is the HTML code: <div class="mat-elevation-z8"> <table mat-table [dataSource]="dataSource" matSort> <ng-container matColumnDef="no"> ...

Exploring the capabilities of Vitest by testing a RESTful API in SvelteKit

I am looking to create unit tests for a REST API built with SvelteKit, but most of the available resources focus on testing svelte components. Additionally, I prefer to avoid using Playwright as I do not require browser testing and want to steer clear of d ...

Establishing the correct data type to be returned from a fetch function in order to align with a specific custom type

My app has two interfaces defined: export interface Job { job_title: string, employer: string, responsibilities: string[] achievements: string[], start_date: string, end_date: string } export interface CreatedJob extends Job { ...

Is there a way to toggle or collapse a table row with a unique identifier using Angular and Bootstrap?

Currently handling Angular and Bootstrap in my work, but facing challenges with table manipulation and collapsing rows. I fetch data from a database and showcase it in a dynamically generated table using *ngFor and two rows within an ng-container. My goal ...

Utilizing a TypeScript function to trigger an action from within a Chart.js option callback

Currently, I am utilizing a wrapper for Chart.js that enables an animation callback to signify when the chart has finished drawing. The chart options in my code are set up like this: public chartOptions: any = { animation: { duration: 2000, ...

Transform Typescript code into Javascript using webpack while preserving the folder organization

Is there a way for webpack to compile my typescript node project into js while preserving the directory structure and not bundling into one file? This is my current project structure: src |_controllers |_home |_index.ts |_ services ...

Having trouble moving to a different component in Angular?

In my application, I am facing an issue with navigating from List to Details component by passing the ID parameter. It seems that there is no response or error when attempting to call the relevant method. Below, you can find the code snippets related to th ...

What could be causing the issue with dayjs dynamic importing in TypeScript?

Currently, I am developing a web screen within a .NET application and facing an issue with sending datetime preferences from the system to the web screen using CefSharp settings. AcceptLanguageList = CultureInfo.CurrentUICulture.Name In my TypeScript code ...

When passing e: EventTarget as a forwarded prop through a wrapper component, Typescript raises an error about the missing "value" property in the onChange function

In my project, there is a custom component called SelectField that serves as a wrapper for rendering label, helper text, and select input (inspired by TextField from @material-UI). The SelectField component exposes props like value and onChange, which are ...

Ionic storage is unable to assign a number as a string

My goal is to store all numbers retrieved from the function getWarrentsNumber() in ionic storage, but I encountered an error. Error: The argument of type "number" cannot be assigned to type 'string'. this.storage.set(this.NumberOfAssignedWarren ...

invoke a specified function at runtime

I recently came across a useful library called https://github.com/ivanhofer/typesafe-i18n This library has the capability to generate strongly typed translation data and functions, as illustrated below. (the examples provided are simplified for clarity) e ...

New Requirement for Angular Service: Subclass Constructor Must Be Provided or Unable to Resolve all Parameters for ClassName (?)

During a recent project, I encountered an issue while working on several services that all extend a base Service class. The base class requires a constructor parameter of HttpClient. When setting up the subclass with autocomplete, I noticed that their con ...