TypeScript: The instantiation of types is too deep and may potentially be endless

I have been working on implementing a versatile split type in TypeScript that can effectively split a literal string using multiple delimiters.

type Spl<T extends string, D extends string> = T extends `${infer A}${D}${infer B}` ? 
    A extends '' ? [] :
    [A, ...Spl<B, D>] : (T extends '' ? [] : [T]);

type SplMany<T extends string, D extends string[]> = D extends [infer H extends string, ...infer Tail extends string[]]
    ? 
        T extends '' ? [] : SplManyInputsManyDelimieter<[...Spl<T, H>], Tail> 
    : [T];

type SplManyInputs<T extends string[], D extends string> = T extends [infer H extends string, ...infer Tail extends string[]]
    ? [...Spl<H, D>, ...SplManyInputs<Tail, D>] : [];

type SplManyInputsManyDelimieter<T extends string[], D extends string[]> = 
  D extends [infer H extends string, ...infer Tail extends string[]] ?
    SplManyInputsManyDelimieter<[...SplManyInputs<T, H>], Tail>
    : T;    

type t1 = Spl<'1 2 3 4 5 6                            7 8 9 10 11 %test% 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 1 2 3 4 5 6                            7 8 9 10 11 %test% 12 13 14 15 16 17 18 19 20 21 22 23 24 25 1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 1 2 3 4 5 6                            7 8 9 10 11 %t...

Upon testing the code, it performs well. However, I encountered an error message as the input strings grew longer:

Type instantiation is excessively deep and possibly infinite. ts(2589)
. It appears that the recursion limit was reached earlier than expected, posing challenges for efficiency.

Are there any strategies I could employ to optimize the code and support longer inputs? Additionally, I attempted to locate the source of the error message within the TypeScript compiler but without success. Does anyone know where this specific error is generated?

Answer №1

When crafting a deeply recursive conditional type, where the intention is for recursion to dive beyond just a few levels, there is a possibility of encountering recursion limits and receiving an error message stating "type instantiation is excessively deep and possibly infinite."

In situations like this, it is possible to refactor the code to apply tail recursion elimination on conditional types, as introduced in microsoft/TypeScript#45711. This approach can allow for up to a thousand levels of recursion, which typically suffices for most use cases.

The strategy involves ensuring that any recursive usage of the type adheres to being tail-recursive, where the output directly passes the result of the recursive type without requiring additional manipulation. This often entails adding an extra accumulator type parameter to the type function. For example, with Spl and SplManyInputs, the implementation could resemble the following:

type Spl<T extends string, D extends string, ACC extends string[] = []> =
    T extends `${infer A}${D}${infer B}` ? A extends '' ? ACC :
    Spl<B, D, [...ACC, A]> : (T extends '' ? ACC : [...ACC, T]);

type SplManyInputs<T extends string[], D extends string, ACC extends string[] = []> =
    T extends [infer H extends string, ...infer Tail extends string[]]
    ? SplManyInputs<Tail, D, [...ACC, ...Spl<H, D>]> : ACC;

In both scenarios, an ACC type parameter is utilized to store the final output, initially set as the empty tuple [], gradually accumulating the intermediate results. The base case involves simply returning the accumulator.

This method provides identical results to previous versions but successfully avoids recursion limitations for the given examples.

Playground link to code

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

The callback function does not seem to work when using MUI v4 PropFunc

