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'.
olhos selvagens
fonte

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;
}
Yozi
fonte
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;
Roger Gusmao
fonte
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
12

as HTMLInputElement funciona para mim

haind
fonte
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.

Leone
fonte
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>

Linshuizhaoying
fonte
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;
}
bobby
fonte
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;
}}
Dryden Williams
fonte
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.

avalanche1
fonte
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} />
)
Código
fonte
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);
};
fjplaurr
fonte
-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

Ali Jamal
fonte