TS

TypeScript Fundamentals

17 lessons

Progress0%
1. Introduction to TypeScript
1What is TypeScript?2Setting Up TypeScript
2. Basic Types
1Primitive Types2Interfaces and Type Aliases
3. Functions and Generics
Typed FunctionsGenerics
4. Classes and OOP
ClassesInheritance and Interfaces
5. Advanced Types
Union and Intersection TypesUtility Types
6. Modules and Decorators
ES Modules
7. Decorators
Class & Method DecoratorsProperty & Parameter Decorators
8. Declaration Files
Writing .d.ts Files@types & DefinitelyTyped
9. Advanced Patterns
Conditional Types & inferTemplate Literal Types & satisfies
All Tutorials
TypeScriptDeclaration Files
Lesson 15 of 17 min
Chapter 8 · Lesson 2

@types & DefinitelyTyped

DefinitelyTyped is a massive community repository that hosts TypeScript declaration files for thousands of JavaScript libraries under the @types npm scope. Understanding how TypeScript discovers and loads these packages is essential for configuring larger projects correctly.

@types/ Packages

Installing @types/lodash places a directory of .d.ts files inside node_modules/@types/lodash/. TypeScript's compiler automatically scans node_modules/@types and includes every package it finds there — no explicit import needed for globals.

bash
npm install --save-dev @types/node @types/lodash

Type Resolution: typeRoots and types

By default TypeScript includes all packages under every node_modules/@types folder in the project. Two tsconfig options narrow this:

  • typeRoots: an array of directories to search instead of the default node_modules/@types.
  • types: an array of package names to include; all others are ignored.
json
{
  "compilerOptions": {
    "typeRoots": ["./node_modules/@types", "./src/types"],
    "types": ["node", "jest"]
  }
}

lib.d.ts

TypeScript ships with a set of built-in declaration files that describe JavaScript's standard library and browser APIs. The lib tsconfig option controls which files are included:

json
{ "compilerOptions": { "lib": ["ES2022", "DOM", "DOM.Iterable"] } }
  • ES2022 — modern JS globals (Array.at, Object.hasOwn, …)
  • DOM — browser APIs (document, fetch, …)
  • DOM.Iterable — iterable DOM collections

Node Types

For Node.js projects, install @types/node. This adds types for process, Buffer, fs, path, and every other Node built-in.

The --declaration Flag

Running tsc --declaration (or setting "declaration": true in tsconfig) generates a .d.ts file alongside each compiled .js file. This is how library authors publish types with their packages.

Creating a Simple @types Package Structure

code
my-types/
  index.d.ts
  package.json  ← { "name": "@types/my-lib", "version": "1.0.0", "main": "" }

strict Mode Implications

Enabling "strict": true activates a family of flags. When consuming @types packages, strict mode can surface errors in your own usage of a library that were invisible before — such as potentially-undefined return values that the library's types correctly declare as T | undefined.

Mastering type resolution saves hours of debugging mysterious "Cannot find module" or "has no exported member" errors in real projects.

Code Examples

tsc --declaration Outputtypescript
// Source file: src/math.ts
// Run with: tsc --declaration --outDir dist

export function add(a: number, b: number): number {
  return a + b;
}

export function multiply(a: number, b: number): number {
  return a * b;
}

export interface Vector2 {
  x: number;
  y: number;
}

export function scaleVector(v: Vector2, factor: number): Vector2 {
  return { x: v.x * factor, y: v.y * factor };
}

// TypeScript generates dist/math.d.ts:
// ----------------------------------------
// export declare function add(a: number, b: number): number;
// export declare function multiply(a: number, b: number): number;
// export interface Vector2 { x: number; y: number; }
// export declare function scaleVector(v: Vector2, factor: number): Vector2;
// ----------------------------------------

// Verify the functions work correctly
console.log(add(3, 4));
console.log(multiply(3, 4));
console.log(JSON.stringify(scaleVector({ x: 1, y: 2 }, 3)));

The --declaration flag tells tsc to emit a .d.ts file alongside every compiled .js file. The generated file contains only declare-prefixed type signatures — no implementation code.

Using a Library with @typestypescript
// After: npm install lodash && npm install --save-dev @types/lodash
// TypeScript now fully understands lodash's API

import _ from "lodash";

interface Product {
  name: string;
  price: number;
  category: string;
}

const products: Product[] = [
  { name: "Widget", price: 9.99, category: "tools" },
  { name: "Gadget", price: 24.99, category: "electronics" },
  { name: "Thingamajig", price: 4.99, category: "tools" },
  { name: "Doohickey", price: 14.99, category: "electronics" },
];

// _.groupBy, _.mapValues, _.sortBy — all fully typed
const grouped = _.groupBy(products, "category");
const cheapest = _.minBy(products, "price");
const sorted = _.sortBy(products, ["category", "price"]);

console.log("Categories:", Object.keys(grouped));
console.log("Cheapest:", cheapest?.name);
console.log("First sorted:", sorted[0].name);

@types/lodash ships complete signatures for every lodash function. TypeScript infers the return type of _.groupBy as Dictionary<Product[]> and _.minBy as Product | undefined, giving full type safety.

typeRoots and types Configurationtypescript
// tsconfig.json (illustrative — not executable TypeScript)
// {
//   "compilerOptions": {
//     "typeRoots": [
//       "./node_modules/@types",
//       "./src/custom-types"
//     ],
//     "types": ["node", "jest"],
//     "lib": ["ES2022"],
//     "strict": true
//   }
// }

// With the above config TypeScript only auto-includes @types/node
// and @types/jest — all other @types packages are ignored unless
// explicitly imported.

// src/custom-types/env.d.ts would live here for project-specific globals.

// Demonstration: type narrowing that strict mode enables
function processValue(val: string | null | undefined): string {
  // Without strict, TypeScript might not warn about missing null check
  if (val == null) {
    return "(empty)";
  }
  return val.toUpperCase(); // safe because null/undefined excluded above
}

console.log(processValue("hello"));
console.log(processValue(null));
console.log(processValue(undefined));

// strict mode also enables:
// - strictNullChecks
// - noImplicitAny
// - strictFunctionTypes
// - strictPropertyInitialization
// - and more
console.log("strict mode catches type errors at compile time");

The types array restricts which @types packages are automatically included globally. typeRoots adds custom type directories. Together they give precise control over what type definitions the compiler loads.

Quick Quiz

1. By default, TypeScript automatically includes types from which directory?

2. What does the tsconfig "types" array do?

3. Which tsconfig flag causes tsc to emit .d.ts files alongside compiled JavaScript?

4. Which lib value adds browser API types like document and fetch to a TypeScript project?

Was this lesson helpful?

PreviousNext