TypeScript'teki koşullu türler


65

TypeScript'te koşullu türlere sahip olup olamayacağımı merak ediyordum?

Şu anda aşağıdaki arayüze sahibim:

interface ValidationResult {
  isValid: boolean;
  errorText?: string;
}

Ama kaldırmak istiyor errorTextve yalnızca ona sahip isValidolan falsebir olarak gerekli özellik.

Keşke şu arayüz olarak yazabilseydim:

interface ValidationResult {
  isValid: true;
}

interface ValidationResult {
  isValid: false;
  errorText: string;
}

Ama bildiğiniz gibi, bu mümkün değil. Peki, bu durum hakkında fikriniz nedir?


, Ne zaman demek istiyorsunuz isValidolduğunu false?
CertainPerformance

18
isValid artık gereksizdir. Siz de sadece errorText'e sahip olabilirsiniz ve sonra errorText boşsa, hata yoktur.
MTilsted

Evet, @MTilsted, haklısınız, ancak eski kodlarımız nedeniyle saklamamız gerekiyor.
Arman

Yanıtlar:


89

Bu tür bir mantığı modellemenin bir yolu, sendika türünü kullanmaktır.

interface Valid {
  isValid: true
}

interface Invalid {
  isValid: false
  errorText: string
}

type ValidationResult = Valid | Invalid

const validate = (n: number): ValidationResult => {
  return n === 4 ? { isValid: true } : { isValid: false, errorText: "num is not 4" }
}

Derleyici, boole bayrağına dayalı olarak türü daraltabilir.

const getErrorTextIfPresent = (r: ValidationResult): string | null => {
  return r.isValid ? null : r.errorText
}

7
Güzel cevap. Ve derleyici aslında burada rtür olması gerektiğini söyleyebilir büyüleyici Invalid.
sleske

1
Buna ayrımcı sendikalar denir. Oldukça havalı şeyler: typescriptlang.org/docs/handbook/…
Umur Kontacı

41

Yalnızca üçte biri oluşturmak için kullanılan birden fazla arabirim oluşturmaktan kaçınmak için, typebunun yerine doğrudan da değiştirebilirsiniz :

type ValidationResult = {
    isValid: false;
    errorText: string;
} | {
    isValid: true;
};

20

Böcek gösterdiği birlik bu işleme tavsiye nasıl. Yine de, typescript yok “olarak bilinen bir şey var şartlı türleri ,” ve bu işleyebilir.

type ValidationResult<IsValid extends boolean = boolean> = (IsValid extends true
    ? { isValid: IsValid; }
    : { isValid: IsValid; errorText: string; }
);


declare const validation: ValidationResult;
if (!validation.isValid) {
    validation.errorText;
}

Bu ValidationResult(aslında ValidationResult<boolean>varsayılan parametreden kaynaklanmaktadır) hataların cevabında veya CertainPerformance'ın cevabında üretilen birliğe eşdeğerdir ve aynı şekilde kullanılabilir.

Buradaki avantaj da bilinen etrafında geçebileceği olmasıdır ValidationResult<false>değeri ve sonra teste olmazdı isValidolmasını bilinecek şekilde falseve errorStringvarlığı biliniyor olacaktır. Muhtemelen böyle bir vaka için gerekli değildir - ve koşullu türler karmaşık ve hata ayıklaması zor olabilir, bu nedenle muhtemelen gereksiz yere kullanılmamalıdır. Ama yapabilirdiniz ve bundan bahsetmeye değer görünüyordu.


3
Bunların zaman zaman gerçekten yararlı olduğuna eminim. Ama benim için sözdizimi gerçekten kötü görünüyor.
Peilonrayz

3
@Peilonrayz Eh, diğer daktilo kodları ile iyi bir tutarlılığa sahiptir ve extendskullanmak için doğru operatördür. Ve bu da tip olarak kazmak için kullanabilirsiniz özellikle beri son derece güçlü sahiptir: type SecondOf<T> = T extends Pair<any, infer U> ? U : never;.
KRyan

@KRyan Bunu düşünüyordum. Bu sadece SecondOf<number>'genişlemek' anlamına mı geliyor Pair<any, number>? Sanırım burada "bir kitabı kapağına göre yargılama" söz konusudur.
Peilonrayz

@Peilonrayz Ah, hayır; tam tersi. SecondOf<Pair<any, number>>olarak değerlendirir number. SecondOf<number>olarak değerlendirir never, çünkü number extends Pair<any, infer U>yanlış numberdeğildir , herhangi bir Pair
kapsamı
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.