İçeriğe geç
Educora
İleri20 dk8 / 8

Modern yöntemler ve bildirim dosyaları

Katı modun neleri yakaladığını öğren, `as const` ve `satisfies` ile kesin tipler elde et, üçüncü taraf JavaScript kütüphanelerini `.d.ts` bildirim dosyalarıyla tiple.

Kendini test et
Bu derste öğreneceklerin
  • strict modunun hangi denetimleri açtığını açıklamak
  • as const ile değerlerden kesin literal tipler elde etmek
  • satisfies'ı tip belirtimi ve as ile karşılaştırmak
  • @types paketlerini kullanmak ve basit bir .d.ts dosyası yazmak

Artık tipleri, fonksiyonları, arayüzleri, birleşimleri, sınıfları ve jenerikleri biliyorsun. Bu son ders, profesyonellerin her gün kullandığı dört araç hakkında: hataların çoğunu yakalayan katı mod, değerlerden kesin tip almak için as const, tipi genişletmeden denetleyen satisfies ve tipsiz JavaScript kütüphanelerini TypeScript'e tanıtan bildirim dosyaları.

Katı mod

tsconfig.json içindeki "strict": true tek bir seçenek değil, bütün bir denetim kümesidir. Onsuz TypeScript pek çok şeye göz yumar ve JavaScript'in en sık görülen hataları gözden kaçar. Kümenin en önemli üyeleri şunlardır:

  • strictNullChecks: null ve undefined ayrı tiplerdir; “undefined olabilecek” bir değer kontrol edilmeden kullanılamaz.
  • noImplicitAny: tipi belirlenemeyen bir parametre sessizce any olmaz, hata verilir.
  • strictPropertyInitialization: her sınıf alanı tanımında ya da yapıcıda bir değer almalıdır.
  • useUnknownInCatchVariables: catch (error) içinde error'ın tipi any değil unknown olur.
TypeScript
const users = [
  { name: 'Aysel', age: 15 },
  { name: 'Murad', age: 17 },
];

const found = users.find((u) => u.name === 'Leyla');
console.log(found.age);
Text
users.ts:7:13 - error TS18048: 'found' is possibly 'undefined'.

7 console.log(found.age);
              ~~~~~
find hiçbir şey bulamayabilir. Katı mod olmasaydı kod hatasız derlenir, çalışma anında ise TypeError: Cannot read properties of undefined (reading 'age') ile çökerdi.
TypeScript
const users = [
  { name: 'Aysel', age: 15 },
  { name: 'Murad', age: 17 },
];

const found = users.find((u) => u.name === 'Leyla');
console.log(found?.age ?? 'not found');
Beklenen çıktı
not found
Doğru çözüm: “bulunamadı” durumunu ?. ve ?? ile ele almak.

as const

as const, bir değerin “dondurulmuş” kabul edilmesini ister: string'ler string yerine kesin literal tipler olur, dizi salt okunur bir demete, nesnenin özellikleri de readonly özelliklere dönüşür. Bu, roller, durumlar ve ayarlar gibi sabit listeler için idealdir ve daha önce konuştuğumuz enum'un yerini rahatça alır:

TypeScript
const ROLES = ['admin', 'editor', 'viewer'] as const;
type Role = (typeof ROLES)[number];

function canEdit(role: Role): boolean {
  return role !== 'viewer';
}

const Status = { Active: 'active', Blocked: 'blocked' } as const;
type Status = (typeof Status)[keyof typeof Status];

const s: Status = Status.Blocked;
console.log(ROLES.join(', '), canEdit('editor'), s);
Beklenen çıktı
admin, editor, viewer true blocked
Role tipi 'admin' | 'editor' | 'viewer', Status tipi ise 'active' | 'blocked''tır. Liste programda da vardır; yazdırılabilir ve döngüyle gezilebilir.
TypeScript
const ROLES = ['admin', 'editor', 'viewer'] as const;
ROLES.push('guest');
Text
roles.ts:2:7 - error TS2339: Property 'push' does not exist on type 'readonly ["admin", "editor", "viewer"]'.

2 ROLES.push('guest');
        ~~~~
as const diziyi salt okunur bir demete dönüştürür; bu yüzden push metodu yoktur.

satisfies operatörü

Tip belirtimi (const x: T = ...) değeri denetler ama değişkenin tipini T'ye genişletir ve değerle ilgili kesin bilgi kaybolur. satisfies T ise yalnızca denetler: değer T'ye uymalıdır, değişken ise TypeScript'in çıkardığı kesin tipi korur. Bir renk paletinde bazı renkler string, bazıları üç sayıdan oluşan demetlerdir:

TypeScript
type ColorName = 'red' | 'green' | 'blue';
type Color = string | [number, number, number];

const palette = {
  red: [255, 0, 0],
  green: '#00ff00',
  blue: [0, 0, 255],
} satisfies Record<ColorName, Color>;

