What is the reason the 'Add' type does not meet the 'number' constraint?

I experimented with type gymnastics using Typescript, focusing on implementing mathematical operations with numeric literals. First, I created the BuildArray type:

type BuildArray<
    Length extends number, 
    Ele = unknown, 
    Arr extends unknown[] = []
> = Arr['length'] extends Length 
        ? Arr 
        : BuildArray<Length, Ele, [...Arr, Ele]>;
type MyArray = BuildArray<3> // type MyArray = [unknown, unknown, unknown]

Next, I implemented the Add type:

type Add<Num1 extends number, Num2 extends number> = 
    [...BuildArray<Num1>, ...BuildArray<Num2>]['length']
type AddResult = Add<2, 5> // type AddResult = 7

However, when trying to create a Multiply type based on Add, I encountered an error:

type Multiply<Num1 extends number, Num2 extends number, Counter extends number = 0, Result extends number = 0> =
    Counter extends Num2?
    Result:
    Multiply<Num1, Num2, Add<Counter, 1>, Add<Num1, Result>>
type MultiplyResult = Multiply<4, 5> // type MultiplyResult = 20

While the result is correct, there was a compilation error:

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

Playground link

Can anyone explain why this compilation error is happening?

Answer №1

When the Counter is being passed into Add<Counter, 1>, it expands the type to number, although it remains an unknown number at this point. As it moves from Add to BuildArray, a check occurs:

Arr['length'] extends Length?

Depending on the result of this check, you either expect types Arr or

BuildArray<Length, Ele, [...Arr, Ele]>
, which presents the same dilemma.

Returning to Add, when dealing with an unknown number, TypeScript cannot confirm that the length property belongs to an Array, which itself is a number.

While the value is retrieved correctly, the actual type remains uncertain as the check Arr['length'] extends Length? in BuildArray does not clarify that Arr is the target for accessing length.

If this explanation seems convoluted, here's a summary: To achieve your objective with minimal adjustments, explicitly specify within the Add type that it will always be a number, rather than expecting TypeScript to infer it autonomously.

One way to enforce this information could involve adding & number:

type Add<Num1 extends number, Num2 extends number> =
    [...BuildArray<Num1>, ...BuildArray<Num2>]['length'] & number
// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^^^^^^^^

Alternatively, implement any form of type checks necessary.

Playground link

Answer №2

This is due to the fact that in this scenario, you are extending with numbers

Counter extends number = 0, Result extends number = 0

and your

Add<num1, num2></co`de> type results in a narrowed number.</p>
<p>For instance: <code>type AddResult = Add<2, 5> // type AddResult = 7

when you use typeof AddResult, the result will be 7 (for TS it is unknown) instead of number, leading to the error.

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

Identifying line breaks caused by browsers or CSS forced line breaks

<p style="width:60px"> This is just a sample text. It is a piece of text that doesn't really say anything meaningful.</p> When this text is rendered as HTML, it would look like this: This is just a sample text. It is a piece of text ...

Tracking the progress of reading position using Jquery within an article

Here is an example of a reading progress indicator where the width increases as you scroll down the page: http://jsfiddle.net/SnJXQ/61/ We want the progress bar width to start increasing when the article content div reaches the end of the article c ...

Despite being used within useEffect with await, asynchronous function fails to wait for results

In my component, I am utilizing a cookie value to determine which component or div block to display. The functionality works correctly in the end, but there is a brief moment where it seems like the cookie value is not being checked yet. During this short ...

Disable the button until all input fields contain text in ASP

Curious if anyone knows how to disable a button until all text boxes have input in ASP.NET and C#. Here is an image showing the scenario I'm referring to - wanting to gray out the commit button. Thanks, Chris! ...

Error message: The Javascript Electron app is unable to find the node-fetch module when

Below is the code snippet from my gate.html file: <html> <head> <meta http-equiv='Content-Security-Policy' content='default-src 'self'; https://example.com.tr/validkeys.txt'> <meta http-equiv=&ap ...

Tips on preventing the occurrence of double encoding in raw JSON output from a view

I am encountering a JavaScript error while attempting to parse JSON data obtained from my controller: Uncaught SyntaxError: Unexpected token & in JSON at position 1 at JSON.parse () at stores:76 This is the code I use to serialize my list of elem ...

Counting the number of visible 'li' elements on a search list: A guide

In the following code snippet, I am attempting to create a simple search functionality. The goal is to count the visible 'li' elements in a list and display the total in a div called "totalClasses." Additionally, when the user searches for a spec ...

The assignment of Type Program[] to a string[] is not valid

I am working with a class that contains information about different programs. My goal is to filter out the active and inactive programs, and then retrieve the names of those programs as an array of strings. Below is the structure of the Program class: ex ...

Using ReactJS to trigger a timer function on a button click

Kindly Note: This is a unique query and not related to ReactJS - Need to click twice to set State and run function. The suggested solution there does not resolve my issue. This represents my original state: constructor(props) { super(props) this. ...

JavaScript code to obscure

My goal is to create a JavaScript function where the "costCenter" object starts with visibility set to false. However, when the user clicks on the "computer" item in a dropdown list, the visibility of "costCenter" should change to true. This is my current ...

Avoiding redirection in Django template form

Currently, I am facing a challenge with my application that involves rendering a Django Template model form where images are referenced from another model. To manage the addition and deletion of images for this other model, I have implemented a button wit ...

Manipulating divs by positioning them at the top, left, right, bottom, and center to occupy the entire visible portion of the page

Many suggest avoiding the use of table layouts and opting for divs and CSS instead, which I am happy to embrace. Please forgive me for asking a basic question. I am looking to create a layout where the center content stretches out to cover the entire visi ...

Interact with various contenteditable sections by navigating with the arrow keys

I have a challenge with multiple <p contenteditable="true"></p> elements on my page. I am seeking a solution to enable the use of arrow keys to navigate seamlessly across these separate elements as if they were one cohesive editable element. F ...

Creating a dynamic div and populating it with data from various elements in separate xhtml files: a step-by-step guide

I am looking to dynamically add a div under the div tag with id "includedContent" in the code below. Additionally, I would like to modify the load method to accept an array of ids instead of a hardcoded Id(123) and display the data in the dynamically creat ...

Missing folders in npm package

After successfully creating and publishing a private npm package, I noticed an inconsistency in the file structure when installing it on another project: Library.Util | |__index.js | |__package.json The original file structure of the package includes a t ...

Having difficulty accessing a public array item within chained AXIO transactions in VUE

I am currently facing an issue with a chained AXIOS call that is triggered from an array. The challenge I am encountering is ensuring that the second call completes before the first one initiates another API request, which seems to be working fine so far. ...

A fresh perspective on incorporating setInterval with external scripts in Angular 7

Incorporating the header and footer of my application from external JavaScript files is essential. The next step involves converting it to HTML format and appending it to the head of an HTML file. private executeScript() { const dynamicScripts = [this.app ...

Is it possible to toggle all parent targets in Bootstrap?

When trying to showcase my point, I believe it is best demonstrated by visiting Bootstrap documentation at https://getbootstrap.com/docs/4.0/components/collapse/ and viewing the "multiple targets section." In this section, you will find three buttons: togg ...

"Encountered a Parsing Error: function keyword was an unexpected token in an Async Function using a more recent version of Node

In the process of working on a side project, I am utilizing node and firebase technologies. While I have successfully created regular functions and cloud functions, I encountered an issue when attempting to create an async function like so: async function ...

How can tick values be displayed on a c3js line chart when all data is unselected?

I'm currently working with a c3js line chart that displays 3 different lines. However, I noticed that when I remove all data sources, the x-axis tick values disappear. Is there a way to keep the x-axis tick values visible even when there is no data pr ...