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.