อินพุต typescript onchange event.target.value


146

ในแอป react และ typescript ของฉันฉันใช้: onChange={(e) => data.motto = (e.target as any).value}.

ฉันจะทำอย่างไรได้อย่างถูกต้องกำหนด typings สำหรับการเรียนดังนั้นฉันจะได้ไม่ต้องตัดทางของฉันรอบระบบการพิมพ์ด้วยany?

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

}

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

ถ้าฉันใส่target: { value: string };ฉันจะได้รับ:

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'.

คำตอบ:


249

โดยทั่วไปตัวจัดการเหตุการณ์ควรใช้e.currentTarget.valueเช่น:

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

คุณสามารถอ่านสาเหตุได้ที่นี่ ( เปลี่ยนกลับ "Make SyntheticEvent.target generic ไม่ใช่ SyntheticEvent.currentTarget" )

UPD: ดังที่กล่าวโดย @ roger-gusmao ChangeEventเหมาะสำหรับการพิมพ์เหตุการณ์ในรูปแบบ

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

17
สิ่งนี้ไม่ได้ผล ค่าไม่ใช่คุณสมบัติของอินเทอร์เฟซ EventTarget
tocqueville

1
ไม่แน่นอน EventTarget แต่เป็นส่วนหนึ่งของ HTMLInputElement คุณสามารถดูความหมายเต็มได้ที่นี่github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/...
Yozi

1
currentTargetโอ้ขอโทษที่คุณใช้ ในกรณีนั้นใช่มันได้ผล แต่คำถามคือเกี่ยวกับtarget
tocqueville

1
ใช่คุณพูดถูก แต่ตามที่กล่าวไว้ในgithub.com/DefininiteTyped/DefininiteTyped/pull/12239โดยใช้targetไม่ถูกต้องในกรณีส่วนใหญ่ ยิ่งไปกว่านั้นเป้าหมายไม่จำเป็นต้องTบังคับให้เราเขียนอย่างถูกต้อง
Yozi

1
สิ่งนี้ไม่ได้ผลสำหรับฉันฉันต้องแคสต์เหตุการณ์React.ChangeEvent<HTMLInputElement>เป็นมากกว่า FormEvent
Oblivionkey3

87

วิธีที่ถูกต้องในการใช้ 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} />
        ...
    );
  }

ทำตามชั้นเรียนที่สมบูรณ์จะดีกว่าที่จะเข้าใจ:

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
ทราบ: เพื่อให้แน่ใจว่าประเภทที่มีอยู่เพิ่มlib: ["dom"]ไปcompilerOptionsในtsconfig.json
เจมส์คลิง

1
@JamesConkling ขอบคุณมาก!
Alexandre Rivest

1
และถ้าคุณมีหลายอินพุตคุณต้องสร้างแถวสำหรับแต่ละรายการหรือไม่?
Trevor Wood

อีกวิธีหนึ่งในการตรวจสอบให้แน่ใจว่ามีการกำหนด 'this' อย่างเหมาะสมในฟังก์ชัน handleChange คือการเขียน handleChange เป็นฟังก์ชันลูกศรเช่น handleChange = (e: React.ChangeEvent <HTMLInputElement>) => {this.setState (... ); }; เมื่อทำเช่นนั้นเราจะไม่ต้องใช้ตัวสร้างเพื่อผูกฟังก์ชัน handleEvent อีกต่อไป
tlavarea

อีกวิธีหนึ่งในการจัดการ 'สิ่งนี้' แทนที่จะใช้ตัวสร้างและวิธีการผูกคือการใช้ฟังก์ชันลูกศรใน onChange prop เช่น onChange = {e => this.handleChange (e)}
tlavarea


9

สิ่งที่targetคุณพยายามเพิ่มเข้ามาInputPropsนั้นไม่เหมือนกับที่targetคุณต้องการซึ่งมีอยู่React.FormEvent

ดังนั้นวิธีแก้ปัญหาที่ฉันคิดได้คือการขยายประเภทที่เกี่ยวข้องกับเหตุการณ์เพื่อเพิ่มประเภทเป้าหมายของคุณเป็น:

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>>;
}

เมื่อคุณมีคลาสเหล่านั้นแล้วคุณสามารถใช้องค์ประกอบการป้อนข้อมูลของคุณเป็น

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

โดยไม่มีข้อผิดพลาดในการคอมไพล์ ในความเป็นจริงคุณยังสามารถใช้สองอินเทอร์เฟซแรกด้านบนสำหรับส่วนประกอบอื่น ๆ ของคุณได้


ประเภทค่าไม่ใช่สตริง!
Roger Gusmao

7

โชคดีที่ฉันพบวิธีแก้ปัญหา คุณสามารถ

นำเข้า {ChangeEvent} จาก 'react';

จากนั้นเขียนโค้ดเช่น: e:ChangeEvent<HTMLInputElement>


2

นี่คือวิธีการทำลายโครงสร้างวัตถุ ES6 ทดสอบด้วย TS 3.3
ตัวอย่างนี้ใช้สำหรับการป้อนข้อความ

name: string = '';

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

1

นี่คือตอนที่คุณกำลังทำงานกับFileListObject:

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
  }

และให้แน่ใจว่าคุณมี"lib": ["dom"]ในtsconfigไฟล์.


1

เมื่อใช้ Child Component เราตรวจสอบประเภทนี้

องค์ประกอบหลัก:

export default () => {

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

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

ส่วนประกอบของเด็ก:

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

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

0

อีกทางเลือกหนึ่งที่ยังไม่ได้กล่าวถึงคือพิมพ์ฟังก์ชัน onChange แทนอุปกรณ์ประกอบฉากที่ได้รับ ใช้ React.ChangeEventHandler:

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

-1

ขอบคุณ@haind

ใช่HTMLInputElementใช้ได้กับช่องป้อนข้อมูล

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

นี้HTMLInputElementเป็นอินเตอร์เฟซที่มีการสืบทอดมาจากHTMLElementที่จะรับมาจากEventTargetที่ระดับราก ดังนั้นเราจึงสามารถใช้ยืนยันasผู้ประกอบการที่จะใช้อินเตอร์เฟซที่เฉพาะเจาะจงตามบริบทเช่นในกรณีนี้เราจะใช้HTMLInputElementสำหรับช่องใส่เชื่อมต่ออื่น ๆ สามารถHTMLButtonElement, HTMLImageElementฯลฯ

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

สำหรับข้อมูลอ้างอิงเพิ่มเติมคุณสามารถตรวจสอบอินเทอร์เฟซอื่น ๆ ที่มีได้ที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.