Подтвердить что ты не робот

Typescript: Реагировать типы событий

Каков правильный тип для событий React. Первоначально я просто использовал any для простоты. Теперь я пытаюсь очистить вещи и полностью не использовать any.

Итак, в простой форме:

export interface LoginProps {
  login: {
    [k: string]: string | Function
    uname: string
    passw: string
    logIn: Function
  }
}
@inject('login') @observer
export class Login extends Component<LoginProps, {}> {
  update = (e: React.SyntheticEvent<EventTarget>): void => {
    this.props.login[e.target.name] = e.target.value
  }
  submit = (e: any): void => {
    this.props.login.logIn()
    e.preventDefault()
  }
  render() {
    const { uname, passw } = this.props.login
    return (
      <div id='login' >
        <form>
          <input
            placeholder='Username'
            type="text"
            name='uname'
            value={uname}
            onChange={this.update}
          />
          <input
            placeholder='Password'
            type="password"
            name='passw'
            value={passw}
            onChange={this.update}
          />
          <button type="submit" onClick={this.submit} >
            Submit
          </button>
        </form>
      </div>
    )
  }
}

Какой тип я использую здесь как тип события?

React.SyntheticEvent<EventTarget>, похоже, не работает, поскольку я получаю сообщение об ошибке, что name и value не существуют на target.

Более общий ответ для всех событий будет действительно оценен.

Спасибо

4b9b3361

Ответ 1

Интерфейс SyntheticEvent является общим:

interface SyntheticEvent<T> {
    ...
    currentTarget: EventTarget & T;
    ...
}

И currentTarget является пересечением общего ограничения и EventTarget.
Кроме того, так как ваши события вызваны элементом ввода, вы должны использовать FormEvent (в файле определения, реагировать документы).

Должно быть:

update = (e: React.FormEvent<HTMLInputElement>): void => {
    this.props.login[e.currentTarget.name] = e.currentTarget.value
}

Ответ 2

Проблема не в типе Event, но в интерфейсе EventTarget в typescript есть только 3 метода:

interface EventTarget {
    addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
    dispatchEvent(evt: Event): boolean;
    removeEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}

interface SyntheticEvent {
    bubbles: boolean;
    cancelable: boolean;
    currentTarget: EventTarget;
    defaultPrevented: boolean;
    eventPhase: number;
    isTrusted: boolean;
    nativeEvent: Event;
    preventDefault(): void;
    stopPropagation(): void;
    target: EventTarget;
    timeStamp: Date;
    type: string;
}

Итак, правильно, что name и value не существуют на EventTarget. Что вам нужно сделать, так это указать цель в конкретный тип элемента с необходимыми свойствами. В этом случае это будет HTMLInputElement.

update = (e: React.SyntheticEvent): void => {
    let target = e.target as HTMLInputElement;
    this.props.login[target.name] = target.value;
}

Также для событий вместо React.SyntheticEvent вы также можете ввести их как: Event, MouseEvent, KeyboardEvent... и т.д., зависит от варианта использования обработчика.

Лучший способ увидеть все эти определения типов - проверить файлы .d.ts как из typescript, так и отреагировать.

Также ознакомьтесь со следующей ссылкой для получения дополнительных пояснений: Почему Event.target not Element в Typescript?

Ответ 3

Чтобы объединить ответы Нитцана и Эдвина, я обнаружил, что для меня это работает:

update = (e: React.FormEvent<EventTarget>): void => {
    let target = e.target as HTMLInputElement;
    this.props.login[target.name] = target.value;
}

Ответ 4

Я думаю, что самый простой способ заключается в том, что:

type InputEvent = React.ChangeEvent<HTMLInputElement>;
type ButtonEvent = React.MouseEvent<HTMLButtonElement>;

update = (e: InputEvent): void => this.props.login[e.target.name] = e.target.value;
submit = (e:  ButtonEvent): void => {
    this.props.login.logIn();
    e.preventDefault();
}