Tips for selecting the correct type for an array of Unions with the help of Array.prototype.find

I have the following variations:

type First = { kind: 'First', name: string }
type Second = { kind: 'Second', title: string }

type Combo = First | Second;

I am attempting to locate the element of type First in a Combo[], as shown below:

const elements: Combo[] = [
    { kind: 'First', name: 'element 1' },
    { kind: 'Second', title: 'element 2' },
]

const foundFirst: First | undefined = elements.find(e => e.kind === 'First');

However, this triggers the error:

Type 'First | Second | undefined' is not assignable to type 'First | undefined'.
  Property 'name' is missing in type 'Second' but required in type 'First'.

The predicate function for Array.prototype.find correctly identifies the appropriate type, and I can access the properties of First without any issues:

https://i.sstatic.net/xuS6V.png

It seems to be the return type that needs refinement.


The only solution I have found so far is using a for loop, but it seems cumbersome and unnecessary.

let foundElement: First | undefined;

for (let i = 0; i < elements.length; i++) { 
    const value = elements[i];
    if (value.kind === 'First') { 
        foundElement = value;
        break;
    }
}

Answer №1

The predicate d => d.style === 'A' you provided is inferred as type (d: Union) => boolean.

In order to achieve the desired behavior, it should be inferred as (d: Union) => d is A, essentially a user-defined type guard. TypeScript does not implicitly infer a function as a user-defined type guard; it needs to be explicitly declared as one. By defining it like this, it will work:

function isA(d: Union): d is A {
    return d.style === 'A';
}

const a: A | undefined = data.find(isA); // no error

Initially, I thought this was not possible because it would require Array.prototype.find to have a return type based on whether the predicate is a user-defined type guard. However, as I discovered through testing, it is indeed possible, and I learned something new today.

Playground Link

Answer №2

Here is the signature for Array.prototype.find:

find<S extends T>(predicate: (this: void, value: T, index: number, obj: T[]) => value is S, thisArg?: any): S | undefined;

It's important to note the return type of the predicate callback: value is S. This predicate is designed to narrow down the results, eliminating the need for an additional function. You can simply write it inline like this:

const a: A | undefined = data.find((d): d is A => d.style === 'A'); // this works

Check out this live example on how this works in action.

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

What is the best way to reference class variables and methods within a callback function in Typescript?

While working on my Angular project with the Highcharts API, I encountered a situation where I needed to pass a state code to a class level method after drilling down to a specific map location. Below is the snippet of my current code: ngOnInit() { this. ...

Is there a way to find the recursive key types in TypeScript?

Is there a method to ensure that code like this can compile while maintaining type safety? type ComplexObject = { primitive1: boolean; complex: { primitive2: string; primitive3: boolean; } }; interface MyReference { myKey: keyof ComplexObj ...

Looking for a TypeScript annotation that allows accessing an object property using a variable

When working with plain JavaScript, we have the ability to access an object's property value using a variable. For example, this is permitted: let obj = { a: 100, b: 'Need help with TypeScript', c: new Date() }; let prop = 'b'; c ...

Next.js API is throwing a TypeError because req.formData is not a recognized function

Below is the code snippet for the Next.js route I am working on: import { NextRequest, NextResponse } from 'next/server'; export const config = { runtime: 'edge', }; export default async function POST(req: NextRequest): Promise< ...

Tips for capturing the output of a dynamically rendered component in Angular 8

I need to capture the output from a rendered component using ViewChild. The content of ViewChild is displayed after an ngIf condition is met. Here is the template code: <div *ngIf="isModalVisible" class="modal" tabindex="-1" role="dialog"> <di ...

How to efficiently upload multiple files simultaneously in Angular 10 and .NET Core 5 by utilizing a JSON object

I have a JSON object structured like this: Class->Students this is a basic representation of my TypeScript class export class Classroom { Id:number; Name:string; Students:Student[]=[]; } export class Student { Name:string; Age:number; Sex:string; Imag ...

Increasing response buffer size in Node.js fetch for version 2.x.x

Currently in the process of implementing an API request using nodejs-fetch and I've encountered an issue. The documentation states that the maximum buffer size for fetch is 16kB, but the response I need to retrieve is 53 kB. This causes the .fetch() f ...

When trying to access the DOM from another module in nwjs, it appears to be empty

When working with modules in my nwjs application that utilize document, it appears that they are unable to access the DOM of the main page correctly. Below is a simple test demonstrating this issue. The following files are involved: package.json ... "ma ...

JSON definitions for Google Apps Scripts in TypeScript

Is there a way to obtain Typescript definitions for the raw JSON schema when creating a Google App Script with a cloud function, as outlined in the following link: https://developers.google.com/workspace/add-ons/alternate-runtimes-quickstart I've com ...

Using Vue: How to utilize v-slot variables in JavaScript

Can the values of the v-slot of a component be accessed in the script? For instance, consider the following template: <cron-core v-model="value" :periods="periods" :format="format" v-slot="{fields, period, error}"> {{period}} <div v-for="fiel ...

Following the npm update, encountering errors with webpack

Upgrading the npm package to version 8.2.0 has caused issues in my React application. Here is a screenshot of the problem: https://i.stack.imgur.com/noQIz.png These are the error messages I see in the console: [HMR] Waiting for update signal from WDS.. ...

Guide on invoking personalized server-side functions (such as object parsing) utilizing Typescript and Angular tools

I've been grappling for weeks to make custom service calls function with Typescript / Angular / C#. It's been a challenge to find a workable solution online, and the more I search, the more bewildered I become. My current approach has largely be ...

Determine the type of the final function within a variable number of nested closures

Imagine you have a function like this: const f = a => b => ... x => { return somevalue } Is there a way to determine the type of just the final function typeof x => { return somevalue } even if we don't know how many closures come before ...

What is the best way to elucidate this concept within the realm of TypeScript?

While diving into my ts learning journey, I came across this interesting code snippet: export const Field:<T> (x:T) => T; I'm having trouble wrapping my head around it. It resembles the function definition below: type myFunction<T> = ...

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 { \* ... *\ } ...

Determine rest parameters based on the initial argument

Struggling to generate a solution that infers the arguments for an ErrorMessage based on the provided code input. ./errorCodes.ts export enum ErrorCodes { ErrorCode1, ErrorCode2, ErrorCode3 } ./errorMessages.ts export const ErrorMessages = { [Err ...

Steps for generating a fresh type denotation from a value within an object

Is it possible to create a new type alias based on an object's values? const test = { 'a': ['music','bbq','shopping'], 'b': ['move','work'] }; How can we extract this information f ...

Substitute data types for certain keys within a Typescript interface

Within this code snippet, the goal is to create a new type from an existing one by iterating through the keys and only replacing those that meet a specific condition. Additionally, union types are being utilized here. class A {} class B { constructor ...

"Overcoming obstacles in managing the global state of a TypeScript preact app with React/Next signals

Hello, I recently attempted to implement a global app state in Preact following the instructions provided in this documentation. However, I kept encountering errors as this is my first time using useContext and I suspect that my configuration might be inco ...

Angular: efficient exchange of information among components

I have a component X that handles a WebSocket. And within component X, I also have multiple presentation components (e.g. Y). Whenever the WebSocket receives a specific message, I need to perform an action in a particular component (e.g. refresh data). To ...