console.log(palette.green.toUpperCase());
console.log(palette.red[0]);
Beklenen çıktı
#00FF00
255
TypeScript, green'in bir string, red'in ise bir demet olduğunu bilir, çünkü satisfies kesin tipi korur.
TypeScript
type ColorName = 'red' | 'green' | 'blue';
type Color = string | [number, number, number];

const annotated: Record<ColorName, Color> = {
  red: [255, 0, 0],
  green: '#00ff00',
  blue: [0, 0, 255],
};
annotated.green.toUpperCase();

const checked = {
  red: [255, 0, 0],
  green: '#00ff00',
  bleu: [0, 0, 255],
} satisfies Record<ColorName, Color>;
Text
palette.ts:9:17 - error TS2339: Property 'toUpperCase' does not exist on type 'Color'.
  Property 'toUpperCase' does not exist on type '[number, number, number]'.

9 annotated.green.toUpperCase();
                  ~~~~~~~~~~~

palette.ts:14:3 - error TS2353: Object literal may only specify known properties, and 'bleu' does not exist in type 'Record<ColorName, Color>'.

14   bleu: [0, 0, 255],
     ~~~~
İlk hata: belirtimden sonra green yalnızca bir Color'dır. İkinci hata: satisfies yine de denetler ve bleu yazım hatasını yakalar.
YazımDenetler mi?Değişkenin tipi
const x: T = valueevetT (genişler)
const x = value satisfies Tevetdeğerin kesin tipi
const x = value as Tneredeyse hiçT

Bildirim dosyaları ve üçüncü taraf kütüphaneler

Tanım
Bildirim dosyası (.d.ts)

Yalnızca tip içeren, çalıştırılabilir hiçbir kodu olmayan bir dosya. JavaScript kodunun TypeScript için yazılmış “kullanım kılavuzudur”: hangi fonksiyonlar var, hangi parametreleri alıyor ve ne döndürüyor.

npm paketlerinin tipleri üç yoldan biriyle gelir. Pek çok modern paket kendi .d.ts dosyalarıyla birlikte gelir ve yapılacak bir şey yoktur. Diğerleri için topluluk tipleri ayrı @types/... paketlerinde yayımlar. İkisi de yoksa bildirim dosyasını kendin yazarsın.

Terminal
npm install lodash
npm install --save-dev @types/lodash
Kütüphanenin kendisi dependencies'e, tipleri ise yalnızca geliştirme sırasında gerektiği için devDependencies'e girer.

Diyelim ki projede tipleri olmayan eski bir old-slug kütüphanesi var; metni bir URL için kısa bir ada dönüştürüyor. Onu içe aktardığında TypeScript, modülün tiplerini bulamadığını bildirir:

Text
src/index.ts:1:21 - error TS7016: Could not find a declaration file for module 'old-slug'. '/home/leyla/blog/node_modules/old-slug/index.js' implicitly has an 'any' type.
  Try `npm i --save-dev @types/old-slug` if it exists or add a new declaration (.d.ts) file containing `declare module 'old-slug';`

1 import slugify from 'old-slug';
                      ~~~~~~~~~~

@types/old-slug paketi yoksa types/old-slug.d.ts dosyasını oluşturur ve modülü declare module ile tanımlarız. declare sözcüğü, bu kodun başka bir yerde zaten var olduğunu, bizim yalnızca tipini bildirdiğimizi söyler:

TypeScript
declare module 'old-slug' {
  export default function slugify(text: string, separator?: string): string;
}
types/old-slug.d.ts: gövdesiz bir fonksiyon imzası, yalnızca tipler.
TypeScript
import slugify from 'old-slug';

const title = 'Hello from Baku';
console.log(slugify(title));
console.log(slugify(title, '_'));
Beklenen çıktı
hello-from-baku
hello_from_baku
src/index.ts artık hatasız denetlenir, editör parametreleri önerir; slugify(42) gibi bir çağrı ise TS2345 hatası verir.

Kendi kütüphaneni yayımlarken .d.ts dosyalarını elle yazman gerekmez. tsconfig.json içindeki "declaration": true seçeneğiyle tsc, her .js dosyasının yanına onun .d.ts dosyasını da üretir:

TypeScript
export interface User {
    name: string;
    age: number;
}
export declare function greet(user: User): string;
greet.ts'ten üretilen greet.d.ts: arayüz ve fonksiyonun imzası kaldı, gövde ise greet.js içinde.

Önemli noktalar

  • strict: true, strictNullChecks, noImplicitAny ve diğer denetimleri açar; her zaman açık tut.
  • as ve ! hata mesajını gizler ama sorunu çözmez.
  • as const bir değeri kesin literal ve salt okunur tiplere dönüştürür; (typeof LIST)[number] listeden bir birleşim tipi çıkarır.
  • satisfies T değeri T'ye göre denetler ama değişkenin kesin tipini korur.
  • .d.ts dosyaları yalnızca tip içerir; tipler paketin kendisinden, @types/... paketlerinden ya da declare module ile yazdığın bir dosyadan gelir.

Kendini test et

10 soru. Her doğru cevap XP kazandırır.

1 / 10
tsconfig.json içindeki "strict": true ne yapar?