简体   繁体   English

TypeScript中的条件键入

[英]Conditional typing in TypeScript

Errors and Touched attributes are used together, and I was wondering if there is any way to tie the use of the two. 错误和Touched属性一起使用,我想知道是否有任何方法可以将两者结合使用。 To use as optional (?) seems to me very shallow. 在我看来,用作可选(?)似乎很浅。

Would there be a way to make it required to use 'touched' from the moment the 'errors' are filled?! 从“错误”被填补的那一刻起,有没有办法让它需要使用“触摸”?

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

Yes, if you can use a type alias instead of an interface, you'd use a union type to represent the constraint (along with an intersection to represent the common properties): 是的,如果您可以使用类型别名而不是接口,则可以使用联合类型来表示约束(以及使用交集来表示公共属性):

  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 });

You can see if you use it that you have to use both or neither: 您可以查看是否同时使用它或不使用:

  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

or else you get errors: 否则你会得到错误:

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

You might find it a little annoying to use this type inside a function that checks it, since it seems that there's a bit of an issue with control flow analysis here: 您可能会发现在用于检查它的函数中使用此类型有些烦人,因为此处的控制流分析似乎存在一些问题:

  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
    }

  }

but it's still probably more useful than your original definition. 但它可能仍然比原始定义有用。


I agree with a commenter that you might want to encapsulate the two together: 我同意一个评论者的意见,您可能希望将两者封装在一起:

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

That type is straightforward and the type system will understand it more: 该类型很简单,并且类型系统会更多地了解它:

  function f2(fp: Encapsulated<string, number>) {
    if (fp.errTouched) {
      fp.errTouched.error.valueOf(); // okay
      fp.errTouched.touched.valueOf(); // okay
    }
  }

Anyway, hope that helps; 无论如何,希望能有所帮助; good luck! 祝好运!

Link to code 链接到代码

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM