TS2304: Cannot find name 'X' fires when TypeScript sees an identifier that is not declared anywhere it can see. Almost always caused by a missing import, missing @types/* package, or missing lib entry in tsconfig.json. Here is the complete 2026 fix guide.
Why TS2304 happens
TypeScript builds a scope of declared names. If your code references a name that is not in any scope (local variable, imported symbol, ambient declaration, or lib type), TS2304 fires. Fix by importing the name, installing the missing types package, or adding the appropriate lib.
Fix 1: missing import
// WRONG
function greet() {
console.log(useState(0));
// TS2304: Cannot find name 'useState'.
}
// FIX
import { useState } from "react";
function greet() {
console.log(useState(0));
}Fix 2: missing @types/* package
// WRONG in Node.js code
const port = process.env.PORT;
// TS2304: Cannot find name 'process'.
// FIX: install Node types
// pnpm add -D @types/node
// or: npm install --save-dev @types/node
// Then TS knows about process, Buffer, __dirname, etc.
const port = process.env.PORT; // worksCommon @types/* packages you may be missing:
@types/nodefor Node.js globals@types/reactfor React APIs@types/react-domfor ReactDOM APIs@types/expressfor Express handlers@types/lodashfor lodash
Fix 3: missing DOM lib for browser globals
// WRONG (in a Node-only project)
const modal = document.querySelector(".modal");
// TS2304: Cannot find name 'document'.
// FIX: add DOM to tsconfig.json lib
// {
// "compilerOptions": {
// "lib": ["ES2022", "DOM", "DOM.Iterable"]
// }
// }Fix 4: missing globals declaration
// You use a global from an old script tag or bundled lib
console.log(analytics.trackEvent("view"));
// TS2304: Cannot find name 'analytics'.
// FIX: declare the global in a .d.ts file
// types/globals.d.ts
declare global {
interface Window {
analytics: {
trackEvent(name: string): void;
};
}
const analytics: {
trackEvent(name: string): void;
};
}
export {}; // required for global augmentation
// Now analytics is known
analytics.trackEvent("view");Debugging checklist
- Is the name a variable? Add an import.
- Is it a Node.js API (process, Buffer)? Install
@types/node. - Is it a browser API (document, window)? Add
DOMtotsconfig.jsonlib. - Is it a third-party library? Install the library’s own types or
@types/*package. - Is it a global your app injects? Declare it in a
.d.tsfile.
Real-world example: Node.js + browser hybrid
// tsconfig.json for a full-stack Next.js app
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022", "DOM", "DOM.Iterable"], // browser + modern JS
"types": ["node"], // Node.js globals
"moduleResolution": "bundler",
"strict": true,
"skipLibCheck": true
}
}
// Now both fs (Node) and document (browser) are recognized
// depending on file contextCommon mistakes when fixing TS2304
- Installing the wrong
@types/*package. Confirm the package name matches. Some libraries bundle their own types now. - Adding
declare constwithoutexport {}. Global augmentation needs the empty export in the file. - Editing
node_modules/@typesdirectly. Gets overwritten. Use module augmentation in your own.d.ts. - Using
@ts-ignore. Hides the error but leaves the runtime bug (if the global does not actually exist).
Debugging TypeScript errors systematically
TypeScript errors follow a predictable pattern once you understand the compiler’s logic. Before jumping to fixes, run through this diagnostic checklist.
- Read the FULL error message. The compiler tells you both the actual type it sees and the expected type. Match them side by side to spot the mismatch.
- Check strictNullChecks and strict mode. Many errors trace back to
strict: truein tsconfig.json. If you inherited a codebase with strict mode on, expect more errors than in loose mode. - Look at inferred types with hover. VS Code shows inferred types on hover. Compare what TypeScript sees vs what you assumed.
- Use // @ts-expect-error strategically. When you know better than the compiler temporarily, mark the line. TypeScript flags the annotation when the underlying issue is fixed.
- Isolate the failing line in a minimal reproducer. A standalone
.tsfile with hardcoded inputs often surfaces the root cause faster than debugging in place.
Common TypeScript configuration issues
Many “why does this not compile” issues trace back to tsconfig.json, not your code.
- strict flag toggles many checks at once.
strict: trueenables strictNullChecks, noImplicitAny, strictFunctionTypes, and more. Turning on strict without preparing your code produces hundreds of errors. - Version mismatch between global and project TypeScript. Different TypeScript versions produce different errors. Pin the version in package.json for consistency.
- skipLibCheck can hide real issues. Setting
skipLibCheck: truespeeds up compilation but hides type mismatches in dependencies. Fine for CI but keep it off during development. - Path aliases and moduleResolution mismatches. The
pathsconfig in tsconfig only works with the right moduleResolution setting. Match “bundler” for Vite, “node16” for Node. - Ambient declarations vs modules. Files with imports are modules; files without imports are ambient scripts. Some errors happen because a file is treated as one when you expected the other.
Production TypeScript best practices
Once you get past errors and ship code, keep these habits to prevent recurring problems.
- Enable strict mode from day 1 on new projects. Migrating to strict later is 10x more work.
- Never use
anywithout a good reason.unknownis safer and forces you to narrow before use. - Avoid type assertions (
as) except at API boundaries. Assertions bypass the type system. Use them sparingly at edges (JSON parsing, DOM, external APIs). - Prefer type over interface for new code. Type aliases work everywhere interfaces do, plus support unions, intersections, and mapped types.
- Test type-level logic. Tools like
expect-typeortsdlet you write tests for your type definitions.
Learning resources for TypeScript
Beyond fixing the current error, deeper TypeScript knowledge pays dividends for years. Recommended starting points:
- Official Handbook. typescriptlang.org/docs/handbook. The canonical reference, well-written and up-to-date.
- Total TypeScript by Matt Pocock. Free tutorials and paid courses. Best for going from junior to advanced TypeScript.
- Type Challenges GitHub repo. Interactive problems that build type-level programming skills.
- TypeScript Deep Dive. Free online book, especially good for the “why” behind features.
- Try in the playground. typescriptlang.org/play lets you experiment with types and see errors immediately.
TypeScript version considerations
Compiler errors can change slightly between TypeScript versions. TypeScript 5.0+ introduced better error messages for many common issues. If you are on 4.x, upgrading may automatically improve diagnostic quality without any code change. Check your package.json for the pinned typescript version, then compare against the release notes at github.com/microsoft/TypeScript/releases before upgrading in production.
Official documentation
Frequently Asked Questions
Why does @types/node fix so many errors?
Node.js exposes lots of globals (process, Buffer, __dirname). Without @types/node, TypeScript sees none of them. Almost every Node.js TS project needs this package.
Do I need DOM lib for React?
Yes for browser-rendered React. Server Components can skip DOM lib. Most Next.js starter tsconfigs include DOM by default.
What if the library has no @types/* package?
Write a minimal .d.ts in your project. Even declare module "some-lib"; silences TS2304 and TS7016 while you use the library.
Should I put custom types in a specific folder?
Convention is types/ or @types/ at project root. Make sure your tsconfig.json‘s include array covers it, or the compiler ignores the file.
Are TS2304 and TS2503 different?
TS2304 is any name, TS2503 is namespace-specific. Same fix approach: import the missing thing or declare it if truly ambient.
