In TypeScript, leveraging the spread operator to determine the largest value in an array containing nullable numbers

Having an array of nullable numbers presented in the following way:

let myArray : Array<number | null> = [1,2,null,4,null,5];
let maximumOfMyArray = Math.max(...myArray); // Type null is not assignable to type number

I am content with JavaScript treating null as 0 in this scenario. There are two potential solutions that come to mind, but neither are perfect:

let myArray : Array<number | null> = [1,2,null,4,null,5];
//@ts-ignore
let maximumOfMyArray = Math.max(...myArray); 

The above method does not fully resolve the issue, and:

let myArray : Array<number | null> = [1,2,null,4,null,5];
let castArray = myArray as unknown as Array<number>;
let maximumOfMyArray = Math.max(...myArray); 

Is there a solution available that does not rely on these workarounds?

Answer №1

To narrow down the array, use a type guardian

const ns: Array<number | null>
const isDefined: <A>(a: A | null | undefined) => a is A

Math.max(...ns.filter(isDefined)) // number

Answer №2

Can a solution be found without resorting to these workarounds?

A different approach is available: Convert the nulls explicitly to 0 using the map function:

let maximumOfMyArray = Math.max(...myArray.map(v => v === null ? 0 : v));

Link to demo

If you don't convert the nulls to numbers (or filter them out as suggested below), your only option is to use a workaround like the ones mentioned, since TypeScript does not allow mixing different types intentionally.


Filtering out the nulls alone did not satisfy TypeScript without a type assertion, even with typeof v === "number". However, it does enable you to perform the type assertion without needing unknown:

const myArrayWithoutNulls = myArray.filter(v => v !== null) as Array<number>;
let maximumOfMyArray = Math.max(...myArrayWithoutNulls);

Link to playground

Alternatively, and a much cleaner option, consider implementing a type guard function as demonstrated by Denis Frezzato in their post on Stack Overflow.

Answer №3

Instead of following the suggestion from @T.J. Crowder, you can take a different approach by expanding the functionality of Math.max to accommodate null values. By doing this, your original code will remain functional without any modifications.

To achieve this, update your .d.ts file with the following:

declare global {
  interface Math {
    max(...values: (number | null)[]): number
  }
}

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 change multiple parameters using ngModelChange?

I have a requirement in my application to update 3 values using a single ngModelChange event. The component structure is as follows: model: any = {}; images: any; public input = true; public dropdown = false; images : any; constructor(...services) { } ...

The logout feature might refresh the page, yet the user remains logged in

Currently, I am enrolled in a course on Udemy where the instructor is utilizing Angular 2. My task involves building the app using the latest version of Angular. The issue that I am facing pertains to the logout functionality. After successfully logging ou ...

What is the process of 'initializing' an object in TypeScript?

Is it possible that retrieving a json from a mongodb database and casting it does not trigger the typescript constructor? What could be causing this issue? I have a Team class export class Team { transformations: { [transformationId: string]: Transfor ...

How to pass a String Array to a String literal in JavaScript

I need to pass an array of string values to a string literal in the following way Code : var arr = ['1','2556','3','4','5']; ... ... var output = ` <scr`+`ipt> window.stringArray = [`+ arr +`] & ...

JavaScript cannot determine the length of an array of objects

I'm encountering an issue with an array of objects named tagTagfilter. When I log it in the browser, it doesn't immediately show the correct length value inside. tagTagFilter: TagFilter = { filterName: 'Tag', tags: [] ...

Tips for injecting scripts into the head tag after an Angular component has been loaded

Currently, I am facing an issue with a script tag containing a Skype web control CDN. The script has been placed in the head section of my index.html file, but it is being called before the component that needs it has finished loading. Does anyone have a ...

The type 'FormikValues' is deficient in the subsequent properties compared to the type 'Exact<{'

I am currently working on a form with the following structure: import { Field, Form, Formik, FormikProps, FormikValues } from 'formik' import { NextPage } from 'next' import React from 'react' import { useCreateUserMutation } ...

Fastify Typescript: dealing with an unidentified body

I'm new to Fastify and I've encountered a problem with accessing values in the body using Typescript. Does anyone have any ideas or suggestions? Thanks! Update: I want to simplify my code and avoid using app.get(...) Here's my code snippet ...

What is the best approach for submitting a form with data through a POST request in an Ionic application?

I am facing an issue while trying to make a POST request in Ionic for submitting a form with an array of data. Surprisingly, it works perfectly fine when I test it on POSTMAN. Although I attempted to use this form, it did not yield the desired results: ...

What is the best way to invoke a function in a specific child component from its parent component?

It seems that I might have provided too much information, but the main question remains: how can I call a method in the child component from the parent template's click() event. <button(click)='get()'>GET</button> In my case, th ...

Is it possible for Typescript interface A to extend B while lacking certain properties from B?

My confusion lies in understanding how TypeScript interfaces function effectively. Here's what I currently have: import type { Socket, Handshake } from 'socket.io'; import type { Session } from './session'; export interface Sessio ...

Typescript's date function offers a variety of useful features

Can anyone help me create a function that formats a date string for sorting in a table? The date is in the format: 08.04.2022 16.54 I need to convert this to a number or date format that can be sorted. I'm new to TypeScript and could use some guida ...

What is the process for utilizing ts-node ESM in conjunction with node modules?

Disclaimer: I understand that the question below pertains to an experimental feature. I have initiated a thread on the ts-node discussion forum. Nonetheless, I believe that posting on StackOverflow will garner more visibility and potentially result in a qu ...

Playwright failing to execute GraphQL tests due to TypeScript configuration problems

I'm facing an issue with my repo where I am running tests using Playwright against a graphQL URL. Despite configuring the tests, there is an error indicating that the environment variable defining the environment cannot be found. The repository in qu ...

Using the useContext hook in a TypeScript class component: a step-by-step guide

I am working with a TypeScript class component and have successfully created a context that can be accessed globally. I am interested in learning how to implement this context in a .ts class component and if it is possible to use it in a pure TypeScript ...

Constructing objects in TypeScript is a breeze with its C#-ins

It seems like finding a simple solution for my task is proving to be quite challenging. I have a class that accepts 10 parameters, most of which are optional. To simplify things, I will illustrate my dilemma using just 3 parameters. I wish to be able to i ...

What are the steps to executing a function that instantiates an object?

Here is an object with filter values: const filters = ref<filterType>({ date: { value: '', }, user: { value: '', }, userId: { value: '', }, ... There is a data sending function that takes an obje ...

Execute a grandchild function in Angular that triggers its grandparent function

I'm currently working with a component structure that looks like this: Component A -> Component B -> Component C Within the template of Component C, there is a button that triggers a function in the 'code behind' when clicked. My go ...

Attempting to execute a synchronous delete operation in Angular 6 upon the browser closing event, specifically the beforeunload or unload event

Is there a way to update a flag in the database using a service call (Delete method) when the user closes the browser? I have tried detecting browser close actions using the onbeforeunload and onunload events, but asynchronous calls do not consistently wor ...

Searching for data based on specific keywords in Angular 2, rather than using a wildcard search, can be done by utilizing the key-in

My dropdown contains 100 values, and I am currently able to search for these values based on key input using wild search. However, I would like the dropdown to display values based on the specific alphabet that I enter first. HTML: <div class="col- ...