TypeScript中的条件类型


65

我想知道我是否可以在TypeScript中使用条件类型?

目前,我有以下界面:

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

但我想删除errorText,并且仅在isValidis false作为必需属性时才使用它。

我希望能够将其编写为以下界面:

interface ValidationResult {
  isValid: true;
}

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

但是,正如您所知,这是不可能的。那么,您对此情况有何想法?


isValidfalse什么时候?
某些性能

18
那么isValid是多余的。您也可能只具有errorText,然后如果errorText为null,则没有错误。
MTilsted

是的,@ MTilsted,您是对的,但是由于我们的旧代码,我们必须保留它。
阿尔曼

Answers:


89

对这种逻辑进行建模的一种方法是使用联合类型,诸如此类

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" }
}

然后,编译器可以根据布尔标志缩小类型

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

7
好答案。令人着迷的是编译器实际上可以告诉您这里r必须是类型Invalid
sleske

1
这称为歧视工会。很酷的东西:typescriptlang.org/docs/handbook/...
UmurKontacı

41

为了避免创建仅用于创建第三个接口的多个接口,您还可以直接使用a type代替:

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

20

我建议如何处理由错误演示联合。尽管如此,Typescript 确实有一些称为“ 条件类型 ”的东西,他们可以处理。

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


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

ValidationResult(实际上是ValidationResult<boolean>由于默认参数引起的)等效于错误的答案或某些性能的答案中产生的联合并集,并且可以以相同的方式使用。

这样做的好处是您还可以传递一个已知ValidationResult<false>值,然后不必进行测试,isValid因为它被认为是falseerrorString将已知的存在。在这种情况下可能没有必要,而且条件类型可能很复杂且难以调试,因此可能不应不必要地使用它们。但是您可以,这似乎值得一提。


3
我确信这些有时确实很有帮助。但是,对我来说,语法看起来真的很讨厌。
Peilonrayz

3
@Peilonrayz嗯,它与其他Typescript编码具有良好的一致性,并且extends是正确的操作员。而且它功能非常强大,特别是因为您还可以使用它来挖掘类型:type SecondOf<T> = T extends Pair<any, infer U> ? U : never;
KRyan

@KRyan我一直在想这个。这基本上只是意味着SecondOf<number>“扩展”到Pair<any, number>吗?我想这句话很恰当:“不要凭封面判断书”。
Peilonrayz

@Peilonrayz啊,不;相反。SecondOf<Pair<any, number>>评估为numberSecondOf<number>计算结果为never,因为number extends Pair<any, infer U>为假,number不进行任何扩展Pair
KRyan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.