Wyobraź sobie, że w Parku Jurajskim odkryto starożytne artefakty — tajemnicze tablice z opisami gatunków dinozaurów, napisane w nieznanym języku. Naukowcy musieli stworzyć "słowniki tłumaczeniowe", żeby zrozumieć, co te tablice opisują. W świecie TypeScript rolę takich słowników pełnią pliki deklaracji (.d.ts) — opisują kształt kodu JavaScript, który sam w sobie nie ma informacji o typach.
Pliki deklaracji (declaration files) to pliki z rozszerzeniem
.d.ts, które zawierają wyłącznie informacje o typach — bez implementacji. Służą do opisania kształtu bibliotek JavaScript, modułów zewnętrznych i globalnych obiektów.1// plik: dinosaur-tracker.d.ts
2// Opisujemy zewnętrzną bibliotekę JavaScript
3
4declare module 'dinosaur-tracker' {
5 export interface DinosaurPosition {
6 id: string;
7 species: string;
8 latitude: number;
9 longitude: number;
10 lastSeen: Date;
11 }
12
13 export function trackDinosaur(id: string): DinosaurPosition;
14 export function getAllPositions(): DinosaurPosition[];
15 export function setAlert(species: string, radius: number): void;
16}Dzięki temu plikowi TypeScript wie, jakie funkcje i typy eksportuje moduł
dinosaur-tracker, mimo że sam moduł jest napisany w czystym JavaScript.Słowo
declare informuje TypeScript: "ten element istnieje w runtime, ale nie musisz go kompilować — po prostu mi zaufaj". Używamy go do opisywania:1// Zmienna globalna dostępna w przeglądarce
2declare const PARK_CONFIG: {
3 name: string;
4 maxCapacity: number;
5 securityLevel: 'low' | 'medium' | 'high' | 'critical';
6};
7
8// Teraz możemy jej użyć z pełnym type safety
9console.log(PARK_CONFIG.name);
10console.log(PARK_CONFIG.securityLevel);
11// PARK_CONFIG.unknownField; // Błąd kompilacji!1// Funkcja zdefiniowana w zewnętrznym skrypcie
2declare function initializeFence(
3 zone: string,
4 voltage: number
5): { active: boolean; zone: string };
6
7declare function emergencyShutdown(): void;
8
9// Użycie z type safety
10const fence = initializeFence('raptor-paddock', 10000);
11console.log(fence.active); // OK
12// console.log(fence.power); // Błąd! Nie ma takiej właściwości1declare class SecuritySystem {
2 constructor(zones: string[]);
3 arm(zone: string): void;
4 disarm(zone: string): void;
5 getStatus(): Record<string, boolean>;
6}
7
8declare namespace ParkAPI {
9 interface Visitor {
10 id: string;
11 name: string;
12 ticket: 'standard' | 'vip' | 'researcher';
13 }
14
15 function registerVisitor(name: string, ticket: Visitor['ticket']): Visitor;
16 function getVisitorCount(): number;
17}
18
19// Użycie
20const system = new SecuritySystem(['zone-a', 'zone-b']);
21system.arm('zone-a');
22
23const visitor = ParkAPI.registerVisitor('Alan Grant', 'researcher');
24console.log(visitor.ticket);Kiedy korzystasz z biblioteki JavaScript, która nie ma typów, musisz napisać własny plik
.d.ts:1// plik: types/legacy-dino-db.d.ts
2// Opisujemy starą bibliotekę JS do zarządzania bazą dinozaurów
3
4declare module 'legacy-dino-db' {
5 export interface DinosaurRecord {
6 id: string;
7 species: string;
8 diet: 'herbivore' | 'carnivore' | 'omnivore';
9 weight: number;
10 height: number;
11 dangerLevel: 1 | 2 | 3 | 4 | 5;
12 }
13
14 export interface QueryOptions {
15 limit?: number;
16 offset?: number;
17 sortBy?: keyof DinosaurRecord;
18 order?: 'asc' | 'desc';
19 }
20
21 export class DinoDB {
22 constructor(connectionString: string);
23 connect(): Promise<void>;
24 disconnect(): Promise<void>;
25 findAll(options?: QueryOptions): Promise<DinosaurRecord[]>;
26 findById(id: string): Promise<DinosaurRecord | null>;
27 insert(record: Omit<DinosaurRecord, 'id'>): Promise<DinosaurRecord>;
28 update(id: string, data: Partial<DinosaurRecord>): Promise<DinosaurRecord>;
29 delete(id: string): Promise<boolean>;
30 }
31
32 // Eksport domyślny
33 export default DinoDB;
34}DefinitelyTyped to ogromne repozytorium na GitHubie, zawierające pliki deklaracji dla tysięcy bibliotek JavaScript. Zamiast pisać własne pliki
.d.ts, możesz zainstalować gotowe typy:1// Instalacja typów dla popularnych bibliotek:
2// npm install --save-dev @types/express
3// npm install --save-dev @types/lodash
4// npm install --save-dev @types/node
5
6// Po instalacji @types/express możesz pisać:
7import express, { Request, Response, NextFunction } from 'express';
8
9const app = express();
10
11// TypeScript zna typy Request, Response, NextFunction
12app.get('/dinosaurs/:id', (req: Request, res: Response) => {
13 const dinoId: string = req.params.id;
14 res.json({ id: dinoId, species: 'T-Rex' });
15});
16
17// Bez @types/express - brak informacji o typach!
18// req, res byłyby typu "any"TypeScript szuka typów w następującej kolejności:
1// 1. Typy wbudowane w paczkę (pole "types" w package.json)
2// Wiele nowoczesnych bibliotek ma wbudowane .d.ts
3// np. axios, zod, prisma
4
5// 2. Paczki @types z node_modules/@types/
6// Automatycznie rozpoznawane przez TypeScript
7// np. @types/react, @types/node
8
9// 3. Własne pliki .d.ts w projekcie
10// Konfiguracja w tsconfig.json:
11// {
12// "compilerOptions": {
13// "typeRoots": ["./node_modules/@types", "./types"],
14// "types": ["node", "express"]
15// },
16// "include": ["src/**/*", "types/**/*"]
17// }
18
19// 4. Triple-slash directives (rzadko używane)
20/// <reference types="node" />
21/// <reference path="./custom-types.d.ts" />Czasami potrzebujesz zadeklarować moduł, który nie jest pakietem npm — na przykład plik CSS, obraz lub plik JSON:
1// plik: types/assets.d.ts
2
3// Import plików CSS
4declare module '*.css' {
5 const classes: Record<string, string>;
6 export default classes;
7}
8
9// Import plików graficznych
10declare module '*.png' {
11 const src: string;
12 export default src;
13}
14
15declare module '*.svg' {
16 const content: string;
17 export default content;
18}
19
20// Import plików JSON
21declare module '*.json' {
22 const value: Record<string, unknown>;
23 export default value;
24}
25
26// Teraz możesz importować te pliki z type safety:
27// import styles from './styles.css';
28// import logo from './logo.png';
29// import dinoData from './dinosaurs.json';Pliki
.d.ts pozwalają na rozszerzanie typów z zewnętrznych bibliotek:1// plik: types/express-extension.d.ts
2// Rozszerzamy typy Express o dodatkowe pola
3
4import 'express';
5
6declare module 'express' {
7 interface Request {
8 userId?: string;
9 parkZone?: string;
10 securityClearance?: 'visitor' | 'staff' | 'admin';
11 }
12}
13
14// Teraz w kodzie aplikacji:
15// app.use((req, res, next) => {
16// req.userId = 'USR-001'; // OK - TypeScript zna to pole
17// req.parkZone = 'zone-a'; // OK
18// req.securityClearance = 'staff'; // OK
19// next();
20// });Pliki deklaracji (.d.ts) i ekosystem DefinitelyTyped to fundamenty pracy z TypeScript w realnym świecie. Dzięki nim możesz korzystać z tysięcy bibliotek JavaScript z pełnym type safety — jak naukowcy w Parku Jurajskim, którzy dzięki "słownikom tłumaczeniowym" potrafili odczytać nawet najstarsze tablice z informacjami o dinozaurach.