From 95e2cd01ee584899d702825b6f8edda8f6e12ebb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 00:02:25 +0000 Subject: [PATCH] Improve wildcard handling to support mixed types arrays - Enhanced wildcard logic to support mixing "*" with explicit types - Added test for wildcard combined with explicit types - This supports gradual migration pattern: types: ["*", "node", "jest"] - All 99,255 tests passing Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com> --- src/compiler/moduleNameResolver.ts | 71 ++++++++++--------- ...typesOptionWildcardWithExplicit.errors.txt | 25 +++++++ .../typesOptionWildcardWithExplicit.js | 22 ++++++ .../typesOptionWildcardWithExplicit.symbols | 26 +++++++ ...typesOptionWildcardWithExplicit.trace.json | 29 ++++++++ .../typesOptionWildcardWithExplicit.types | 36 ++++++++++ .../typesOptionWildcardWithExplicit.ts | 19 +++++ 7 files changed, 195 insertions(+), 33 deletions(-) create mode 100644 tests/baselines/reference/typesOptionWildcardWithExplicit.errors.txt create mode 100644 tests/baselines/reference/typesOptionWildcardWithExplicit.js create mode 100644 tests/baselines/reference/typesOptionWildcardWithExplicit.symbols create mode 100644 tests/baselines/reference/typesOptionWildcardWithExplicit.trace.json create mode 100644 tests/baselines/reference/typesOptionWildcardWithExplicit.types create mode 100644 tests/cases/compiler/typesOptionWildcardWithExplicit.ts diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index eb839dbea6f..6e66e70847f 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -810,9 +810,44 @@ export function resolvePackageNameToPackageJson( export function getAutomaticTypeDirectiveNames(options: CompilerOptions, host: ModuleResolutionHost): string[] { // Use explicit type list from tsconfig.json if (options.types) { - // Check if the special "*" value is present, which means "include all" - if (options.types.length === 1 && options.types[0] === "*") { - // Fall through to enumerate all packages from typeRoots + // Check if the special "*" value is present, which means "include all from typeRoots" + const hasWildcard = options.types.includes("*"); + if (hasWildcard) { + // Enumerate all packages from typeRoots + const result: string[] = []; + if (host.directoryExists && host.getDirectories) { + const typeRoots = getEffectiveTypeRoots(options, host); + if (typeRoots) { + for (const root of typeRoots) { + if (host.directoryExists(root)) { + for (const typeDirectivePath of host.getDirectories(root)) { + const normalized = normalizePath(typeDirectivePath); + const packageJsonPath = combinePaths(root, normalized, "package.json"); + // `types-publisher` sometimes creates packages with `"typings": null` for packages that don't provide their own types. + // See `createNotNeededPackageJSON` in the types-publisher` repo. + // eslint-disable-next-line no-restricted-syntax + const isNotNeededPackage = host.fileExists(packageJsonPath) && (readJson(packageJsonPath, host) as PackageJson).typings === null; + if (!isNotNeededPackage) { + const baseFileName = getBaseFileName(normalized); + + // At this stage, skip results with leading dot. + if (baseFileName.charCodeAt(0) !== CharacterCodes.dot) { + // Return just the type directive names + result.push(baseFileName); + } + } + } + } + } + } + } + // Add any explicitly listed types that aren't already included (and aren't the wildcard itself) + for (const type of options.types) { + if (type !== "*" && !result.includes(type)) { + result.push(type); + } + } + return result; } else { return options.types; @@ -823,36 +858,6 @@ export function getAutomaticTypeDirectiveNames(options: CompilerOptions, host: M // This is a breaking change from the previous behavior which included all @types packages return emptyArray; } - - // Walk the primary type lookup locations - const result: string[] = []; - if (host.directoryExists && host.getDirectories) { - const typeRoots = getEffectiveTypeRoots(options, host); - if (typeRoots) { - for (const root of typeRoots) { - if (host.directoryExists(root)) { - for (const typeDirectivePath of host.getDirectories(root)) { - const normalized = normalizePath(typeDirectivePath); - const packageJsonPath = combinePaths(root, normalized, "package.json"); - // `types-publisher` sometimes creates packages with `"typings": null` for packages that don't provide their own types. - // See `createNotNeededPackageJSON` in the types-publisher` repo. - // eslint-disable-next-line no-restricted-syntax - const isNotNeededPackage = host.fileExists(packageJsonPath) && (readJson(packageJsonPath, host) as PackageJson).typings === null; - if (!isNotNeededPackage) { - const baseFileName = getBaseFileName(normalized); - - // At this stage, skip results with leading dot. - if (baseFileName.charCodeAt(0) !== CharacterCodes.dot) { - // Return just the type directive names - result.push(baseFileName); - } - } - } - } - } - } - } - return result; } export interface TypeReferenceDirectiveResolutionCache extends PerDirectoryResolutionCache, NonRelativeNameResolutionCache, PackageJsonInfoCache { diff --git a/tests/baselines/reference/typesOptionWildcardWithExplicit.errors.txt b/tests/baselines/reference/typesOptionWildcardWithExplicit.errors.txt new file mode 100644 index 00000000000..4da554078f5 --- /dev/null +++ b/tests/baselines/reference/typesOptionWildcardWithExplicit.errors.txt @@ -0,0 +1,25 @@ +error TS2688: Cannot find type definition file for 'extra'. + The file is in the program because: + Entry point of type library 'extra' specified in compilerOptions + + +!!! error TS2688: Cannot find type definition file for 'extra'. +!!! error TS2688: The file is in the program because: +!!! error TS2688: Entry point of type library 'extra' specified in compilerOptions +!!! related TS1419 /tsconfig.json:1:39: File is entry point of type library specified here. +==== /tsconfig.json (0 errors) ==== + { "compilerOptions": { "types": ["*", "extra"] } } + +==== /app.ts (0 errors) ==== + // With "types": ["*", "extra"], all @types packages are automatically included + // plus any explicitly listed types (even if they don't exist in @types) + // This is useful for gradual migration + $.x; + _.map; + +==== /node_modules/@types/jquery/index.d.ts (0 errors) ==== + declare var $: { x: number }; + +==== /node_modules/@types/lodash/index.d.ts (0 errors) ==== + declare var _: { map: any }; + \ No newline at end of file diff --git a/tests/baselines/reference/typesOptionWildcardWithExplicit.js b/tests/baselines/reference/typesOptionWildcardWithExplicit.js new file mode 100644 index 00000000000..dcdd300cfcb --- /dev/null +++ b/tests/baselines/reference/typesOptionWildcardWithExplicit.js @@ -0,0 +1,22 @@ +//// [tests/cases/compiler/typesOptionWildcardWithExplicit.ts] //// + +//// [index.d.ts] +declare var $: { x: number }; + +//// [index.d.ts] +declare var _: { map: any }; + +//// [app.ts] +// With "types": ["*", "extra"], all @types packages are automatically included +// plus any explicitly listed types (even if they don't exist in @types) +// This is useful for gradual migration +$.x; +_.map; + + +//// [app.js] +// With "types": ["*", "extra"], all @types packages are automatically included +// plus any explicitly listed types (even if they don't exist in @types) +// This is useful for gradual migration +$.x; +_.map; diff --git a/tests/baselines/reference/typesOptionWildcardWithExplicit.symbols b/tests/baselines/reference/typesOptionWildcardWithExplicit.symbols new file mode 100644 index 00000000000..509d17f328a --- /dev/null +++ b/tests/baselines/reference/typesOptionWildcardWithExplicit.symbols @@ -0,0 +1,26 @@ +//// [tests/cases/compiler/typesOptionWildcardWithExplicit.ts] //// + +=== /app.ts === +// With "types": ["*", "extra"], all @types packages are automatically included +// plus any explicitly listed types (even if they don't exist in @types) +// This is useful for gradual migration +$.x; +>$.x : Symbol(x, Decl(index.d.ts, 0, 16)) +>$ : Symbol($, Decl(index.d.ts, 0, 11)) +>x : Symbol(x, Decl(index.d.ts, 0, 16)) + +_.map; +>_.map : Symbol(map, Decl(index.d.ts, 0, 16)) +>_ : Symbol(_, Decl(index.d.ts, 0, 11)) +>map : Symbol(map, Decl(index.d.ts, 0, 16)) + +=== /node_modules/@types/jquery/index.d.ts === +declare var $: { x: number }; +>$ : Symbol($, Decl(index.d.ts, 0, 11)) +>x : Symbol(x, Decl(index.d.ts, 0, 16)) + +=== /node_modules/@types/lodash/index.d.ts === +declare var _: { map: any }; +>_ : Symbol(_, Decl(index.d.ts, 0, 11)) +>map : Symbol(map, Decl(index.d.ts, 0, 16)) + diff --git a/tests/baselines/reference/typesOptionWildcardWithExplicit.trace.json b/tests/baselines/reference/typesOptionWildcardWithExplicit.trace.json new file mode 100644 index 00000000000..01094f97ac3 --- /dev/null +++ b/tests/baselines/reference/typesOptionWildcardWithExplicit.trace.json @@ -0,0 +1,29 @@ +[ + "======== Resolving type reference directive 'jquery', containing file '/__inferred type names__.ts', root directory '/node_modules/@types'. ========", + "Resolving with primary search path '/node_modules/@types'.", + "File '/node_modules/@types/jquery/package.json' does not exist.", + "File '/node_modules/@types/jquery/index.d.ts' exists - use it as a name resolution result.", + "Resolving real path for '/node_modules/@types/jquery/index.d.ts', result '/node_modules/@types/jquery/index.d.ts'.", + "======== Type reference directive 'jquery' was successfully resolved to '/node_modules/@types/jquery/index.d.ts', primary: true. ========", + "======== Resolving type reference directive 'lodash', containing file '/__inferred type names__.ts', root directory '/node_modules/@types'. ========", + "Resolving with primary search path '/node_modules/@types'.", + "File '/node_modules/@types/lodash/package.json' does not exist.", + "File '/node_modules/@types/lodash/index.d.ts' exists - use it as a name resolution result.", + "Resolving real path for '/node_modules/@types/lodash/index.d.ts', result '/node_modules/@types/lodash/index.d.ts'.", + "======== Type reference directive 'lodash' was successfully resolved to '/node_modules/@types/lodash/index.d.ts', primary: true. ========", + "======== Resolving type reference directive 'extra', containing file '/__inferred type names__.ts', root directory '/node_modules/@types'. ========", + "Resolving with primary search path '/node_modules/@types'.", + "Looking up in 'node_modules' folder, initial location '/'.", + "Searching all ancestor node_modules directories for preferred extensions: Declaration.", + "File '/node_modules/extra.d.ts' does not exist.", + "File '/node_modules/@types/extra.d.ts' does not exist.", + "======== Type reference directive 'extra' was not resolved. ========", + "File '/node_modules/@types/jquery/package.json' does not exist according to earlier cached lookups.", + "File '/node_modules/@types/package.json' does not exist.", + "File '/node_modules/package.json' does not exist.", + "File '/package.json' does not exist.", + "File '/node_modules/@types/lodash/package.json' does not exist according to earlier cached lookups.", + "File '/node_modules/@types/package.json' does not exist according to earlier cached lookups.", + "File '/node_modules/package.json' does not exist according to earlier cached lookups.", + "File '/package.json' does not exist according to earlier cached lookups." +] \ No newline at end of file diff --git a/tests/baselines/reference/typesOptionWildcardWithExplicit.types b/tests/baselines/reference/typesOptionWildcardWithExplicit.types new file mode 100644 index 00000000000..495b8184e5b --- /dev/null +++ b/tests/baselines/reference/typesOptionWildcardWithExplicit.types @@ -0,0 +1,36 @@ +//// [tests/cases/compiler/typesOptionWildcardWithExplicit.ts] //// + +=== /app.ts === +// With "types": ["*", "extra"], all @types packages are automatically included +// plus any explicitly listed types (even if they don't exist in @types) +// This is useful for gradual migration +$.x; +>$.x : number +> : ^^^^^^ +>$ : { x: number; } +> : ^^^^^ ^^^ +>x : number +> : ^^^^^^ + +_.map; +>_.map : any +> : ^^^ +>_ : { map: any; } +> : ^^^^^^^ ^^^ +>map : any +> : ^^^ + +=== /node_modules/@types/jquery/index.d.ts === +declare var $: { x: number }; +>$ : { x: number; } +> : ^^^^^ ^^^ +>x : number +> : ^^^^^^ + +=== /node_modules/@types/lodash/index.d.ts === +declare var _: { map: any }; +>_ : { map: any; } +> : ^^^^^^^ ^^^ +>map : any +> : ^^^ + diff --git a/tests/cases/compiler/typesOptionWildcardWithExplicit.ts b/tests/cases/compiler/typesOptionWildcardWithExplicit.ts new file mode 100644 index 00000000000..6a122b1ec1c --- /dev/null +++ b/tests/cases/compiler/typesOptionWildcardWithExplicit.ts @@ -0,0 +1,19 @@ +// @traceResolution: true +// @noImplicitReferences: true +// @currentDirectory: / + +// @filename: /tsconfig.json +{ "compilerOptions": { "types": ["*", "extra"] } } + +// @filename: /node_modules/@types/jquery/index.d.ts +declare var $: { x: number }; + +// @filename: /node_modules/@types/lodash/index.d.ts +declare var _: { map: any }; + +// @filename: /app.ts +// With "types": ["*", "extra"], all @types packages are automatically included +// plus any explicitly listed types (even if they don't exist in @types) +// This is useful for gradual migration +$.x; +_.map;