Entrada datilografada onchange event.target.value


142

Na minha reagir e aplicativo original datilografado, eu uso: onChange={(e) => data.motto = (e.target as any).value}.

Como defino corretamente as digitações para a classe, para que eu não precise me intrometer no sistema de tipos any?

export interface InputProps extends React.HTMLProps<Input> {
...

}

export class Input extends React.Component<InputProps, {}> {
}

Se eu colocar target: { value: string };, recebo:

ERROR in [default] /react-onsenui.d.ts:87:18
Interface 'InputProps' incorrectly extends interface 'HTMLProps<Input>'.
  Types of property 'target' are incompatible.
    Type '{ value: string; }' is not assignable to type 'string'.

Respostas:


243

Geralmente, os manipuladores de eventos devem usar e.currentTarget.value, por exemplo:

onChange = (e: React.FormEvent<HTMLInputElement>) => {
    const newValue = e.currentTarget.value;
}

Você pode ler o porquê disso aqui ( reverta "Torne SyntheticEvent.target genérico, não SyntheticEvent.currentTarget." ).

UPD: Conforme mencionado por @ roger-gusmao, ChangeEventmais adequado para digitar eventos de formulário.

onChange = (e: React.ChangeEvent<HTMLInputElement>)=> {
   const newValue = e.target.value;
}

17
Isso simplesmente não funciona. valor não é uma propriedade da interface EventTarget
— tocqueville 28/03

1
Claro que não EventTarget, mas parte de HTMLInputElement Você pode ver definição completa aqui github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/...
— Yozi

1
Oh, desculpe, você usou currentTarget. Nesse caso, sim, funciona, mas a pergunta era sobretarget
— tocqueville

1
Sim, você está certo, mas conforme mencionado em github.com/DefinitelyTyped/DefinitelyTyped/pull/12239, o uso targetincorreto na maioria dos casos. Além disso, o alvo não tiver Tpara nos forçar a escrever corretamente
— Yozi

1
Isso não funcionou para mim, tive que transmitir o evento para React.ChangeEvent<HTMLInputElement>um FormEvent.
— Oblivionkey3

86

a maneira correta de usar no TypeScript é

  handleChange(e: React.ChangeEvent<HTMLInputElement>) {
    // No longer need to cast to any - hooray for react!
    this.setState({temperature: e.target.value});
  }

  render() {
        ...
        <input value={temperature} onChange={this.handleChange} />
        ...
    );
  }

Siga a aula completa, é melhor entender:

import * as React from "react";

const scaleNames = {
  c: 'Celsius',
  f: 'Fahrenheit'
};


interface TemperatureState {
   temperature: string;
}

interface TemperatureProps {
   scale: string;

}

class TemperatureInput extends React.Component<TemperatureProps, TemperatureState> {
  constructor(props: TemperatureProps) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.state = {temperature: ''};
  }

  //  handleChange(e: { target: { value: string; }; }) {
  //    this.setState({temperature: e.target.value});  
  //  }


  handleChange(e: React.ChangeEvent<HTMLInputElement>) {
    // No longer need to cast to any - hooray for react!
    this.setState({temperature: e.target.value});
  }

  render() {
    const temperature = this.state.temperature;
    const scale = this.props.scale;
    return (
      <fieldset>
        <legend>Enter temperature in {scaleNames[scale]}:</legend>
        <input value={temperature} onChange={this.handleChange} />
      </fieldset>
    );
  }
}

export default TemperatureInput;

3
Nota: Para garantir tipos estão disponíveis, adicione lib: ["dom"]a compilerOptionsemtsconfig.json
— James Conkling

1
@JamesConkling Muito obrigado!
— Alexandre Rivest

1
E se você tiver várias entradas, precisará criar uma linha para cada uma?
— Trevor madeira

Outra maneira de garantir que 'this' seja atribuído adequadamente na função handleChange seria escrever handleChange como uma função de seta, por exemplo, handleChange = (e: React.ChangeEvent <HTMLInputElement>) => {this.setState (...); }; Ao fazer isso, não seria mais necessário usar o construtor para vincular a função handleEvent.
— tlavarea 16/09/19

Mais uma maneira de lidar com 'this' em vez de usar o construtor e o método bind seria usar a função de seta no objeto onChange, ou seja, onChange = {e => this.handleChange (e)}
— tlavarea


9

O que targetvocê tentou adicionar InputPropsnão é o mesmo que targetvocê queria, que está noReact.FormEvent

Portanto, a solução que eu pude encontrar foi estender os tipos relacionados ao evento para adicionar seu tipo de destino, como:

interface MyEventTarget extends EventTarget {
    value: string
}

interface MyFormEvent<T> extends React.FormEvent<T> {
    target: MyEventTarget
}

interface InputProps extends React.HTMLProps<Input> {
    onChange?: React.EventHandler<MyFormEvent<Input>>;
}

Depois de ter essas classes, você pode usar seu componente de entrada como

<Input onChange={e => alert(e.target.value)} />

sem erros de compilação. De fato, você também pode usar as duas primeiras interfaces acima para seus outros componentes.


O tipo de valor não é uma string!
— Roger Gusmao

7

sorte eu encontrar uma solução. você pode

importar {ChangeEvent} de 'reagir';

e escreva um código como: e:ChangeEvent<HTMLInputElement>


2

Aqui está uma maneira de destruir o objeto ES6, testado com o TS 3.3.
Este exemplo é para uma entrada de texto.

name: string = '';

private updateName({ target }: { target: HTMLInputElement }) {
    this.name = target.value;
}

1

É quando você está trabalhando com um FileListObjeto:

onChange={(event: React.ChangeEvent<HTMLInputElement>): void => {
  const fileListObj: FileList | null = event.target.files;
  if (Object.keys(fileListObj as Object).length > 3) {
    alert('Only three images pleaseeeee :)');
  } else {
    // Do something
  }

  return;
}}

1
  function handle_change(
    evt: React.ChangeEvent<HTMLInputElement>
  ): string {
    evt.persist(); // This is needed so you can actually get the currentTarget
    const inputValue = evt.currentTarget.value;

    return inputValue
  }

E certifique-se de ter o "lib": ["dom"]seu tsconfig.


1

Ao usar o componente filho, verificamos o tipo como este.

Componente pai:

export default () => {

  const onChangeHandler = ((e: React.ChangeEvent<HTMLInputElement>): void => {
    console.log(e.currentTarget.value)
  }

  return (
    <div>
      <Input onChange={onChangeHandler} />
    </div>
  );
}

Componente filho:

type Props = {
  onChange: (e: React.ChangeEvent<HTMLInputElement>) => void
}

export Input:React.FC<Props> ({onChange}) => (
  <input type="tex" onChange={onChange} />
)

0

Uma alternativa que ainda não foi mencionada é digitar a função onChange em vez dos props que ela recebe. Usando React.ChangeEventHandler:

const stateChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {
    console.log(event.target.value);
};

-1

Obrigado @haind

Sim HTMLInputElementtrabalhou para o campo de entrada

//Example
var elem = e.currentTarget as HTMLInputElement;
elem.setAttribute('my-attribute','my value');
elem.value='5';

Essa HTMLInputElementinterface é herdada da HTMLElementqual é herdada EventTargetno nível raiz. Portanto, podemos afirmar usando o asoperador para usar interfaces específicas de acordo com o contexto, como neste caso, estamos usando HTMLInputElementpara o campo de entrada outras interfaces HTMLButtonElement, HTMLImageElementetc.

https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement

Para mais referência, você pode verificar outra interface disponível aqui

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.