TypeScript中的条件键入

时间:2019-07-16 18:26:17

标签: typescript

错误和Touched属性一起使用,我想知道是否有任何方法可以将两者结合使用。在我看来,用作可选(?)很浅。

是否有一种方法可以使从“错误”被填补的那一刻起就需要使用“触摸”?!

import { ChangeEvent, FocusEvent, Ref } from 'react';

export interface FormikProps<Value, Element> {
  name: string;
  value: Value;
  onChange: (event: ChangeEvent<Element>) => void;
  onBlur: (event: FocusEvent<Element>) => void;
  error?: string | undefined;
  touched?: boolean | undefined;
  ref?: Ref<Element>;
}

1 个答案:

答案 0 :(得分:4)

是的,如果可以使用type alias而不是接口,则可以使用union type来表示约束(以及intersection来表示公共属性):

BeanCreatedEventListener

您可以查看是否必须同时使用或不使用:

  type FormikProps<Value, Element> = {
    name: string;
    value: Value;
    onChange: (event: ChangeEvent<Element>) => void;
    onBlur: (event: FocusEvent<Element>) => void;
    ref?: Ref<Element>;
  } & (
    | { error: string; touched: boolean }
    | { error?: never; touched?: never });

否则会出现错误:

  const useBoth: FormikProps<string, number> = {
    name: "F",
    value: "v",
    onChange: e => console.log(e),
    onBlur: e => console.log(e),
    error: "hey",
    touched: false
  }; // okay

  const useNeither: FormikProps<string, number> = {
    name: "F",
    value: "v",
    onChange: e => console.log(e),
    onBlur: e => console.log(e)
  }; // okay

您可能会发现在检查它的函数中使用这种类型有点烦人,因为这里的控制流分析似乎有点问题:

  const justUseError: FormikProps<string, number> = { // error!
  //    ~~~~~~~~~~~~ <-- "touched is missing"
    name: "F",
    value: "v",
    onChange: e => console.log(e),
    onBlur: e => console.log(e),
    error: "hey",
  };

  const justUseTouched: FormikProps<string, number> = { // error!
  //    ~~~~~~~~~~~~~~ <-- "error is missing"
    name: "F",
    value: "v",
    onChange: e => console.log(e),
    onBlur: e => console.log(e),
    touched: true
  };

但是它可能仍然比原始定义有用。


我同意一个评论者的意见,您可能希望将两者封装在一起:

  function f(fp: FormikProps<string, number>) {

    if (typeof fp.error === "string") {
      fp.touched.valueOf(); // error!
    //~~~~~~~~~~ <-- object is possibly undefined ?!
      fp.touched!.valueOf(); // okay, asserted
    } 

    if (fp.error) {
      fp.touched.valueOf(); // this works for some reason
    }

  }

该类型很简单,类型系统会更了解它:

  interface Encapsulated<Value, Element> {
    name: string;
    value: Value;
    onChange: (event: ChangeEvent<Element>) => void;
    onBlur: (event: FocusEvent<Element>) => void;
    ref?: Ref<Element>;
    errTouched?: { error: string; touched: boolean };
  }

无论如何,希望能有所帮助;祝你好运!

Link to code