declare i pliki .d.ts

Opisywanie typów czegoś, co istnieje poza twoim kodem TypeScript: zmiennych globalnych, bibliotek JavaScript i modułów.

Na tej stronie

Przykład

#
TypeScript
// src/types/globals.d.ts
declare const APP_VERSION: string
declare function trackEvent(name: string, data?: Record<string, unknown>): void

// src/lesson.ts
trackEvent('lesson_completed', { lesson: 'flexbox', version: APP_VERSION })

trackEvent(42)
// Błąd: Argument of type 'number' is not assignable to parameter of type 'string'.

Wartość APP_VERSION wstawia bundler podczas budowania, a funkcję trackEvent dodaje skrypt analityki dołączony do strony. Kompilator wie o nich tylko dzięki deklaracjom.

Definicja i zastosowanie

#

Słowo declare informuje kompilator, że coś istnieje, choć nie zostało zdefiniowane w tym miejscu: zmienna wstrzyknięta przez inny skrypt na stronie, funkcja z biblioteki napisanej w JavaScripcie albo cały moduł. Deklaracja opisuje wyłącznie typ i znika po kompilacji, nie tworzy żadnego kodu.

Pliki z rozszerzeniem .d.ts zawierają tylko takie opisy, bez implementacji. Kompilator generuje je z twojego kodu przy opcji declaration, a autorzy bibliotek dołączają je do paczek npm. Dla pakietów bez własnych typów istnieją paczki @types/… z repozytorium DefinitelyTyped, np. @types/lodash.

We własnym projekcie plik .d.ts przydaje się do opisania zmiennych globalnych, rozszerzenia wbudowanych typów przez declare global i importów plików, które nie są kodem, np. declare module "*.svg". Plik musi być objęty przez include w tsconfig.json, inaczej kompilator go nie zobaczy.

Składnia

#
Składnia
declare const nazwa: typ
declare function nazwa(param: typ): typ
declare module "pakiet" { … }
declare global { … }

Rodzaje deklaracji

#
  • declare const

    Zmienna globalna, np. wstrzyknięta przez bundler albo skrypt dołączony do strony. Zamiast const możesz użyć let lub var.
  • declare function

    Funkcja dostępna globalnie. Możesz podać kilka sygnatur, tak jak przy przeciążeniach.
  • declare class

    Klasa zdefiniowana poza TypeScriptem, np. w starszej bibliotece.
  • declare module

    Typy całego modułu: pakietu npm ("legacy-charts") albo wzorca plików ("*.svg").
  • declare global

    Dopisuje deklaracje do zakresu globalnego z wnętrza modułu, np. nowe pole w Window.

Więcej przykładów

#
Typy dla pakietu bez typów
TypeScript
// src/types/legacy-charts.d.ts
declare module 'legacy-charts' {
  interface ChartOptions {
    title: string
    values: number[]
    color?: string
  }

  export default function drawChart(element: HTMLElement, options: ChartOptions): void
}

// src/progress.ts
import drawChart from 'legacy-charts'

drawChart(document.body, { title: 'Postęp' })
// Błąd: Argument of type '{ title: string; }' is not assignable to parameter of type 'ChartOptions'.
//   Property 'values' is missing in type '{ title: string; }' but required in type 'ChartOptions'.
Nowe pole w obiekcie window
TypeScript
// src/types/window.d.ts
export {}

declare global {
  interface Window {
    dataLayer: unknown[]
  }
}

// dowolny plik w projekcie
window.dataLayer.push({ event: 'signup' })

Linia export {} zamienia plik w moduł. Bez niej kompilator zgłosi „Augmentations for the global scope can only be directly nested in external modules or ambient module declarations”.

Dobre praktyki

#
  • Zanim napiszesz własne typy dla pakietu, sprawdź, czy istnieje paczka @types/nazwa-pakietu. Komunikat „Could not find a declaration file for module” zwykle sam ją podpowiada.
  • Skrót declare module "pakiet"; bez ciała wycisza błąd, ale wszystko z modułu dostaje wtedy typ any. Traktuj go jako rozwiązanie tymczasowe.
  • declare niczego nie tworzy. Jeśli zmienna naprawdę nie istnieje w działającym programie, kompilacja przejdzie, a program zatrzyma się na błędzie „is not defined”.

Powiązane hasła

#

Widzisz błąd albo brakuje przykładu? Napisz do nas.