Skip to content

[WIP] Fix TS5097 error for require() in checked JS - #64030

Draft
Ryan Cavanaugh (RyanCavanaugh) with Copilot wants to merge 1 commit into
mainfrom
copilot/fix-ts5097-error-require-imports
Draft

[WIP] Fix TS5097 error for require() in checked JS#64030
Ryan Cavanaugh (RyanCavanaugh) with Copilot wants to merge 1 commit into
mainfrom
copilot/fix-ts5097-error-require-imports

Conversation

Copilot AI commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Thanks for asking me to work on this. I will get started on it and keep this PR's description up to date as I form a plan and make progress.


This section details on the original issue you should resolve

<issue_title>TS5097 is not reported for require() in checked JS or for clause-less side-effect imports</issue_title>
<issue_description>Regression from typescript@6.0.2 to typescript@7.0.2. Also reproduces on @typescript/native-preview@7.0.0-dev.20260707.2 and on current main. node v24.13.0, darwin/arm64.

Steps to reproduce

Three files, no tsconfig.json:

lib.ts

export const value = 1;

require.js

// @ts-check
const { value } = require('./lib.ts');
console.log(value);

side-effect.ts

import './lib.ts';
tsc --noEmit --allowJs require.js side-effect.ts

Behavior with typescript@6.0.2

require.js(2,27): error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled.
side-effect.ts(1,8): error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled.

Behavior with typescript@7.0.2

No output — both are silently accepted.

This is not a module-resolution difference: 7.0 resolves require('./lib.ts') and type-checks against it. Changing console.log(value) to value(123) yields the same TS2349 from both versions at the same position — only TS5097 is missing.

Root cause

The two versions guard the diagnostic differently:

7.0 — tsc/internal/checker/checker.go:15334    if ast.FindAncestor(location, ast.IsEmittableImport) != nil {
6.0 — src/compiler/checker.ts:4779             if (errorNode && !(importOrExport?.isTypeOnly || findAncestor(location, isImportTypeNode))) {

7.0 asks "will this import survive emit?"; 6.0 asks "is this explicitly type-only?". The answers differ for exactly two shapes: a CommonJS require(), which is a plain CallExpression that IsEmittableImport never matched, and a clause-less side-effect import, which stopped matching in typescript-go#1198 — a fix for typescript-go#1190 in the adjacent .d.ts branch, which shares the same predicate.

Full matrix

case 6.0.2 7.0.2
require('./lib.ts') in checked JS TS5097
import './lib.ts' TS5097
import { value } from './lib.ts' TS5097 TS5097
import { value } from './lib.ts' in JS TS5097 TS5097
export { value } from './lib.ts' TS5097 TS5097
import('./lib.ts') TS5097 TS5097
import lib = require('./lib.ts') TS5097 TS5097
import type { Thing } from './lib.ts'
export type { Thing } from './lib.ts'
import('./lib.ts').Thing in type position
import './types.d.ts'

The versions disagree only on the first two rows; the last four are negative cases where both correctly stay silent.
</issue_description>

Comments on the Issue (you are Copilot in this section)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TS5097 is not reported for require() in checked JS or for clause-less side-effect imports

2 participants