Encountering an issue with custom styling using PropFunc in Material UI (MUI) v4 (4.12.4). When providing a PropFunc in the traditional callback way to get CSS, it works as expected: const useStyles = makeStyles((theme) => { return { input: { ...

Combine the selected values of two dropdowns and display the result in an input field using Angular

I am working on a component that consists of 2 dropdowns. Below is the HTML code snippet for this component: <div class="form-group"> <label>{{l("RoomType")}}</label> <p-dropdown [disabled] = "!roomTypes.length" [options]= ...

Getting rid of the Chrome default page after a user has logged in - here's how to do

After implementing Next.js, I am using router.replace to navigate the user to the home page. Everything works fine, but the problem arises when the back button is still active. Clicking it directs me to Chrome's default page. How can I disable this be ...

Issues with displaying data in Angular Material table

I am having trouble displaying data in a table. The data shows up when I display it in another element, but not in the table. Here is my code: <mat-accordion *ngIf="posts.length > 0"> <mat-expansion-panel *ngFor="let post of p ...

Establishing the types of object properties prior to performing a destructuring assignment

Consider a scenario where a function is utilized to return an object with property types that can be inferred or explicitly provided: const myFn = (arg: number) => { return { a: 1 + arg, b: 'b' + arg, c: (() => { ...

The specialized middleware in Next.js gets dispatched to the browser

Attempting to retrieve user information based on the current session, I created a small _middleware.ts file. In order to get the users' data, I imported a prisma (ORM) client. However, upon loading the page in the browser, an error message appeared: ...

Encountering compilation issues when transitioning from Angular 7 to Angular 8

Upon upgrading my project to Angular 8, an unexpected error occurs during the build process: ERROR in HostResourceLoader: loader(C:/myapp/cli/src/app/pages/user-home/user-home.component.html) returned a Promise i 「wdm」: Failed to compile. Ho ...

Angular 12: How to detect when a browser tab is closing and implement a confirmation dialog with MatDialog

I have a scenario where I am checking if the browser tab is closed using the code below. It currently works with windows dialog, but I would like to incorporate MatDialog for confirmation instead. @HostListener('window:beforeunload', ['$eve ...

Transforming Uint8Array into BigInt using Javascript

I've come across 3 different ways to convert a Uint8Array to BigInt, but each method seems to produce varying results. Can someone clarify which approach is correct and recommended? Utilizing the bigint-conversion library. The function bigintConversi ...

What is the best way to identify the data type of elements in an array using TypeScript?

When working with TypeScript, it is common to reference interface properties using syntax like Person['gender']. This allows for clear definition of types in TypeScript, as shown in the following example: interface Person { gender: 'male& ...

Why isn't this directive registering changes on ion-input in Angular and Ionic?

I am attempting to get this directive to function with ion input, however, I am facing two challenges that I am unsure how to resolve: 1 - Difficulty loading the mask when the ion-input is displayed - The issue is that the input element only appears as a ...

What is the best way to implement a comprehensive switch case in Typescript using string enums that are referencing other string enums?

I am faced with a challenge where I have a subset of values from one enum that I need to switch case across in TypeScript. Here's an example to illustrate my dilemma: const enum Fruit { APPLE = 'Apple', BANANA = 'Banana', ...

What is the best way to include a minified bootstrap file in a TypeScript project?

Instead of using react-bootstrap, I only want to add the minified CSS. I went ahead and copied the original CSS file into my project, then added the path in the index.html, but unfortunately, it's still not working. <head> <meta charset=&quo ...

What is preventing the TypeScript compiler from accepting this code that appears to be valid?

I am encountering difficulties comprehending why the TypeScript type-checker is denying code that appears to be valid. export type Fn<I, O> = (value: I) => O type FInput<F extends Fn<any, any>> = F extends Fn<infer I, any> ? I : ...

How can I correctly enable the css property in Emotion 11 and Next.js 10 applications?

The css property is not being detected during the build process. It's unclear whether this issue stems from a misconfiguration in the project settings or if it's a known bug. Type '{ children: (string | number | boolean | {} | ReactElement ...

At a specific duration of inactivity on the website, I am automatically redirected to the login page due to session expiration

When I navigate through the URL based on the session, the session will expire if the user is inactive on the site. The issue arises when a user is considered inactive because the session expires after a certain period of inactivity and then redirects to th ...

Tips for restricting custom number types based on if conditions in TypeScript

Programming Digits type NumType = 1 | 2 | 3 | 4 | 5; function numFunc(number: NumType) { console.log("Number selected: ", number); } const randomNumber = Math.floor(Math.random() * 10); if (0 < randomNumber && randomNumber < 6 ...

The PDF can be accessed from the console but the network tab is not visible

import { axiosInstances } from "./axiosInstanc" interface upladPdfPayload { name: string; pdf: File } export const uploadPdfApi = async (payload: upladPdfPayload) => { try { console.log(payload); const res = await a ...

Having trouble locating the error in my Angular and Spring Security application

I am currently working on a project that involves integrating Spring Security with an Angular client. I have encountered an issue where, despite checking for null values in the login form on the Angular side before sending it to the Java application, the J ...

The value specified as type '{ value: BigNumber; }' cannot be assigned to the parameter type 'Overrides & { from?: string | Promise<string> | undefined; }'

I am currently working on a smart contract using Solidity (version 0.8.0) at my buildspace project. Below is a snippet of my code written in TypeScript (4.5.x)/JavaScript and Node.js 16.13.x: ... const waveContractFactory = await hre.ethers.getContractFact ...