Компонент Typescript и React, который принимает onChange как для TextArea, так и для ввода

Я новичок в машинописном тексте, и я пытаюсь создать компонент ввода, который, если он получает type = "text", отображает input, а если он получает type = "textarea", он отображает, вы его получили, textarea. Проблема в том, что машинописный текст жалуется, когда я использую компонент в своем коде вместе с onChange, кажется, это не позволяет мне использовать два типа в одном и том же событии?

Он показывает мне:

Type '(e: ChangeEvent<HTMLInputElement>) => void' is not assignable to type '(e?: ChangeEvent<HTMLInputElement> | ChangeEvent<HTMLTextAreaElement> | undefined) => void'.
Types of parameters 'e' and 'e' are incompatible.
Type 'ChangeEvent<HTMLInputElement> | ChangeEvent<HTMLTextAreaElement> | undefined' is not assignable to type 'ChangeEvent<HTMLInputElement>'.
Type 'undefined' is not assignable to type 'ChangeEvent<HTMLInputElement>'.

input.js

interface InputProps {
  className?: string;
  type?: string;
  placeholder?: string;
  onChange?: (e?: React.ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement>) => void;
}

const Input: FunctionComponent<InputProps> = ({ type = 'text', ...props }) => {
  if (type === 'textarea') {
    return <textarea {...props} />;
  }
  return <input type = {type} {...props} />;
};

использование:

class Usage extends React.Component<State> {
  state: State;

  onInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    this.setState({ input: e.target.value });
  };

  render() {
    return (
        <Input placeholder = "Write an something..." onChange = {this.onInputChange} />
    );
  }
}

Как я могу это исправить?


ОБНОВИТЬ

На данный момент я решил это, сказав, что событие может иметь тип any, но это своего рода взлом

type CommonProps = {
  className?: string;
  placeholder?: string;
  type?: string;
  onChange?: (e: any) => void;
};

Не могли бы вы вставить свою версию машинописного текста и версию @ types / react? Кажется, это работает для меня, но, вероятно, я делаю что-то по-другому. Кстати, он на самом деле жалуется на эту деталь undefined, так что e не является обязательным.

barnski 27.12.2018 12:15

@barnski typescript - v3.2.1 / @ types / react - v16.7.6

JCQuintas 27.12.2018 15:54
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
11
2
11 972
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вам нужно создать класс, если вы используете машинописный текст. Обычная функция не позволяет использовать | в типах опор машинописного текста.

Это должен быть ваш файл Input.js:

export interface IInputProps {
  className?: string;
  type?: string;
  placeholder?: string;
  onChange?: (e?: React.ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement>) => void;
}

export class Input extends React.Component<IInputProps, {}> {
  constructor(props: IInputProps) {
    super(props);
  }
  render() {
    const { props, props: { type } } = this;
    if (type === 'textarea') {
      return <textarea {...props} />;
    }
    return <input type = {type} {...props} />;
  }
}

и вот как это можно использовать:

class Usage extends React.Component<State> {
  state: State;

  onInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    this.setState({ input: e.target.value });
  };

  render() {
    return (
      <Input placeholder = "Write an something..." onChange = {this.onInputChange} />
    );
  }
}

Вот как он будет оценивать, является ли это Input или TextArea:

Хм .. каково ваше определение IInputProps? В коде, который вы предоставляете, такая же ошибка в Usage.

Titian Cernicova-Dragomir 27.12.2018 12:39

TypeScript V3.2.2

Harish Soni 27.12.2018 12:40

ваш код работает с strict:false, но код OP также работал бы со строгим выключением ... Я предполагаю, что strictFunctionTypes вызывает ошибку при назначении onChange

Titian Cernicova-Dragomir 27.12.2018 12:46
Ответ принят как подходящий

Вы можете использовать размеченное объединение для передачи двух типов аргументов: одного для text, а другого для textarea. Это дает дополнительный бонус в виде обеспечения синхронизации обработчика и типа.

type InputProps = { // The common Part
    className?: string;
    placeholder?: string;
} & ({ // The discriminated union
    type?: "text";
    onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
} | {
    type: "textarea";
    onChange?: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;
})

const Input: FunctionComponent<InputProps> = (props: InputProps) => {
    if (props.type === 'textarea') {
        return <textarea {...props} />;
    }
    return <input {...props} />;
};


class Usage extends React.Component<State> {
    state: State;

    onInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        this.setState({ input: e.target.value });
    };

    render() {
        return (
            <Input placeholder = "Write an something..." onChange = {this.onInputChange} />
        );
    }
}

Слишком долго, пришлось добавить в качестве ответа

JCQuintas 27.12.2018 15:50

У меня работает: github.com/dragomirtitian/so-answers/tree/so-53943737

Titian Cernicova-Dragomir 27.12.2018 16:01

Это сработало с некоторыми корректировками. Он терпит неудачу всякий раз, когда я пытаюсь разрушить реквизит. Спасибо!

JCQuintas 27.12.2018 16:18

@JCQuintas, да, нарушение структуры не будет работать должным образом из-за союза ... поэтому я удалил его. (Удалите ответ с ошибкой, иначе он получит отрицательное голосование по уважительной причине)

Titian Cernicova-Dragomir 27.12.2018 16:24

Другие вопросы по теме