导出具有通用类型的组件时如何定义通用类型

时间:2019-05-15 01:32:09

标签: reactjs typescript

我正在使用typescript来执行React组件。我在定义泛型时遇到问题。下面是代码:

interface Props<T> {
  classes: { [className in keyof typeof styles]: string };
  style?: React.CSSProperties;
  value?: T;
  label: string;
  onChange: (e: T) => void;
}

export const OutlinedInputField = withStyles(styles)(
  <T extends string | number>({ classes, style, value, onChange, label }: Props<T>) => {
    const type = typeof value  === 'number' ? 'number' : 'text';
    return (
      <Grid className={classes.root} style={style}>
        <TextField
          value={value}
          type={type}
          variant="outlined"
          label={label}
          onChange={(e) => onChange(e.target.value as T)}
        />
      </Grid>
    );
  }
);

上述组件的value属性需要通用类型。并且它使用此类型来确定它是数字还是文本Textfield。我不了解如何使用此组件?

如果我通过以下方式使用此组件(value属性的类型为数字),则onChange上的参数为numberstring。它不限制类型为数字。如何在number组件上强制使用类型OutlinedInputField

<OutlinedInputField value={value} label="Item weight (kg)" onChange={(n: number) => setValue(n)}/>

我尝试了下面的代码,但收到错误Expected 0 type arguments, but got 1.

<OutlinedInputField<number> value={value} label="Item weight (kg)" onChange={(n: number) => setValue(n)}/>

1 个答案:

答案 0 :(得分:0)

我可以想到有两种选择可以实现这一目标:

  1. Cast the export
export const OutlinedInputField = withStyles(styles)(
  ({ classes, style, value, onChange, label }: Props<string | number>) => {
    const type = typeof value === "number" ? "number" : "text";
    return (
      <Grid className={classes.root} style={style}>
        <TextField
          value={value}
          type={type}
          variant="outlined"
          label={label}
          onChange={e => onChange(e.target.value as T)}
        />
      </Grid>
    );
  }
) as <T extends number | string>(props: Props<T>) => any

用法

<OutlinedInputField<number> value={value} label="Item weight (kg)" onChange={(n: number) => setValue(n)}/>
  1. 工厂
export const createOutlinedInputField = <T extends number | string>() => {
  const OutlinedInputField: React.FC<Props<T>> = ({ classes, style, value, onChange, label }) => {
    const type = typeof value === "number" ? "number" : "text";
    return (
      <Grid className={classes.root} style={style}>
        <TextField
          value={value}
          type={type}
          variant="outlined"
          label={label}
          onChange={e => onChange(e.target.value as T)}
        />
      </Grid>
    );
  };

  return withStyles()(OutlinedInputField);
};

用法:

const OutlinedInputField = createOutlinedInputField<number>();

<OutlinedInputField value={value} label="Item weight (kg)" onChange={(n: number) => setValue(n)}/>