TypeScript 中的条件类型

Arm*_*man 72 javascript types typescript

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

目前我有以下界面:

interface ValidationResult {
  isValid: boolean;
  errorText?: string;
}
Run Code Online (Sandbox Code Playgroud)

但我想删除errorText,而当只有它isValidfalse一个必需的属性。

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

interface ValidationResult {
  isValid: true;
}

interface ValidationResult {
  isValid: false;
  errorText: string;
}
Run Code Online (Sandbox Code Playgroud)

但如你所知,这是不可能的。那么,您对这种情况有何看法?

bug*_*ugs 94

对这种逻辑建模的一种方法是使用联合类型,像这样

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" }
}
Run Code Online (Sandbox Code Playgroud)

然后编译器能够根据布尔标志缩小类型

const getErrorTextIfPresent = (r: ValidationResult): string | null => {
  return r.isValid ? null : r.errorText
}
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案。令人着迷的是,编译器实际上可以告诉我们这里的“r”必须是“Invalid”类型。 (7认同)
  • 这称为歧视性工会。非常酷的东西:https://www.typescriptlang.org/docs/handbook/advanced-types.html#discriminated-unions (2认同)

Cer*_*nce 43

为避免创建仅用于创建第三个接口的多个接口,您也可以直接交替使用type

type ValidationResult = {
    isValid: false;
    errorText: string;
} | {
    isValid: true;
};
Run Code Online (Sandbox Code Playgroud)


KRy*_*yan 22

错误展示联合是我推荐的处理方式。尽管如此,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;
}
Run Code Online (Sandbox Code Playgroud)

ValidationResult(实际上是ValidationResult<boolean>由于默认参数造成的)相当于在 bugs 的答案或CertainPerformance 的答案中产生的联合,并且可以以相同的方式使用。

这里的优点是您还可以传递一个已知ValidationResult<false>值,然后您就不必进行测试,isValid因为它会被知道false并且errorString会被知道存在。对于这种情况,可能没有必要——条件类型可能很复杂且难以调试,因此可能不应不必要地使用它们。但是你可以,而且这似乎值得一提。

  • 我确信这些有时确实很有帮助。但是,对我来说,语法看起来真的很糟糕。 (3认同)
  • @Peilonrayz 嗯,它与其他 Typescript 编码具有良好的一致性,并且“extends”是正确使用的运算符。它非常强大,特别是因为您还可以使用它来挖掘类型:`type SecondOf&lt;T&gt; = T extends Pair&lt;any, infer U&gt; ?U:从来没有;`。 (3认同)