Bir declaration dosyası (.d.ts) tiplerden başka bir şey içermez: başka bir yerde yaşayan JavaScript için imzalar, interface'ler ve class şekilleri. declare anahtar kelimesi sıradan bir dosyanın içinde aynı işi görür. Derleyiciye "bu çalışma zamanında var, bana güven" der ve hiçbir kod üretmez.
Derleyici __APP_VERSION__.length ifadesini kabul etti, çünkü tanım onun bir string olduğunu söylüyor. Çalışma zamanında böyle bir değişken yoktur, bu yüzden .length okumak ReferenceError: __APP_VERSION__ is not defined fırlatır; derleyicinin hiç öngörmediği bir çalışma zamanı exception'ı. Her tanımın sözleşmesi budur: tipler ancak arkalarındaki JavaScript kadar doğrudur.
Bir .d.ts Dosyasında Neler Bulunur
Fikri en iyi declaration: true ile derlemek gösterir. Bu kaynaktan:
// price.ts
export interface LineItem {
name: string;
price: number;
qty: number;
}
const TAX = 0.2;
export function total(items: LineItem[]) {
const sum = items.reduce((acc, item) => acc + item.price * item.qty, 0);
return Math.round(sum * (1 + TAX) * 100) / 100;
}
export class Cart {
private items: LineItem[] = [];
add(item: LineItem) {
this.items.push(item);
return this;
}
}
tsc, price.js dosyasını ve şu price.d.ts dosyasını yazar:
export interface LineItem {
name: string;
price: number;
qty: number;
}
export declare function total(items: LineItem[]): number;
export declare class Cart {
private items;
add(item: LineItem): this;
}
Fonksiyon gövdeleri gitmiştir, çıkarılan dönüş tipleri açıkça yazılmıştır (number, this), private alan adını korur ama tipini kaybeder ve export edilmeyen TAX hiç yoktur. Bir kütüphane .js dosyasını Node için, .d.ts dosyasını editörünüz ve derleyiciniz için yayımlar. emitDeclarationOnly: true yalnızca .d.ts dosyalarını üretir; JavaScript'i bir bundler'ın derlediği projeler içindir.
Her gün kullandığınız ES2022 yerleşikleri de declaration dosyalarından gelir: lib.es2022.d.ts ve benzerleri TypeScript ile birlikte gelir ve target ile lib tarafından seçilir.
declare Biçimleri
Her declare ifadesi zaten var olan bir şeyi tanımlar. import ya da export içermeyen bir .d.ts dosyasında (global bir declaration dosyası) bunların her biri bütün projede görünür olur:
// globals.d.ts
declare const API_URL: string; // a global constant
declare let debugMode: boolean; // a global variable
declare function track(event: string, props?: Record<string, string>): void;
declare class Widget { // a class from a script tag
constructor(el: string);
render(): void;
}
declare namespace Analytics { // a global object
function page(name: string): void;
}
declare module "legacy-charts" { // a module you import
export function draw(data: number[]): void;
}
Bir .d.ts dosyasının içinde interface ve type için declare gerekmez; declare ya da export olmadan yazılan diğer her en üst seviye tanım TS1046 hatasıdır. Bir dosya import ya da export içerdiği anda tanımları o dosyaya yerel olur ve global kapsama yapılan eklemeler bir declare global bloğuna gider (aşağıda gösteriliyor). Derleyici çağrıları tanımlanan imzaya göre kontrol eder:
Derleyici şunu bildirir: index.ts(5,21): error TS2322: Type 'number' is not assignable to type 'string'. { items: "3" } verin ya da gerçek fonksiyon number kabul ediyorsa tanımı değiştirin.
@types Paketleri
Birçok npm paketi kendi .d.ts dosyalarını içerir ve bunlara package.json dosyasının types alanından (ya da exports içindeki bir types koşulundan) başvurulur. Yalnızca JavaScript olan paketler için topluluk tarafından sürdürülen DefinitelyTyped projesi tipleri @types kapsamı altında yayımlar:
npm i lodash
npm i -D @types/lodash
Bir paketi import ettiğinizde TypeScript otomatik olarak node_modules/@types/{name} konumuna bakar. Bir import'u değil global değerleri tanımlayan tipler, örneğin @types/node (process, Buffer) ya da bir test aracının describe ve it fonksiyonları, tsconfig.json içinde listelenmelidir:
{
"compilerOptions": {
"types": ["node"]
}
}
Bu girdi olmadan TypeScript 7, paket kurulu olsa bile onları yüklemez:
error TS2591: Cannot find name 'process'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node` and then add 'node' to the types field in your tsconfig.
tsc --init yeni config'e "types": [] yazar ve Node projeleri için ["node"] öneren bir yorum ekler.
Tipsiz Bir Modülü Tiplemek
Ne kendi içinde ne de @types altında tipi olan bir JavaScript paketini import etmek TS7016 hatasıdır:
error TS7016: Could not find a declaration file for module 'fakelib'. '/project/node_modules/fakelib/index.js' implicitly has an 'any' type.
Bunu projenizin herhangi bir yerinde (bir types/ klasörü yaygındır; tek şart include kapsamında olmasıdır), en üst seviyede import ya da export içermeyen bir .d.ts dosyasıyla düzeltin. Kullandığınız kısımları tanımlayın:
// types/fakelib.d.ts
declare module "fakelib" {
export function hi(name: string): string;
export const version: string;
}
// Non-code files a bundler lets you import
declare module "*.svg" {
const url: string;
export default url;
}
En kısa sürüm, tek satırlık declare module "fakelib";, paketten gelen her import'u any yapar. Hatayla birlikte her kontrolü de kaldırır, bu yüzden onu geçici bir adım olarak görün.
declare global
Global kapsama ekleme yapan kod, örneğin bir polyfill, bir yerleşik üzerinde yeni bir metot ya da bir script etiketinin ayarladığı global bir değişken, karşılık gelen tiplere ihtiyaç duyar. declare global bunları ekler. Bir modülün (bir import ya da export içeren dosyanın) içinde olmalıdır, en üstte export {} bulunmasının nedeni budur:
interface Array<T>, yerleşik Array interface'inin yerini almak yerine onunla birleşir ve globalThis üzerine bir özellik ekleyen şey var'dır (let ya da const değil). Paylaşılan kodda yerleşik prototype'ları genişletmek risklidir; projeler @types/node içindeki NodeJS.ProcessEnv interface'i aracılığıyla process.env'e kendi değişkenlerini de aynı declare global tekniğiyle ekler.
Module Augmentation
Import ettiğiniz bir paketin tiplerine ekleme yapmak için modül adını yeniden tanımlayın ve interface'i yeniden açın. Dosyanın kendisi bir modül olmalıdır (bunu import sağlar; export {} de işe yarar). import ya da export olmadan aynı blok, paketin gerçek tiplerini gizleyen yepyeni bir config-lib modülü tanımlar:
// types/config-lib.d.ts
import "config-lib";
declare module "config-lib" {
interface Settings {
beta: boolean; // merged into the package's own Settings interface
}
}
Bundan sonra config-lib'den gelen load().beta her yerde boolean olarak tiplenir. Interface'ler birleşir, type alias'lar birleşmez; bu yüzden bunun çalışması için kütüphanenin bir interface export etmesi gerekir. Eklentiler bir framework'ün request ya da config nesnelerine alanları bu şekilde ekler.
skipLibCheck
skipLibCheck: true, derleyicinin node_modules içindekiler dahil .d.ts dosyalarını tip kontrolünden geçirmesini durdurur. Kendi kodunuz yine de onlara göre kontrol edilir. Zaman kazandırır ve tanımları birbiriyle çelişen iki paketten gelen hataları önler; tsc --init'in onu açmasının nedeni budur. Bedeli, kendi .d.ts dosyalarınızdaki bir hatanın da bildirilmemesidir.
Sıkça Sorulan Sorular
TypeScript'te .d.ts dosyası nedir?
Bir declaration dosyasıdır: yalnızca tipleri (fonksiyon imzaları, interface'ler, class şekilleri) tutar, hiçbir uygulama içermez. Derlenmiş bir kütüphane ya da tarayıcının yerleşik API'leri gibi başka bir yerde var olan JavaScript'i tanımlar, böylece TypeScript onu kullanan kodu kontrol edebilir. tsc onun için asla JavaScript üretmez.
TypeScript'te declare anahtar kelimesi ne yapar?
Derleyiciye bir değerin çalışma zamanında var olduğunu, onu oluşturmadan söyler. declare const VERSION: string; satırı VERSION'ı bir string olarak kullanmanıza izin verir ve bu satır çıktıdan kaybolur. VERSION'ı gerçekten tanımlayan bir şey yoksa program çalışma zamanında bir ReferenceError ile başarısız olur.
"Could not find a declaration file for module" hatasını nasıl düzeltirim?
TS7016 hatası paketin tipleri olmadığı anlamına gelir. Varsa onları kurun (npm i -D @types/package-name) ya da kullandığınız kısmı tanımlayan declare module "package-name" { ... } içeren bir .d.ts dosyası ekleyin. Tek başına declare module "package-name"; modülün tamamını any olarak tipleyerek hatayı susturur.
TypeScript'ten .d.ts dosyaları nasıl üretilir?
tsconfig.json içinde "declaration": true ayarlayın (ya da --declaration verin). Böylece her .ts dosyası kendi .js dosyasının yanında bir .d.ts üretir. JavaScript'i başka bir araç derliyorsa emitDeclarationOnly, editörlerin tiplerden kaynak kodunuza atlayabilmesi için declarationMap ekleyin.
declare global ile declare module arasındaki fark nedir?
declare global { ... } global kapsama ekleme yapar, örneğin Array üzerinde yeni bir özellik ya da global bir değişken. declare module "name" { ... } ise o adla import ettiğiniz bir modülü tanımlar. declare global bir modülün (bir import ya da export içeren dosyanın) içinde olmalıdır; declare module, import ya da export içermeyen bir dosyada yeni bir modül tanımlar, bir modülün içinde ise var olan bir modülü genişletir.