TypeScript türü, bir nesnenin olası özellikler kümesinden tam olarak tek bir özellikten oluştuğu durum
Bir nesnenin olası özellikler kümesinden tam olarak tek bir özelliğe sahip olduğu belirli bir deseni tür sistemi ile modellemeye çalışıyorum.
Başka bir deyişle, bu tür kısmi bir tür olurdu ama sadece bir özellik izin verilirdi.
interface PossibleProperties {
cat?: AllPropsOfSameType;
dog?: AllPropsOfSameType;
cow?: AllPropsOfSameType;
}
interface ShouldBeExactlyOneOfPossibleProperties {
[P in keyof PossibleProperties]: AllPropsOfSameType; // Wupz, this allows for 0 or more...
}
En az bir özelliğin gerekli olduğunu belirten çözümleri gördüm:
type AtLeastOne<T, U = {[K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U]
Ama şuna benzer bir şeye ihtiyacım var: AtMostOne<T, U={[K in keyof T]: Pick<T, K> }> veya ExactlyOne<T, U={[K in keyof T]: Pick<T, K> }> ki bu muhtemelen AtMostOne ve AtLeastOne birleşim türü olabilir
Bunun mümkün olup olmadığı hakkında herhangi bir fikriniz var mı?
Cevap #1
Bu tüm gönderi boyunca kullanılan bilgilerle, aşağıdaki çözümü elde ediyorum:
type Explode<T> = keyof T extends infer K
? K extends unknown
? { [I in keyof T]: I extends K ? T[I] : never }
: never
: never;
type AtMostOne<T> = Explode<Partial<T>>;
type AtLeastOne<T, U = {[K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U]
type ExactlyOne<T> = AtMostOne<T> & AtLeastOne<T>
Cevap #2
Kendi soruma cevap veriyorum, ama kredi https://github.com/keithlayne'e ait çünkü çözümü https://gitter.im/Microsoft/TypeScript üzerinde o buldu.
Ayrıca, ilk mantığı geliştiren https://github.com/fatcerberus'a da kredi verilmelidir.
Buna TS'de modelleme yolu olmadığına oldukça eminim, tamamen yapısal tiplemenin nasıl çalıştığı yüzünden. Tipin açıkça listelemediği fazladan özelliklere her zaman sahip olabilirsiniz.
Tek özellikli türlerin bir birleşimini yapsanız bile, diğerlerinden hiçbirine sahip olmayacağınızın garantisi yoktur
Hmm... Yanılıyor olabilirim. Eğer anahtarlar üzerinde dolaşan ve
{a:string,b:never} | {a:never,b:string}gibi bir birleşim oluşturan bir tür yapabilirsen, bu işe yarayabilir. Ama bunu nasıl yapacağını tam olarak bilmiyorum.
İşte Keith'in cevabı:
type Explode<T> = keyof T extends infer K
? K extends unknown
? { [I in keyof T]: I extends K ? T[I] : never }
: never
: never;
eylemde
Bu muhtemelen anlaması daha kolay:
type Split<T, K extends keyof T> = K extends unknown ? { [I in keyof T]: I extends K ? T[I] : never } : never;
type Explode<T> = Split<T, keyof T>;
Temelde, keyof T'deki her üye için T üzerinde harita oluşturun ve birleşimi döndürün.
