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;