typescript - TS: Bir nesnenin bir string birleşimi türünden tek bir anahtara sahip olduğundan nasıl emin olunur?
MongoDB sorgularına benzeyen, tür güvenli bir sorgu sistemi inşa etmeye çalışıyorum.
Bir nesnenin birleşim tipinde tek bir özelliğe sahip olmasını garanti etmek istiyorum, ama bir çözüm bulamıyorum. Aşağıdaki kodun derlenmesini sağlamama biri yardımcı olabilir mi?
type Operator = 'AND' | 'OR';
type OperatorNode = { [O in Operator]: [] };
const shouldWork1: OperatorNode = {
AND: [],
};
const shouldWork2: OperatorNode = {
OR: [],
};
const shouldFail1: OperatorNode = {};
const shouldFail2: OperatorNode = {
AND: [],
OR: [],
};
Oyun alanında görebileceğiniz gibi, tam olarak istediğim şekilde davranmıyor: http://www.typescriptlang.org/play/?ssl=1&ssc=1&pln=18&pc=3#code/C4TwDgpgBA8pBOBDYB7eUC8UDkBBAcgCLZQA+OMAStgNwBQdoksCya+KAJtFgN5QBtGFACWAOxYQkqeAF0AXINlQAvvToBjFGIDOwKDoAWKAK4AbTgHU0AawCMiuFLbwO3TFF50oUAoUUCsgA0dGoMWrr6RqYW1vA2AEyOrDJuPJ7esJQBwaHqEXoGxuacAGKIImYOktLsXOm8YZrahdEl5ZVJNS5pHl4+fjkhPlRDeUA
Anladığım kadarıyla, bu yapısal türleme nedeniyle gerçekleştirilmesi karmaşık olabilir, ancak belki bazı püf noktaları vardır?
Cevap #1
İstediğiniz nihai tür şudur:
type OperatorNode = { AND: []; OR?: undefined; } | { OR: []; AND?: undefined; }
Yani, her birinin tek bir tanımlı özelliği olan ve geri kalan özelliklerin yalnızca mevcutlarsa undefined olmasına izin verilen türlerin birleşimidir. Bunun, istediğiniz gibi çalıştığını doğrulayabilirsiniz:
const shouldWork1: OperatorNode = { AND: [], }; // okay
const shouldWork2: OperatorNode = { OR: [], }; // okay
const shouldFail1: OperatorNode = {}; // error!
const shouldFail2: OperatorNode = { AND: [], OR: [], }; // error!
Biraz tür oyunu yapmak gerekir, Operator öğesini programatik olarak OperatorNode'a çevirmek için. İşte bunu nasıl yapardım:
type ExclusiveRecord<K extends PropertyKey, V> = {
[P in K]: Record<P, V> & Partial<Record<Exclude<K, P>, never>> extends
infer O ? { [Q in keyof O]: O[Q] } : never }[K]
Bu, birlik K'nin her bir elemanı P üzerinde tekrar eden birkaç eşleme türü kullanır ve Record<P, V> & Partial<Record<Exclude<K, P>, never>> yapılarını oluşturur. Record<P, V>, P anahtarının V değerine sahip olduğu anlamına gelir ve Partial<Record<Exclude<K, P>, never>>, P dışında K'deki her anahtar için tanımlı değer bulunmadığı anlamına gelir. extends infer O... kısmı ise sadece o çirkin kesişim tipini tek bir nesne tipine dönüştürmek içindir, böylece Record<"AND", []> & Partial<Record<"OR", never>> ile uğraşmak zorunda kalmayız. Ardından bunların hepsi sonunda birleştirilir. Hadi çalıştığından emin olalım:
type OperatorNode = ExclusiveRecord<Operator, []>
/* type OperatorNode = {
AND: [];
OR?: undefined;
} | {
OR: [];
AND?: undefined;
}
*/
Evet, iyi görünüyor. Umarım yardımcı olur; iyi şanslar!
Koda bağlantı
