What does TypeScript's `skipLibCheck` compiler option actually skip, and what real problems can it hide?
answer
- it skips checking, not reading
- errors inside the files, not at call sites
- not limited to node_modules
- your own declarations included
- conflicting library types go quiet
basics
~20 sskipLibCheck stops the compiler reporting errors found inside declaration files — all of them, including your own, not just node_modules. Your code is still checked against those declarations. It mainly hides broken or mutually conflicting library types.
solid answer
~50 s`skipLibCheck` tells `tsc` not to type-check the **contents** of `.d.ts` files. It does not stop the compiler from reading them: your source is still checked against every library type as usual. What disappears are errors that live *inside* declarations — a dependency whose types reference a `lib` you do not include, or two packages that declare the same global with incompatible shapes. Two things surprise people. First, the skip applies to **every** declaration file, including declarations you hand-wrote and the ones your own build emits, so a genuine mistake in your `.d.ts` goes unreported. Second, it is a real speed win on large dependency trees, which is why most starter templates turn it on. The judgment call is that it converts "my dependencies' types disagree" from a build failure into a silent inconsistency you meet later as a confusing error at a call site.
code
json · 9 lines{
"compilerOptions": {
"strict": true,
"skipLibCheck": true,
"declaration": true,
"outDir": "dist"
},
"include": ["src"]
}go deeper
Know that it turns off error reporting inside .d.ts files, that it is commonly on in starter configs, and that your own code is still fully type-checked.
Explain the read-versus-check distinction — declarations are still parsed and still constrain your code — and that the skip covers every declaration file, your own included.
Show the operational judgment: name what it hides in practice, such as conflicting global declarations or duplicate @types versions, and how you would still verify declarations you publish.
Set the policy — on by default for applications for build-time reasons, paired with a dedicated check-enabled verification of any declarations you ship — and be able to justify why suppressing dependency-internal errors is acceptable while suppressing your own is not.
## What the option does Every `.d.ts` in the program — the `lib.*.d.ts` files that describe JavaScript and the DOM, the declarations bundled in your dependencies, the `@types` packages, and any declaration you wrote yourself — is normally type-checked like any other file. `"skipLibCheck": true` suppresses the diagnostics produced *within* those files. The critical distinction: **skipping the check is not skipping the file**. The compiler still parses every declaration and still uses the types in it to check your code. If `@types/foo` says `parse(input: string): Config`, calling `parse(42)` is still an error with `skipLibCheck` on. Only errors whose location is inside a declaration file are dropped. ## Why teams turn it on Two reasons, and they are different in character. **Speed.** Checking thousands of declaration files across a large `node_modules` costs real time on every cold build. Skipping it is one of the cheapest wins available on a big project, which is why it appears in most scaffolded configs. **Unblocking.** A dependency ships declarations that do not compile under *your* configuration. Common causes: the declarations use a DOM type but your `lib` is Node-only; two installed versions of the same `@types` package declare the same global twice; a package's types were written against a newer compiler than yours. None of these are bugs in your code, and none are fixable by you in a hurry. `skipLibCheck` makes the build proceed. ```json { "compilerOptions": { "strict": true, "skipLibCheck": true } } ``` ## What it hides - **Conflicting global declarations.** Two libraries each declaring `interface Window { … }` or a duplicate global with incompatible members. Without the check, one wins arbitrarily and you get puzzling errors at call sites instead of a clear duplicate-identifier report. - **Version drift between packages.** A library's declarations reference types from a peer whose installed version no longer has them. Errors surface later and further from the cause. - **Your own declarations.** This is the one people miss. A hand-written ambient `.d.ts`, or the `.d.ts` your own library emits for publishing, is a declaration file too. If it is internally inconsistent — references a type that does not exist, or was written against a stale dependency — you will not hear about it, and your **consumers** will, because their build is where the error finally appears. ## The library-author angle For a package that publishes types, `skipLibCheck` in your own repo is a way to ship broken declarations without noticing. The mitigation is not to turn it off globally (you would inherit every dependency's problems) but to add a dedicated verification step: a small project that consumes your built `.d.ts` with `skipLibCheck` **off** and nothing else, so the only declarations being checked are yours. Some teams do this by type-checking the packed tarball in a scratch install. ## What it is not - It is not `skipDefaultLibCheck`, which is narrower and only covers the compiler's built-in `lib` files. - It does not exclude `node_modules` from the program, and it does not stop declarations from contributing globals. - It does not weaken checking of your own `.ts` files in any way. `strict` and `skipLibCheck` are orthogonal: you can and usually should have both on. - It does not make an untyped dependency typed; a package with no declarations is still an implicit `any` import. ## Reasonable position On most application codebases, on. The errors it suppresses are overwhelmingly not yours to fix, and the build-time saving is real. On a library that publishes declarations, keep it on for the main build but verify the emitted `.d.ts` separately with the check enabled, because there the declarations under suspicion are the ones you are asking other people to trust.
- With `skipLibCheck` on, is a call that violates a library's declared signature still an error?Yes. The compiler still reads every declaration and checks your source against it, so passing a number where the declaration says `string` still fails. Only diagnostics located *inside* declaration files are suppressed — the types themselves remain fully in force everywhere else.
- How would a library author get the safety back for their own published declarations?Keep `skipLibCheck` on for the main build, then add a separate verification project that type-checks the built `.d.ts` with the option off — ideally against the packed tarball in a scratch install. That way only your declarations are under scrutiny, and you find breakage before consumers do.
- What kind of failure typically pushes a team to enable it in the first place?Declarations that do not compile under the consumer's own configuration: a dependency using DOM types when `lib` is Node-only, two installed copies of the same `@types` package declaring a global twice, or types authored against a newer compiler. None are fixable in your code, so the option unblocks the build.
saying these in an interview costs you the question
- Thinks it stops the compiler from using library types at all
- Says it only applies to files under node_modules
- Believes it weakens strict checking of your own source
- Confuses it with excluding node_modules from the program
- Assumes it makes an untyped package typed