WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Maximum call stack size exceeded in isTypeAssignableTo when using recursive template literal types in a generic contextΒ #62933

@mdm317

Description

@mdm317

πŸ”Ž Search Terms

Maximum call stack size exceeded in isTypeAssignableTo when using recursive template literal types in a generic context

πŸ•— Version & Regression Information

  • This changed between versions 5.9.3

⏯ Playground Link

https://codesandbox.io/p/devbox/7ctt7z?file=%2Findex.js%3A40%2C9

πŸ’» Code

import ts from "typescript";

const code = `

type A<T extends string> = T extends \`\${infer F}\${infer R}\`
  ? \`\${F}b\${A<R>}\`
  : "";

type B<T extends string> = T extends \`\${infer F}\${infer R}\`
  ? \`\${F}b\${B<R>}\`
  : "";

type C<T extends string> = A<T> | B<T>;

`;

const fileName = "test.ts";
const sourceFile = ts.createSourceFile(
  fileName,
  code,
  ts.ScriptTarget.Latest,
  true
);

const host = ts.createCompilerHost({});
host.getSourceFile = (name) => (name === fileName ? sourceFile : undefined);

const program = ts.createProgram([fileName], {}, host);
const checker = program.getTypeChecker();

const types = {};

ts.forEachChild(sourceFile, (node) => {
  if (ts.isTypeAliasDeclaration(node)) {
    types[node.name.escapedText] = checker.getTypeAtLocation(node);
  }
});
const typeA = types["A"];
const typeB = types["B"];
// works
console.log("isTypeAssignableTo(A, B):", checker.isTypeAssignableTo(typeA, typeB));


ts.forEachChildRecursively(sourceFile, (node) => {
  if (ts.isTypeReferenceNode(node) && ts.isUnionTypeNode(node.parent)) {
    types[node.typeName.escapedText] = checker.getTypeAtLocation(node);
  }
});
const typeAInsideGeneric = types["A"];
const typeBInsideGeneric = types["B"];

// Maximum call stack size exceeded
console.log("isTypeAssignableTo(A, B):", checker.isTypeAssignableTo(typeAInsideGeneric, typeBInsideGeneric));

πŸ™ Actual behavior

Maximum call stack

πŸ™‚ Expected behavior

Not occur maximum call stack

Additional information about the issue

from typescript-eslint/11824

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions