TypeScript DefinitelyTyped

Using type definitions for JavaScript libraries

📚 What is DefinitelyTyped?

DefinitelyTyped is a massive repository of TypeScript type definitions for JavaScript libraries. It provides type safety when using JavaScript packages, enabling IntelliSense, type checking, and better developer experience in TypeScript projects.


# Install type definitions for a library
npm install --save-dev @types/lodash

# Now use lodash with full type support
import _ from 'lodash';
const result: number = _.sum([1, 2, 3]);
                                    

Result:

Full TypeScript support for lodash library

Key Concepts

📦

@types Packages

Type definitions from npm

npm install --save-dev 
@types/node
🔍

Type Discovery

Automatic type resolution

// TypeScript finds types
// automatically
import express from 'express';
✍️

Declaration Files

Custom .d.ts files

// mylib.d.ts
declare module 'mylib' {
  export function fn(): void;
}
🌐

Global Types

Types available everywhere

// Extends global scope
declare global {
  var myGlobal: string;
}

🔹 Installing Type Definitions

Add TypeScript types for JavaScript libraries:

# Install types for popular libraries
npm install --save-dev @types/node
npm install --save-dev @types/express
npm install --save-dev @types/react
npm install --save-dev @types/lodash
npm install --save-dev @types/jest

# Check if types are available
npm search @types/library-name

Result:

Type definitions installed in node_modules/@types/

🔹 Using @types Packages

Once installed, types work automatically:

// Install: npm install --save-dev @types/node
import * as fs from 'fs';

// TypeScript knows the types!
const content: string = fs.readFileSync('file.txt', 'utf-8');

// Install: npm install lodash @types/lodash
import _ from 'lodash';

// Full type support
const numbers: number[] = [1, 2, 3, 4, 5];
const sum: number = _.sum(numbers);
const doubled: number[] = _.map(numbers, n => n * 2);

console.log(sum);      // 15
console.log(doubled);  // [2, 4, 6, 8, 10]

Output:

15
[2, 4, 6, 8, 10]

🔹 Creating Declaration Files

Write your own type definitions for libraries without types:

// types/my-library.d.ts

// Declare a module
declare module 'my-library' {
    // Export functions
    export function greet(name: string): string;
    
    // Export classes
    export class Calculator {
        add(a: number, b: number): number;
        subtract(a: number, b: number): number;
    }
    
    // Export interfaces
    export interface Config {
        apiKey: string;
        timeout: number;
    }
    
    // Default export
    export default function initialize(config: Config): void;
}

// Now you can use it with types
import myLib, { greet, Calculator } from 'my-library';

const message = greet("Alice");
const calc = new Calculator();
const result = calc.add(5, 3);

Result:

Full type support for my-library

🔹 Ambient Declarations

Declare types for global variables and modules:

// types/globals.d.ts

// Declare global variables
declare const API_URL: string;
declare const VERSION: number;

// Extend global namespace
declare global {
    interface Window {
        myApp: {
            version: string;
            init(): void;
        };
    }
    
    // Add custom global function
    function customAlert(message: string): void;
}

// Use the global types
console.log(API_URL);
console.log(VERSION);

window.myApp.init();
customAlert("Hello!");

// Export to make it a module
export {};

Result:

Global types available throughout project

🔹 Module Augmentation

Extend existing type definitions:

// types/express-extensions.d.ts

// Augment Express Request interface
import { Request } from 'express';

declare module 'express-serve-static-core' {
    interface Request {
        // Add custom properties
        user?: {
            id: number;
            username: string;
            role: string;
        };
        
        // Add custom methods
        isAuthenticated(): boolean;
    }
}

// Now use the extended types
import express from 'express';

const app = express();

app.get('/profile', (req, res) => {
    // TypeScript knows about req.user
    if (req.user) {
        res.json({
            id: req.user.id,
            username: req.user.username
        });
    } else {
        res.status(401).send('Not authenticated');
    }
});

Result:

Express Request type extended with custom properties

🔹 Type Definition Structure

Understanding .d.ts file structure:

Basic Structure:

// library.d.ts

// Type aliases
type UserId = string | number;

// Interfaces
interface User {
    id: UserId;
    name: string;
}

// Functions
declare function getUser(id: UserId): User;
declare function createUser(name: string): User;

// Classes
declare class Database {
    constructor(url: string);
    connect(): Promise<void>;
    disconnect(): void;
}

// Namespaces
declare namespace Utils {
    function formatDate(date: Date): string;
    function parseDate(str: string): Date;
}

// Module exports
export { User, UserId, getUser, createUser, Database, Utils };

🔹 TypeScript Configuration

Configure TypeScript to find your type definitions:

// tsconfig.json
{
  "compilerOptions": {
    // Where to look for type definitions
    "typeRoots": [
      "./node_modules/@types",
      "./types"
    ],
    
    // Specific types to include
    "types": [
      "node",
      "jest",
      "express"
    ],
    
    // Allow JavaScript files
    "allowJs": true,
    
    // Check JavaScript files
    "checkJs": false,
    
    // Skip type checking of declaration files
    "skipLibCheck": true
  },
  
  // Include custom type definitions
  "include": [
    "src/**/*",
    "types/**/*"
  ]
}

Result:

TypeScript finds types in both node_modules/@types and ./types

🔹 Best Practices

Tips for working with type definitions:

✅ Do:

  • Install @types packages as devDependencies
  • Keep types updated with library versions
  • Use skipLibCheck to speed up compilation
  • Organize custom types in a types/ directory
  • Document your declarations with JSDoc comments

❌ Don't:

  • Mix types and implementation in .d.ts files
  • Use any type excessively in declarations
  • Forget to export types from declaration files
  • Duplicate types that already exist in DefinitelyTyped
// ✅ Good: Well-documented declaration
/**
 * Fetches user data from the API
 * @param id - The user's unique identifier
 * @returns Promise resolving to user object
 */
declare function fetchUser(id: number): Promise<User>;

// ❌ Bad: Using 'any' type
declare function processData(data: any): any;

🧠 Test Your Knowledge

Where are @types packages installed?