You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Feature Request: allow exclusion of node_modules when skipLibCheck is false #30511
All I've found is this lonely SO post. As that user notes, there are a lot of posts around Angular and excluding node_modules from typechecking on one dimension or another, but they all end up suggesting turning onskipLibCheck.
Suggestion
Allow the exclusion of files in node_modules (regardless of their inclusion in the Project) from lib checking when skipLibCheck is set to false.
Use Cases
I want to be able to typecheck my own.d.ts files without being responsible for all of the types my dependencies import. My local configuration is strict and it may be that the types provided in my packages were not intended strictly, or other configurations in my local JSON run up against the way other packages have written theirs.
I am assuming the counterargument is that it's all-or-nothing, but then why do .ts files that rely on.d.ts files typecheck fine when my .d.ts files are not typechecked? Can't that behavior be applied to definitions in node_modules?
Examples
Not sure how to show an example here. I would like to be able to run tsc --noEmit on my codebase and get errors for my own definitions files without having a bunch of noise from unfixable errors in node_modules/@types etc.
Checklist
My suggestion meets these guidelines:
This wouldn't be a breaking change in existing TypeScript/JavaScript code If implemented as some additional flag?
This wouldn't change the runtime behavior of existing JavaScript code
This could be implemented without emitting different JS based on the types of the expressions
This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
changed the title [-]Allow exclusion of node_modules from skipLibCheck[/-][+]Feature Request: allow exclusion of node_modules from skipLibCheck[/+]on Mar 20, 2019
It sounds like you're asking for the opposite - a mode for skipLibCheck that says only skip checking of .d.ts files from node_modules?
Reacted by cbdeveloper, Jon Lauridsen, Rusty, smiley-uriux, Mattias Hällkvist, Matthew Halloran, Rockys, Dougal Graham, Keal Jones, Thomas Mur and 8 more
changed the title [-]Feature Request: allow exclusion of node_modules from skipLibCheck[/-][+]Feature Request: allow exclusion of node_modules when skipLibCheck is false[/+]on Mar 26, 2019
FWIW I think this ongoing issue is my biggest use case for this flag: Styled-Components automatically includes React-Native types, which duplicate Node types, so if you use Styled-Components and Node, you mustskipLibCheck because of a long-standing problem that you have no power to fix
Reacted by Heather Booker, Boris Okunskiy, cbdeveloper and Tyler C Laprade, CFA
Another use-case for this feature comes from nexus.
Nexus has a novel "typegen" feature wherein based on user code a TS types file is generated and via interface-merging is able to imbue static guarantees on otherwise dynamic app code.
We are currently working on making the default disk location for this typegen be node_modules/@types/whatever/index.d.ts. This allows nexus to provide the typegen DX without any config demands upon the user.
Now, the motivation, for us, for this TS issue, is that nexus typegen would become weaker in the face of skipLibCheck. Advanced users can configure typegen output, but their getting it wrong while skipLibCheck: true would make it silently fail. This TS feature would help maintain our users' confidence in nexus typegen even in situations where they need to skipLibCheck for just one or two libs in their project.
I am not sure if it would make sense or whether this has any negative effect, but the only way I could make sure my declaration files didn't have any errors, was to rename all .d.ts to .ts, while keeping skipLibCheck=true.
I faced many situations where I did have errors on my .d.ts files to only figure it out once those were then checked by tsc after being renamed.
I might be missing something though.
Reacted by Seyi Adebajo, Tyler C Laprade, CFA and robert-melonn
My use case for this is also related to the styled-components and @types/react-native issue. I'm getting 40 errors.
It does not harm my code, so I would like to ignore all those errors by setting --skipLibChecks: true, while still checking and getting errors for my own .d.ts files inside my src folder.
Any updates on this?
Reacted by Chris Schmitz, Seyi Adebajo, Adam Spiers, roihassecb, norbornen, robert-melonn, gedalez and Jim Blackler
We discussed this today and decided that its fate is linked to that of #39231. Currently, we have a fairly coherent posture that .d.ts files are either outputs or they describe the shape of colocated JS (as in libraries), but they’re not inputs to be hand-authored. There are reasons to reconsider that stance, but we would do so altogether, and such a change in perspective would likely address this issue and #39231, but it’s not something we’re actively exploring right now.
Reacted by Paweł Dymara, Matthew Dean, robert-melonn, Daniel Kaplan, Kevin Fleischman, NightKev, Sébastien Mischler and lolifamily
which says that any .d.ts file in your files or include pattern is checked, but any .d.ts file that gets into your program via other means is not (e.g. node_modules imports, output .d.ts files from upstream project references)
Thoughts?
Reacted by Artem Kazaryan, Seyi Adebajo, vilicvane, Emilio Srougo, smiley-uriux, Jake Bailey, Alex Weininger, Mattias Hällkvist, Jake Boone, Jonny Rathbone and 58 more
Reacted by Seyi Adebajo, smiley-uriux, Jake Boone, Jonny Rathbone, Dani Akash, salagadoola, Dailos Rafael Díaz Lara, Marvin Horitani, Adam Spiers, DongKeon Kim / 김동건 and 14 more
We discussed this today and decided that its fate is linked to that of #39231. Currently, we have a fairly coherent posture that .d.ts files are either outputs or they describe the shape of colocated JS (as in libraries), but they’re not inputs to be hand-authored. There are reasons to reconsider that stance, but we would do so altogether, and such a change in perspective would likely address this issue and #39231, but it’s not something we’re actively exploring right now.
Those files are not exempt from the behavior I described. If you import from type-fest with the compiler option --importsNotUsedAsValues preserve, the output will crash despite not hearing an error from us. When type-fest exposes module .d.ts files that export types, it implies that there are corresponding .js files that export nothing, which is very different from there not being .js files. To correctly reason about a library like type-fest, we would need a completely new concept of a type-only module, which is known to have no runtime counterpart. Alternatively, collections of utility types could choose to declare a global namespace rather than modules, so users would just use tf.EmptyObject instead of importing EmptyObject, for example. But I understand why that feels less desirable. Fortunately, the majority of users have no reason to set --importsNotUsedAsValues preserve, and many folks are writing import type for these imports anyway, so in practice, I don’t think anyone is getting hit by this. But hopefully it explains that yes, even type-fest technically implies the existence of a set of empty .js modules.
I am trying to enable project references in Babel to speed up incremental type checking, and this is being a partial blocker.
We cannot use skipLibCheck, because we have multiple manually-written .d.ts files that need to be checked. When migrating to project references, type checking gets more than 3x slower:
"monolithic project" with skipLibCheck: false takes ~3 minutes
project references with skipLibCheck: false takes ~10 minutes
project references with skipLibCheck: true takes ~3 minutes
As a workaround, we are probably going to use skipLibCheck: true in most projects expect for the ones that contain manually-written .d.ts files, but:
it still incurs in a ~20 seconds performance penalty for each project that has skipLibCheck: false
it's easy to accidentally forget to set skipLibCheck: false in a project when adding a .d.ts file.
For this use case, skipLibCheck should accept a pattern so that I can exclude .d.ts files generated by tsc (while still type-checking manually-written .d.ts and .d.ts from my dependencies):
That difference seems surprising. Do you have an active PR/branch with the above I could test? I was thinking it might be babel/babel#16416 but that doesn't actually seem to be it.
I fully agree with this. Another (admitted niche) user case: I'm using https://github.com/Tencent/puerts for my game It's a Javascript/Typescript runtime for Unity. To access C# runtime from Typescript, it generated *.d.ts files from C# classes. However, in most case you'd like to draw a clear line between C# codebase and Typescript codebase, and therefore only want to generate *.d.ts for a few classes that "glue" between C# and TS.
Obviously, it would cause some unresolvable symbols in those generated *.d.ts, and it's totally fine. But I'd still like to check other *.d.ts files that are NOT generated from C#.
Hello Ryan Cavanaugh (@RyanCavanaugh)Andrew Branch (@andrewbranch) , is there any intention to review these types of cases? There are a lot of issues referencing these behaviours but nothing concrete is achieved. There are a lot of use cases for having this property skipping folder patterns, something like skipLibCheck: ["node_modules/", "./src/undesired_handwritten.d.ts"].
Even working with project references is a nightmare when it comes to monorepos (widely used today). I feel that no one has paid attention to specific behaviors that typescript has (or ignores them) otherwise the community would have stopped using typescript a long time ago.
There are some big gaps in the explanations of how tsconfig files actually work. I absolutely believe that more than 90% of the community believes that an exclude: ["node_modules/"] is saying that typescript will not check for files in that folder so they are ignored even though the documentation explains it. Configuration properties names must convey their intent, which tsconfig files do not.
There are problems when dealing with typescript projects from different environments (or intentions), such as whether I want to verify source, tests, storybook, e2e, build or node files. I'm almost sure people think that adding a tsconfig.node.json
will actually check the types of your included files (unless you specify that file in the tsc command). We don't have a clear way to check everything at once avoiding type collisions, configurations, without using the annoying, unpredictable, slow and almost undocumented project references. On many occasions I have seen proposals and suggestions from the community, such as an override per environment in a single tsconfig.json file, but I feel that everything the community suggests is still being ignored, even if it solves real problems .
We must do something
Reacted by Albert Portnoy, Vitaliy Potapov, Maksym Mozghovoi, Tomo Yanagi, Kevin Ghadyani, georgetzlp, gedalez, Daniel Kaplan, Stein Strindhaug, darcyrush and 3 more
I probably riding the bandwagon here, but I want to add my thoughts as someone who runs into this issue in every single TS project and has yet to find a suitable solution. I've always enabled skipLibCheck, but the fact that it doesn't check types in my local index.d.ts files is something I know but most don't. I remember when I first found that out by mistake.
Type checking someone else's files
It makes no sense to me that I'd wanna check someone else's types when it's their job to check their own types before releasing a version of their library. I have to have trust that the library I'm importing is both tested and functional; I can't make an assumption that they did everything wrong because fixing it isn't my job, and not something I can easily control.
I'm sure there's a great argument for why you need to check someone else's types in your library similar to the argument for why it's important to re-bundle someone else's production library code because they might've used a different browserslist config.
As unintuitive as it may seem, skipLibCheck: true should probably be the default. Like robert-melonn suggested, I assumed that excluding a directory also excludes it from type checking. Wasting hours on an issue caused by an unintuitive config file setting isn't a great user experience. TypeScript will have more new users than old users over time, and they're all gonna run into this same issue as I did. It's a 100% given. I don't know anyone who hasn't run into this issue.
How I got here
The entire reason I found this thread is because I'm trying to figure out a way to have local index.d.ts files for when I need to create types for a 3rd party library, but that file isn't typechecked, and any attempt at doing types.ts doesn't work the same when using "type": "module". If this is supposed to work, I'd argue the documentation is lacking, and that all stems from the fact that it's unintuitive.
There are a lot of use cases for having this property skipping folder patterns, something like skipLibCheck: ["node_modules/", "./src/undesired_handwritten.d.ts"].
I'd like to say I prefer something similar to robert-melonn 's idea. Maybe this property could be extended to take glob patterns. I would probably want to use something like this: skipLibCheck: ["!./src/**"] to say, "Exclude every lib check except those in my src dir.
To summarize, testcafe-hammerhead has a dependency whose types conflict with typescript's own (node-lru-cache). But I don't want to skipLibCheck: true because I had to write some type declarations by hand: I'm using old versions of libraries that predate DefinitelyTyped types. Current versions of the library have @types, but not the versions I'm using.
In the meanwhile, I created the following script to report all issues (skipLibCheck: false) but excluding the ones coming from node_modules. It is meant to be used in projects with references (incremental builds) (equivalent to tsc --build).
I use TypeScript - 5.8.3
const{readFile}=require('node:fs/promises');const{dirname, join, relative}=require('node:path');constignore=require('ignore');const{
formatDiagnostic,
sys,
createSolutionBuilderHost,
getParsedCommandLineOfConfigFile,
DiagnosticCategory,
formatDiagnosticsWithColorAndContext,
createSolutionBuilder
}=require('typescript');// https://github.com/microsoft/TypeScript/issues/30511// https://github.com/microsoft/TypeScript/issues/62035constscript={name: 'build-types',fn: async(input={})=>{constbasePath=dirname(input.configFile);constignoreFilePath=join(basePath,'.buildtypesignore');constignoreFileContent=awaitreadFile(ignoreFilePath).then((content)=>content.toString()).catch((err)=>{if(err.code==='ENOENT'){returnnull;}else{throwerr;}});constig=ignore();if(ignoreFileContent){ig.add(ignoreFileContent);}// FUNCTIONS TO FORMAT DIAGNOSTICS (REUSED FOR CONSISTENCY)constformat=(diagnostic)=>{returnformatDiagnostic(diagnostic,{getCanonicalFileName: (fileName)=>fileName,getCurrentDirectory: sys.getCurrentDirectory,getNewLine: ()=>sys.newLine});};constformatWithColorAndContext=(diagnostic)=>{returnformatDiagnosticsWithColorAndContext([diagnostic],{getCanonicalFileName: (fileName)=>fileName,getCurrentDirectory: sys.getCurrentDirectory,getNewLine: ()=>sys.newLine});};constcontext={lastProjectName: null,externalDiagnostics: [],internalDiagnostics: [],configsMap: newMap(),diagnosticsMetaMap: newWeakMap(),isLibCheckOverride: false};// CREATE THE DEFAULT SOLUTION BUILDER HOST FIRSTconstdefaultHost=createSolutionBuilderHost(sys);// NOW, CREATE A CUSTOM HOST BY EXTENDING THE DEFAULT ONEconstcustomHost={
...defaultHost,createProgram: (...args)=>{constprogram=defaultHost.createProgram(...args);const[,options]=args;context.lastProjectName=options.configFilePath||null;returnprogram;},// OVERRIDE getParsedCommandLine TO MODIFY OPTIONS FOR EACH PROJECT. THIS FUNCTION IS CALLED BY THE SOLUTION BUILDER FOR EACH TSCONFIG FILE IT PROCESSESgetParsedCommandLine: (fileName)=>{constparsed=getParsedCommandLineOfConfigFile(fileName,{},{
...sys,onUnRecoverableConfigFileDiagnostic: (diagnostic)=>{console.error(format(diagnostic));}});if(typeofparsed!=='object'||parsed===null){returnparsed;}// ADJUST CONFIG FOR LIB CHECKINGif(typeofinput.libCheck==='boolean'){if(input.libCheck){if(parsed.options.skipLibCheck){context.isLibCheckOverride=true;}parsed.options.noEmitOnError=false;parsed.options.skipLibCheck=false;}else{parsed.options.skipLibCheck=true;}}context.configsMap.set(parsed.options.configFilePath,{rootDir: parsed.options.rootDir,declarationDir: parsed.options.declarationDir});returnparsed;},// OVERRIDE reportDiagnostic TO ADD FILTERING LOGICreportDiagnostic: (diagnostic)=>{if(!diagnostic.file){return;}constfilePath=diagnostic.file.fileName;if(ig.ignores(relative(basePath,filePath))){return;}// FILTER DIAGNOSTICS: SEPARATE EXTERNAL AND INTERNAL ONESif(filePath.includes('node_modules')||filePath.includes('.yarn')){context.externalDiagnostics.push(diagnostic);context.diagnosticsMetaMap.set(diagnostic,{
filePath,project: context.lastProjectName,scope: 'external'});}else{context.internalDiagnostics.push(diagnostic);context.diagnosticsMetaMap.set(diagnostic,{
filePath,project: context.lastProjectName,scope: 'internal'});}},// OVERRIDE reportSolutionBuilderStatusreportSolutionBuilderStatus: (diagnostic)=>{// THESE ARE USUALLY BUILD STATUS MESSAGES, NOT CODE ERRORS.console.log(format(diagnostic));}};// CREATE THE SOLUTION BUILDER USING THE CUSTOM HOSTconstbuilder=createSolutionBuilder(customHost,// PATH TO THE ROOT tsconfig.json (THE ONE WITH ALL PROJECTS 'references')[input.configFile],{verbose: input.verbose,stopBuildOnErrors: input.bail});// EXECUTE THE BUILDconsole.log();console.log('STARTING SOLUTION BUILD...');console.log();builder.build();console.log('SOLUTION BUILD FINISHED.');console.log();letoutput=[];switch(input.showDiagnostics){case'all':
output=[
...context.internalDiagnostics,
...context.externalDiagnostics];break;case'internal':
output=[...context.internalDiagnostics];break;case'external':
output=[...context.externalDiagnostics];break;case'none':
default:
break;}// AFTER THE BUILD, FORMAT AND PRINT THE COLLECTED DIAGNOSTICS ACCORDING TO OPTIONSif(output.length){console.log('DIAGNOSTICS:\n');constshowCategory=(diagnostic)=>{letlabel;switch(diagnostic.category){caseDiagnosticCategory.Warning:
label='WARNING';break;caseDiagnosticCategory.Error:
label='ERROR';break;caseDiagnosticCategory.Suggestion:
label='INFO';break;caseDiagnosticCategory.Message:
label='MESSAGE';break;default:
label='UNKNOWN';break;}console.log(`CATEGORY: ${label}`);};constshowLocation=(meta)=>{constconfig=context.configsMap.get(meta.project);if(config&&meta.filePath){if(meta.scope==='internal'){if(config.declarationDir&&meta.filePath.startsWith(config.declarationDir)){console.log('LOCATION: DECLARATION');}elseif(config.rootDir&&meta.filePath.startsWith(config.rootDir)){console.log('LOCATION: SOURCE');}else{console.log('LOCATION: OUTSIDE OF SOURCE');}}else{console.log('LOCATION: DEPENDENCY');}}else{console.log('LOCATION: UNKNOWN');}};switch(input.groupDiagnosticsBy){case'project': {constgroups={};output.forEach((diagnostic)=>{constmeta=context.diagnosticsMetaMap.get(diagnostic);if(groups[meta.project]){groups[meta.project].push({diagnostic, meta});}else{groups[meta.project]=[{diagnostic, meta}];}});Object.entries(groups).forEach(([project,entries],index,array)=>{console.log(`PROJECT: ${project}\n`);entries.forEach(({diagnostic, meta})=>{showCategory(diagnostic);showLocation(meta);constformatted=formatWithColorAndContext(diagnostic);console.log(formatted);});if(index<array.length-1){console.log('\n---\n');}});break;}case'none':
default:
output.forEach((diagnostic,index)=>{constmeta=context.diagnosticsMetaMap.get(diagnostic);console.log(`PROJECT: ${meta.project||'Unknown'}`);showCategory(diagnostic);showLocation(meta);constformatted=formatWithColorAndContext(diagnostic);console.log(formatted);if(index<output.length-1){console.log('\n---\n');}});break;}}console.log();console.log(`DIAGNOSTICS FOUND: ${output.length}`);console.log();if(output.length){if(context.isLibCheckOverride){console.log('YOU MIGHT NEED TO TEMPORARILY DISABLE "skipLibCheck" IN YOUR TYPESCRIPT CONFIG TO ADDRESS VIA YOUR IDE');}if(input.ci){thrownewError('BUILD CONTAINS ERRORS. SEE LOGS ABOVE.');}}}};module.exports={script};
Inputs:
constinputs={configFile: {type: 'string',describe: 'Path to config file'},verbose: {type: 'boolean',describe: 'Increase verbosity of the output'},groupDiagnosticsBy: {type: 'string',describe: 'Specifies how diagnostics should be grouped',choices: ['project','none']},showDiagnostics: {type: 'string',describe: 'Specifies which diagnostics should be showed',choices: ['all','internal','external','none']},libCheck: {type: 'boolean',describe: 'Whether to check libraries'},ci: {type: 'boolean',describe: 'Throw if diagnostics are found'},bail: {type: 'boolean',describe: 'Exit on first diagnostic'}};
We discussed this today and decided that its fate is linked to that of #39231. Currently, we have a fairly coherent posture that .d.ts files are either outputs or they describe the shape of colocated JS (as in libraries), but they’re not inputs to be hand-authored. There are reasons to reconsider that stance, but we would do so altogether, and such a change in perspective would likely address this issue and #39231, but it’s not something we’re actively exploring right now.
This ignores the reality of how TS is being used and degrades DX. Please "actively explore" changing this.
I'd propose a new setting
`"skipLibCheck": "external"
which says that any .d.ts file in your files or include pattern is checked, but any .d.ts file that gets into your program via other means is not (e.g. node_modules imports, output .d.ts files from upstream project references)
I understand the design intent, but this does not match real-world TypeScript usage.
.d.ts files are very often hand-authored. That is the entire purpose of DefinitelyTyped, and it is explicitly documented in the official handbook (1, 2). Treating them as “outputs only” ignores a common and documented workflow and directly leads to the skipLibCheck DX issues raised in this thread.
Reacted by georgetzlp, Jake 'Sid' Smith, Daniel Kaplan, Daniel Power, Christian and Dixon Sean Low Yan Feng
Activity
[-]Allow exclusion of node_modules from skipLibCheck[/-][+]Feature Request: allow exclusion of node_modules from skipLibCheck[/+]RyanCavanaugh commentedon Mar 26, 2019
It sounds like you're asking for the opposite - a mode for
skipLibCheckthat says only skip checking of .d.ts files fromnode_modules?bensaufley commentedon Mar 26, 2019
You're right, that wasn't the right phrasing (I was thinking of
skipLibCheck: false—excluded from enabled libCheck).[-]Feature Request: allow exclusion of node_modules from skipLibCheck[/-][+]Feature Request: allow exclusion of node_modules when skipLibCheck is false[/+]bensaufley commentedon Jul 5, 2019
FWIW I think this ongoing issue is my biggest use case for this flag: Styled-Components automatically includes React-Native types, which duplicate Node types, so if you use Styled-Components and Node, you must
skipLibCheckbecause of a long-standing problem that you have no power to fixjasonkuhrt commentedon Sep 30, 2019
Another use-case for this feature comes from nexus.
Nexus has a novel "typegen" feature wherein based on user code a TS types file is generated and via interface-merging is able to imbue static guarantees on otherwise dynamic app code.
We are currently working on making the default disk location for this typegen be
node_modules/@types/whatever/index.d.ts. This allows nexus to provide the typegen DX without any config demands upon the user.Now, the motivation, for us, for this TS issue, is that nexus typegen would become weaker in the face of
skipLibCheck. Advanced users can configure typegen output, but their getting it wrong whileskipLibCheck: truewould make it silently fail. This TS feature would help maintain our users' confidence in nexus typegen even in situations where they need toskipLibCheckfor just one or two libs in their project.Hope that makes sense :)
zanona commentedon Nov 27, 2020
I completely agree with the author.
I am not sure if it would make sense or whether this has any negative effect, but the only way I could make sure my declaration files didn't have any errors, was to rename all
.d.tsto.ts, while keepingskipLibCheck=true.I faced many situations where I did have errors on my
.d.tsfiles to only figure it out once those were then checked bytscafter being renamed.I might be missing something though.
cbdeveloper commentedon Jan 6, 2021
My use case for this is also related to the
styled-componentsand@types/react-nativeissue. I'm getting 40 errors.It does not harm my code, so I would like to ignore all those errors by setting
--skipLibChecks: true, while still checking and getting errors for my own.d.tsfiles inside mysrcfolder.Any updates on this?
andrewbranch commentedon Aug 30, 2021
We discussed this today and decided that its fate is linked to that of #39231. Currently, we have a fairly coherent posture that
.d.tsfiles are either outputs or they describe the shape of colocated JS (as in libraries), but they’re not inputs to be hand-authored. There are reasons to reconsider that stance, but we would do so altogether, and such a change in perspective would likely address this issue and #39231, but it’s not something we’re actively exploring right now.RyanCavanaugh commentedon Apr 19, 2022
I'd propose a new setting
which says that any
.d.tsfile in yourfilesorincludepattern is checked, but any.d.tsfile that gets into your program via other means is not (e.g. node_modules imports, output .d.ts files from upstream project references)Thoughts?
skarab42 commentedon Sep 21, 2022
What about this kind of types collection? https://github.com/sindresorhus/type-fest
fix: revert `skipLibCheck` to true
andrewbranch commentedon Sep 21, 2022
Those files are not exempt from the behavior I described. If you import from type-fest with the compiler option
--importsNotUsedAsValues preserve, the output will crash despite not hearing an error from us. When type-fest exposes module .d.ts files that export types, it implies that there are corresponding .js files that export nothing, which is very different from there not being .js files. To correctly reason about a library like type-fest, we would need a completely new concept of a type-only module, which is known to have no runtime counterpart. Alternatively, collections of utility types could choose to declare a global namespace rather than modules, so users would just usetf.EmptyObjectinstead of importingEmptyObject, for example. But I understand why that feels less desirable. Fortunately, the majority of users have no reason to set--importsNotUsedAsValues preserve, and many folks are writingimport typefor these imports anyway, so in practice, I don’t think anyone is getting hit by this. But hopefully it explains that yes, even type-fest technically implies the existence of a set of empty .js modules.4 remaining items
nicolo-ribaudo commentedon Apr 14, 2024
Coming here from #43140.
I am trying to enable project references in Babel to speed up incremental type checking, and this is being a partial blocker.
We cannot use
skipLibCheck, because we have multiple manually-written.d.tsfiles that need to be checked. When migrating to project references, type checking gets more than 3x slower:skipLibCheck: falsetakes ~3 minutesskipLibCheck: falsetakes ~10 minutesskipLibCheck: truetakes ~3 minutesAs a workaround, we are probably going to use
skipLibCheck: truein most projects expect for the ones that contain manually-written.d.tsfiles, but:skipLibCheck: falseskipLibCheck: falsein a project when adding a.d.tsfile.For this use case,
skipLibCheckshould accept a pattern so that I can exclude.d.tsfiles generated bytsc(while still type-checking manually-written.d.tsand.d.tsfrom my dependencies):{ "compilerOptions": { "skipLibCheck": [ "./packages/*/lib/**/*.d.ts", "./codemods/*/lib/**/*.d.ts", "./eslint/*/lib/**/*.d.ts", ] }, }I'd be happy to open a PR for it.
jakebailey commentedon Apr 14, 2024
That difference seems surprising. Do you have an active PR/branch with the above I could test? I was thinking it might be babel/babel#16416 but that doesn't actually seem to be it.
test/static-code: tweak Typescript config again
test/static-code: tweak Typescript config again
test/static-code: tweak Typescript config again
kodra-dev commentedon Sep 9, 2024
I fully agree with this. Another (admitted niche) user case: I'm using https://github.com/Tencent/puerts for my game It's a Javascript/Typescript runtime for Unity. To access C# runtime from Typescript, it generated
*.d.tsfiles from C# classes. However, in most case you'd like to draw a clear line between C# codebase and Typescript codebase, and therefore only want to generate*.d.tsfor a few classes that "glue" between C# and TS.Obviously, it would cause some unresolvable symbols in those generated
*.d.ts, and it's totally fine. But I'd still like to check other*.d.tsfiles that are NOT generated from C#.robert-melonn commentedon Oct 29, 2024
Hello Ryan Cavanaugh (@RyanCavanaugh) Andrew Branch (@andrewbranch) , is there any intention to review these types of cases? There are a lot of issues referencing these behaviours but nothing concrete is achieved. There are a lot of use cases for having this property skipping folder patterns, something like
skipLibCheck: ["node_modules/", "./src/undesired_handwritten.d.ts"].Even working with project references is a nightmare when it comes to monorepos (widely used today). I feel that no one has paid attention to specific behaviors that typescript has (or ignores them) otherwise the community would have stopped using typescript a long time ago.
There are some big gaps in the explanations of how tsconfig files actually work. I absolutely believe that more than 90% of the community believes that an
exclude: ["node_modules/"]is saying that typescript will not check for files in that folder so they are ignored even though the documentation explains it. Configuration properties names must convey their intent, which tsconfig files do not.There are problems when dealing with typescript projects from different environments (or intentions), such as whether I want to verify source, tests, storybook, e2e, build or node files. I'm almost sure people think that adding a tsconfig.node.json
will actually check the types of your included files (unless you specify that file in the tsc command). We don't have a clear way to check everything at once avoiding type collisions, configurations, without using the annoying, unpredictable, slow and almost undocumented project references. On many occasions I have seen proposals and suggestions from the community, such as an override per environment in a single tsconfig.json file, but I feel that everything the community suggests is still being ignored, even if it solves real problems .
We must do something
KevinGhadyani-Okta commentedon Nov 7, 2024
My 2 cents
I probably riding the bandwagon here, but I want to add my thoughts as someone who runs into this issue in every single TS project and has yet to find a suitable solution. I've always enabled
skipLibCheck, but the fact that it doesn't check types in my localindex.d.tsfiles is something I know but most don't. I remember when I first found that out by mistake.Type checking someone else's files
It makes no sense to me that I'd wanna check someone else's types when it's their job to check their own types before releasing a version of their library. I have to have trust that the library I'm importing is both tested and functional; I can't make an assumption that they did everything wrong because fixing it isn't my job, and not something I can easily control.
I'm sure there's a great argument for why you need to check someone else's types in your library similar to the argument for why it's important to re-bundle someone else's production library code because they might've used a different
browserslistconfig.As unintuitive as it may seem,
skipLibCheck: trueshould probably be the default. Like robert-melonn suggested, I assumed that excluding a directory also excludes it from type checking. Wasting hours on an issue caused by an unintuitive config file setting isn't a great user experience. TypeScript will have more new users than old users over time, and they're all gonna run into this same issue as I did. It's a 100% given. I don't know anyone who hasn't run into this issue.How I got here
The entire reason I found this thread is because I'm trying to figure out a way to have local
index.d.tsfiles for when I need to create types for a 3rd party library, but that file isn't typechecked, and any attempt at doingtypes.tsdoesn't work the same when using"type": "module". If this is supposed to work, I'd argue the documentation is lacking, and that all stems from the fact that it's unintuitive.thorn0 commentedon Nov 7, 2024
Kevin Ghadyani (@KevinGhadyani-Okta) Use
declare global { ... }instead of the.d.tsextension. Same thing but not affected byskipLibCheck.robert-melonn commentedon Nov 8, 2024
Georgii Dolzhykov (@thorn0) declare global is just for modules that use window object. It shouldnt be used arbitrarily
DanKaplanSES commentedon Mar 1, 2025
Ryan Cavanaugh (@RyanCavanaugh):
robert-melonn:
I'd like to say I prefer something similar to robert-melonn 's idea. Maybe this property could be extended to take glob patterns. I would probably want to use something like this:
skipLibCheck: ["!./src/**"]to say, "Exclude every lib check except those in mysrcdir.Here's my use case: DevExpress/testcafe-hammerhead#3036
To summarize, testcafe-hammerhead has a dependency whose types conflict with typescript's own (node-lru-cache). But I don't want to
skipLibCheck: truebecause I had to write some type declarations by hand: I'm using old versions of libraries that predate DefinitelyTyped types. Current versions of the library have@types, but not the versions I'm using.ernestostifano commentedon Jul 10, 2025
In the meanwhile, I created the following script to report all issues (
skipLibCheck: false) but excluding the ones coming fromnode_modules. It is meant to be used in projects with references (incremental builds) (equivalent totsc --build).I use
TypeScript - 5.8.3Inputs:
I call it via a CLI created with yargs.
UPDATE: Script edited to include more features.
NOTE: Beware of #62035
alexsch01 commentedon Aug 8, 2025
Any update on this?
DayKev commentedon Jan 15, 2026
^ #30511 (comment)
This ignores the reality of how TS is being used and degrades DX. Please "actively explore" changing this.
^ #30511 (comment)
Yes, please. 🙏
skarab42 commentedon Jan 15, 2026
I understand the design intent, but this does not match real-world TypeScript usage.
.d.ts files are very often hand-authored. That is the entire purpose of DefinitelyTyped, and it is explicitly documented in the official handbook (1, 2). Treating them as “outputs only” ignores a common and documented workflow and directly leads to the skipLibCheck DX issues raised in this thread.