Partial<T>, T tipinin her özelliğini isteğe bağlı yapan yerleşik bir utility type'tır. Bir güncelleme ya da patch için doğal tiptir: çağıran taraf yalnızca değişen alanları gönderir.
Partial<User> tipi { id?: number; name?: string; email?: string } olur. Derleyici geçirdiğiniz alanları yine kontrol eder: { nmae: "x" } ya da { name: 42 } bir hatadır; Partial tipini gevşek bir object ya da any parametresinden daha iyi yapan da budur.
Partial Nasıl Tanımlanır
Partial, TypeScript'in standart kütüphanesinde tek satırlık bir mapped type'tır:
type Partial<T> = {
[P in keyof T]?: T[P];
};
T tipinin her P anahtarı için aynı tipte isteğe bağlı bir özellik bildirir. keyof T üzerinde eşleme yaptığı için, readonly olan özelliklerde readonly korunur. Sıradan bir tip olduğu için çalışma zamanında hiçbir etkisi yoktur: changes olarak geçirilen nesne her durumda aynı nesnedir.
Bir Partial'dan Okumak T | undefined Verir
Bir Partial<T> tipinin her özelliği eksik olabilir, bu yüzden birini okumak özellik tipini ve undefined değerini verir. Derleyici eksik durumu ele almanızı ister:
{ ...defaults, ...opts }, bir Partial<Options> değerini eksiksiz bir Options değerine geri çevirmenin olağan yoludur: önce varsayılanları yayın, verilen değerlerin onları ezmesine izin verin.
Açık undefined Tuzağı
İsteğe bağlı bir özellik eksik olabilir, ama undefined değeriyle var da olabilir. Nesne spread'i bu undefined değerini gerçek değerin üzerine kopyalar ve sonuç tipi bunu göstermez:
Bu sorun, boş alanların undefined hâline geldiği bir formdan ya da query string'den bir patch oluşturulduğunda ortaya çıkar. exactOptionalPropertyTypes derleyici seçeneği (strict kapsamında değildir), name?: string | undefined yazmadığınız sürece name?: string için { name: undefined } ifadesini bir derleme hatası yapar ve sorunu kaynağında önler.
Partial Sığdır
Partial yalnızca en üst düzey özellikleri isteğe bağlı yapar. İç içe bir nesneyi geçirirseniz, o nesne eksiksiz olmalıdır:
index.ts(8,3): error TS2741: Property 'tabSize' is missing in type '{ fontSize: number; }' but required in type '{ fontSize: number; tabSize: number; }'.
editor özelliği isteğe bağlıdır, ama var olduğunda tipi değişmeden { fontSize: number; tabSize: number } olur. Ayar nesneleri, API patch'leri ve test fixture'ları için genellikle her düzeyde isteğe bağlı özellikler istersiniz. Bunun için özyinelemeli bir tip gerekir.
DeepPartial: Özyinelemeli Bir Partial
TypeScript'te yerleşik bir derin sürüm yoktur, ama birkaç satırdan ibarettir. Fonksiyonlar ve diziler olduğu gibi bırakılır, çünkü dizi elemanlarını isteğe bağlı yapmak [undefined] değerine izin verirdi:
Tip özyinelemelidir; birleştirme değildir. applySettings, editor özelliğini elle birleştirir, çünkü nesne spread'i de sığdır. lodash gibi kütüphanelerde generic bir derin birleştirme fonksiyonu (merge) vardır ve onun tiplenmesi yukarıdaki tipten daha zordur.
Required: Partial'ın Tersi
Required<T>, her özellikten ? işaretini kaldırır. -? değiştiricisiyle tanımlanmıştır; bu değiştirici her özelliğin tipinden undefined değerini de çıkarır:
Desen Partial ile aynıdır, yalnızca tersine çevrilmiştir: bir API'nin kullanıcıları gevşek bir yapılandırma geçirir, içerideki kod ise her değerin var olduğunun bilindiği bir Required sürümüyle çalışır. Spread'de yukarıdaki güncelleme fonksiyonundaki açık aynen vardır: açıkça port: undefined geçiren bir çağıran, varsayılanı undefined ile ezer ve exactOptionalPropertyTypes açık değilse derleyici bunu kabul eder. Required da Partial gibi sığdır.
Yalnızca Bazı Özellikleri İsteğe Bağlı ya da Zorunlu Yapmak
Partial ve Required her özelliğe uygulanır. Yalnızca birkaçını değiştirmek için tipi Pick ve Omit ile bölün ve yeniden birleştirin:
type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
type RequiredBy<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
interface Post {
id: number;
title: string;
body?: string;
}
type NewPost = PartialBy<Post, "id">; // id optional, title required, body optional
type Published = RequiredBy<Post, "body">; // body now required
| Tip | Etkisi | Derin mi? |
|---|---|---|
Partial<T> | her özellik isteğe bağlı | hayır |
Required<T> | her özellik zorunlu, undefined çıkarılmış | hayır |
DeepPartial<T> (kendi yazdığınız) | her düzeyde isteğe bağlı | evet |
PartialBy<T, K> (kendi yazdığınız) | yalnızca K anahtarları isteğe bağlı | hayır |
Readonly<T> | her özellik readonly | hayır |
Sıkça Sorulan Sorular
TypeScript'te Partial ne işe yarar?
Partial<T>, T tipinin tüm özellikleri isteğe bağlı olarak işaretlenmiş bir tip oluşturur. interface User { name: string; email: string } için Partial<User> tipi { name?: string; email?: string } olur; böylece {}, { name: "Ada" } ve eksiksiz bir kullanıcı geçerli değerlerdir.
TypeScript'te Partial derin mi çalışır?
Hayır, Partial yalnızca en üst düzey özellikleri etkiler. Bir Partial<T> içindeki iç içe bir nesne yine eksiksiz olmalıdır. Özyinelemeli bir sürüm için, nesne tipli özelliklere kendini uygulayan bir DeepPartial<T> tipi yazın.
TypeScript'te Partial'ın tersi nedir?
Required<T>. Her özellikten ? işaretini kaldırır ve tiplerinden undefined değerini de çıkarır; böylece Required<{ port?: number }> tipi { port: number } olur. -? değiştiricisine sahip bir mapped type olarak tanımlanmıştır.
Yalnızca bazı özellikleri nasıl isteğe bağlı yaparım?
Omit, Pick ve Partial tiplerini birleştirin: type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>. PartialBy<User, "email"> her özelliği olduğu gibi bırakır, yalnızca email isteğe bağlı hâle gelir.
Bir Partial güncellemesi birleştirildikten sonra bir özellik neden undefined oluyor?
Partial<T>, bir özelliğin undefined değeriyle var olmasına izin verir ve nesne spread'i onu kopyalar: TypeScript sonucu User olarak tiplese de { ...user, ...{ name: undefined } } içinde name: undefined bulunur. Birleştirmeden önce undefined değerlerini filtreleyin ya da açık bir undefined reddedilsin diye exactOptionalPropertyTypes seçeneğini açın.