typescript - Tuple/dizi değerlerinden birleşim türü türetmek
Diyelim ki bir dizim var:
const list = ['a', 'b', 'c']
Bu değerden 'a' | 'b' | 'c' olan bir birleşim türü türetmek mümkün mü?
Bunu istiyorum çünkü sadece statik diziden gelen değerlere izin veren bir tip tanımlamak istiyorum ve ayrıca bu değerleri çalışma zamanında listelemem gerekiyor, bu yüzden dizi kullanıyorum.
Bir indekslenmiş nesne ile nasıl uygulanabileceğine örnek:
const indexed = {a: null, b: null, c: null}
const list = Object.keys(index)
type NeededUnionType = keyof typeof indexed
Bunu indeksli bir harita kullanmadan yapmak mümkün mü?
Cevap #1
MEVCUT CEVAP
TypeScript 3.4 ve üzeri sürümlerde, bir ifadede herhangi bir literal değerin özgül literal türlerini korumasını derleyiciye belirtmek için const doğrulamasını kullanabilirsiniz.
const list = ['a', 'b', 'c'] as const; // const assertion
type NeededUnionType = typeof list[number]; // 'a'|'b'|'c';
Koda yönelik oyun alanı bağlantısı
GÜNCELLEME Şubat 2019
TypeScript 3.4'te, Mart 2019'da yayınlanması planlandığı üzere, derleyiciye bir literaller demetinin türünü, örneğin string[] yerine, literaller demeti olarak çıkarmasını söylemek mümkün olacak; bunu as const sözdizimini kullanarak yapabilirsiniz. Bu tür bir doğrulama, derleyicinin bir değer için mümkün olan en dar türü çıkarmasına neden olur, her şeyi readonly yapmayı da içerir. Şöyle görünmelidir:
const list = ['a', 'b', 'c'] as const; // TS3.4 syntax
type NeededUnionType = typeof list[number]; // 'a'|'b'|'c';
Bu, her türlü yardımcı fonksiyona olan ihtiyacı ortadan kaldıracaktır. Herkese tekrar iyi şanslar!
GÜNCELLEME Temmuz 2018
Görünüşe göre, TypeScript 3.0 ile başlayarak, TypeScript'in otomatik olarak demet (tuple) türlerini çıkarması mümkün olacak. Yayınlandıktan sonra, ihtiyacınız olan tuple() fonksiyonu şu şekilde kısaca yazılabilir:
export type Lit = string | number | boolean | undefined | null | void | {};
export const tuple = <T extends Lit[]>(...args: T) => args;
Ve sonra bunu şöyle kullanabilirsiniz:
const list = tuple('a','b','c'); // type is ['a','b','c']
type NeededUnionType = typeof list[number]; // 'a'|'b'|'c'
Umarım bu insanlar için işe yarar!
GÜNCELLEME Aralık 2017
Bu cevabı paylaştığımdan beri, eğer kütüphanenize bir fonksiyon eklemeye istekliyseniz, demet (tuple) tiplerini çıkarsamanın bir yolunu buldum. tuple.ts dosyasındaki tuple() fonksiyonuna bir göz atın. Bunu kullanarak, aşağıdaki kodu yazabilir ve kendinizi tekrar etmeyebilirsiniz:
const list = tuple('a','b','c'); // type is ['a','b','c']
type NeededUnionType = typeof list[number]; // 'a'|'b'|'c'
İyi şanslar!
ORİJİNAL Temmuz 2017
Bir sorun, literal ['a','b','c'] ifadesinin string[] türü olarak çıkarılacak olmasıdır, bu yüzden tür sistemi belirli değerleri unutacaktır. Tür sisteminin her değeri literal bir string olarak hatırlamasını zorlayabilirsiniz:
const list = ['a' as 'a','b' as 'b','c' as 'c']; // infers as ('a'|'b'|'c')[]
Ya da belki daha iyisi, listeyi bir demet türü olarak yorumlayın:
const list: ['a','b','c'] = ['a','b','c']; // tuple
Bu sinir bozucu bir tekrar, ama en azından çalışma zamanında gereksiz bir nesne oluşturmuyor.
Şimdi sendikanızı şöyle alabilirsiniz:
type NeededUnionType = typeof list[number]; // 'a'|'b'|'c'.
Cevap #2
TypeScript 3.4 için güncelleme:
TypeScript 3.4 ile gelecek olan "const contextleri" adlı yeni bir sözdizimi, gösterildiği gibi bir fonksiyon çağrısı gerektirmeyen çok daha basit bir çözüm sunacak. Bu özellik şu anda bu PR'de görüldüğü gibi inceleme aşamasında.
Kısacası, bu sözdizimi dar bir türe sahip değişmez diziler oluşturulmasına izin verir (yani, ('a' | 'b' | 'c')[] veya string[] yerine ['a', 'b', 'c'] türü). Bu şekilde, aşağıda gösterildiği gibi sabitlerden birlik türleri oluşturmak kolaylaşır:
const MY_VALUES = <const> ['a', 'b', 'c']
type MyType = typeof MY_VALUES[number]
Alternatif sözdiziminde:
const MY_VALUES = ['a', 'b', 'c'] as const
type MyType = typeof MY_VALUES[number]
