TypeScript, tuple / array değerlerinden birleşim türünü türetir


94

Listem olduğunu söyle const list = ['a', 'b', 'c']

Yani bu değer birleşim tipinden türetmek mümkün müdür 'a' | 'b' | 'c'?

Bunu istiyorum çünkü sadece statik diziden gelen değerlere izin veren türü tanımlamak istiyorum ve bu değerleri çalışma zamanında numaralandırmam gerekiyor, bu yüzden dizi kullanıyorum.

Dizine alınmış bir nesne ile nasıl uygulanabileceği örneği:

const indexed = {a: null, b: null, c: null}
const list = Object.keys(index)
type NeededUnionType = keyof typeof indexed

Endekslenmiş bir harita kullanmadan bunu yapmanın mümkün olup olmadığını merak ediyorum.


Yani esasen, anında türler oluşturmak ister misiniz?
SwiftsNamesake

Türler yalnızca derleme sırasında bulunur, bu nedenle bunları çalışma zamanında dinamik olarak oluşturamazsınız.
jonrsharpe

Bu ilginç bir soru. Kullanım durumunuz nedir?
07:47

Yanıtlar:


198

GÜNCEL Şubat 2019

In Mart 2019 yılında piyasaya edilmelidir typescript 3.4, değişmezleri bir başlığın türünü tahmin derleyici söylemek mümkün olacaktır değişmezleri bir demet olarak yerine söylemek gibi bir, string[]kullanarak as constsözdizimi . Bu tür bir iddia, derleyicinin her şeyi yapmak da dahil olmak üzere bir değer için mümkün olan en dar türü çıkarmasına neden olur readonly. Şöyle görünmeli:

const list = ['a', 'b', 'c'] as const; // TS3.4 syntax
type NeededUnionType = typeof list[number]; // 'a'|'b'|'c';

Bu, her türden yardımcı bir işleve olan ihtiyacı ortadan kaldıracaktır. Herkese tekrar iyi şanslar!


GÜNCEL Temmuz 2018

Görünüşe göre, TypeScript 3.0'dan başlayarak, TypeScript'in demet türlerini otomatik olarak çıkarması mümkün olacak . Serbest bırakıldığında, tuple()ihtiyacınız olan işlev kısaca şu şekilde yazılabilir:

export type Lit = string | number | boolean | undefined | null | void | {};
export const tuple = <T extends Lit[]>(...args: T) => args;

Ve sonra bunu şu şekilde 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ı yayınladığımdan beri, kitaplığınıza bir işlev eklemek istiyorsanız, tuple türlerini çıkarmanın bir yolunu buldum. Fonksiyonunu kontrol edin tuple()içinde tuple.ts . Bunu kullanarak aşağıdakileri yazabilir ve kendinizi tekrar edemezsiniz:

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 problem, değişmez değerin ['a','b','c']tür olarak çıkarılmasıdır string[], bu nedenle tür sistemi belirli değerleri unutacaktır. Tür sistemini her değeri değişmez bir dize olarak hatırlamaya 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 can sıkıcı bir tekrar, ancak en azından çalışma zamanında yabancı bir nesne ortaya çıkarmıyor.

Şimdi sendikanızı şu şekilde alabilirsiniz:

type NeededUnionType = typeof list[number];  // 'a'|'b'|'c'.

Umarım yardımcı olur.


Bu, çalışma zamanı kontrollerine (tuple kullanarak) ve bir tür birleşimi kullanarak derleme zamanı kontrollerine ihtiyacım olduğunda, sık sık karşılaştığım bir sorun için mükemmel bir çözümdür. Dile örtük tuple yazımı için destek ekleme çabası olup olmadığını bilen var mı?
Jørgen Tvedt

Çözümünüzü denedim ama çalışmıyorcont xs = ['a','b','c']; const list = tuple(...xs);
Miguel Carvajal

1
Bu zaman yapmanız beri, bunda işe olmaması gerek const xs = ['a','b','c']derleyici zaten büyümüştür xsiçin string[]ve tamamen belirli değerlerle unutmuş. En azından TS3.2 itibariyle bu davranışa yardım edemem ( as constyine de işe yarayan bir gelecek gösterim olabilir ). Neyse ben standlarda olarak cevap (orada ki Bahsetmek bunu yapabilir hala kadar doğru olduğunu düşünüyorum ['a','b','c']olarak anlaşılmaktadır string[]) Eminim daha neye ihtiyacınız değilim bu yüzden.
jcalz

3
birisi ne [number]olduğunu açıklayabilir list[number]mi?
Orelus

3
(typeof list)[number]Değil ... olarak ayrıştırılır typeof (list[number]). Tür T[K], anahtarı olan özelliğin türünü alan bir arama türüdür . İçinde , anahtarlarının olduğu özelliklerin türlerini alıyorsunuz . Diziler mi var sayısal endeks imzaları onların yüzden, anahtar verimleri tüm sayısal-endeksli özelliklerinin birliği. TK(typeof list)[number](typeof list)numbertypeof listnumber
jcalz

15

TypeScript 3.4 Güncellemesi:

TypeScript 3.4'e ulaşacak "const bağlamları" adlı yeni bir sözdizimi , gösterildiği gibi bir işlev çağrısı gerektirmeyen daha da basit bir çözüme izin verecektir. Bu özellik şu anda bu PK'da görüldüğü gibi inceleniyor .

Kısacası, bu sözdizimi, dar bir türe sahip (yani veya ['a', 'b', 'c']yerine tür ) değişmez dizilerin oluşturulmasına izin verir . Bu şekilde, değişmez değerlerden birleşim türlerini aşağıda gösterildiği gibi kolayca oluşturabiliriz:('a' | 'b' | 'c')[]string[]

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]

Merhaba, bu soruyu gönderdikten sonra cevabınızı yeni buldum. Cevap vermek istersen biraz karma kazanmana izin vereceğim;) stackoverflow.com/questions/56113411/…
Sebastien Lorber

2

Bunu Array ile yapmak mümkün değildir.

Bunun nedeni, değişkeni const olarak bildirseniz bile, bir dizinin içeriği hala değişebilir, dolayısıyla @jonrsharpe bunun çalışma zamanı olduğunu belirtir.

Eğer kullanmak daha iyi olabilir istediğini Verilen interfaceile keyof:

interface X {
    a: string,
    b: string
}

type Y = keyof X  // Y: 'a' | 'b'

Veya enum:

enum X { a, b, c }

Belirli alanları dışlamanın bir yolu var mı? Örneğin, sadece atarla istiyorsam ..
neomib

Bunun için kullanabilirsiniz Pick<T, U>.
2019
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.