Skip to content

Native compiler API resolves a default-parameter reference to a body function binding #65090

Closed

Description

@CaliLuke

Version and environment

  • typescript@7.0.2 (native compiler API)
  • Node.js 26.12.1, macOS arm64

Problem

A reference in a default parameter resolves to a function declared inside the function body, rather than the outer variable used at runtime. This reproduces with the maintained native compiler API, independently of the legacy 6.0 API.

Reproduction

In an empty directory run npm install typescript@7.0.2, save the following as repro.mjs, and run node repro.mjs:

import { API } from 'typescript/unstable/sync';
import { SyntaxKind } from 'typescript/unstable/ast';
import { mkdtempSync, writeFileSync, rmSync } from 'node:fs';
import { join } from 'node:path';
import { tmpdir } from 'node:os';

const dir = mkdtempSync(join(tmpdir(), 'ts-default-'));
const file = join(dir, 'case.ts');
const config = join(dir, 'tsconfig.json');
const text = `const styles = { root: "outer" };
export function read(value = styles.root) {
  function styles() {}
  return value;
}
`;
writeFileSync(file, text);
writeFileSync(config, JSON.stringify({
  compilerOptions: { target: 'ESNext', noEmit: true, types: [] },
  files: ['case.ts'],
}));
const api = new API({ cwd: dir });
try {
  const snapshot = api.updateSnapshot({ openProjects: [config] });
  const project = snapshot.getProject(config);
  const position = text.indexOf('= styles') + 2;
  const symbol = project.checker.getSymbolAtPosition(file, position);
  const declaration = symbol.valueDeclaration.resolve();
  console.log('Resolved declaration:', SyntaxKind[declaration.kind]);
  console.log('Declaration source:', text.slice(declaration.pos, declaration.end).trim());
  const { read } = await import('data:text/javascript,' + encodeURIComponent(text));
  console.log('Runtime default value:', read());
  snapshot.dispose();
} finally {
  api.close();
  rmSync(dir, { recursive: true, force: true });
}

Actual output:

Resolved declaration: FunctionDeclaration
Declaration source: function styles() {}
Runtime default value: outer

Expected behavior

The symbol for styles in value = styles.root should resolve to the outer VariableDeclaration, matching the runtime parameter-initializer scope. The body function binding is not visible from that initializer.

Compiler-API consumers following the returned declaration can otherwise associate a reference with the wrong runtime binding.

History

The legacy-API report #65048 was closed because the 6.0 API is no longer maintained and a runnable reproduction was missing. This new report provides a complete runnable reproduction against the native 7.0.2 API.

Metadata

Metadata

Labels

BugA bug in TypeScript

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions