【问题标题】:Typescript: React event types打字稿:反应事件类型
【发布时间】:2017-06-24 04:58:28
【问题描述】:

什么是 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&lt;EventTarget&gt; 似乎无法正常工作,因为我收到一个错误:namevaluetarget 上不存在。

非常感谢所有事件的更通用的答案。

谢谢

【问题讨论】:

    标签: javascript reactjs typescript


    【解决方案1】:

    问题不在于 Event 类型,而在于 typescript 中的 EventTarget 接口只有 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;
    }
    

    所以 namevalue 在 EventTarget 上不存在是正确的。您需要做的是将目标转换为具有您需要的属性的特定元素类型。在这种情况下,它将是HTMLInputElement

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

    对于事件而不是 React.SyntheticEvent,您还可以键入如下:EventMouseEventKeyboardEvent...等,具体取决于处理程序的用例。

    查看所有这些类型定义的最佳方法是从 typescript 和 react 中检出 .d.ts 文件。

    还可以查看以下链接以获取更多说明: Why is Event.target not Element in Typescript?

    【讨论】:

    • ps。看起来我的类型定义文件有点过时,因为它没有显示通用 SyntheticEvent 接口。 Nitzan Tomer 的答案更好。
    【解决方案2】:

    SyntheticEvent 接口是通用的:

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

    (从技术上讲,currentTarget 属性位于父 BaseSyntheticEvent 类型上。)

    currentTarget 是通用约束和EventTarget 的交集。
    此外,由于您的事件是由输入元素引起的,您应该使用ChangeEventin definition filethe react docs)。

    应该是:

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

    (注:这个答案最初建议使用React.FormEvent。cmets中的讨论与此建议有关,但如上所示应使用React.ChangeEvent。)

    【讨论】:

    • 阅读所有常见事件类型的好地方是什么?找不到任何地方。
    • React 事件类型?它们都在events page in the docs 中进行了描述。
    • 我得到 'name' 在类型 'EventTarget & HTMLInputElements' 上不存在 (TS v2.4)
    • 这仍然给我以下错误。 “类型‘EventTarget & HTMLInputElement’上不存在属性‘值’。”
    • @CMCDragonkai 我认为e.key 只是键盘事件的一部分。
    【解决方案3】:

    结合 Nitzan 和 Edwin 的答案,我发现这样的事情对我有用:

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

    【讨论】:

    • this.props.login[target.name] = target.value; ???你在换道具吗:o
    • 只是从原始问题中复制该行,以便答案对 OP 有意义。
    【解决方案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();
    }
    

    【讨论】:

      【解决方案5】:

      你可以在反应中这样做

      handleEvent = (e: React.SyntheticEvent<EventTarget>) => {
        const simpleInput = (e.target as HTMLInputElement).value;
        //for simple html input values
        const formInput = (e.target as HTMLFormElement).files[0];
        //for html form elements
      }
      

      【讨论】:

      • 你的例子和handleEvent有什么区别:React.ReactEventHandler = (e) => { ... }
      【解决方案6】:

      对于那些正在寻找解决方案来获取事件和存储内容的人,在我的例子中是 HTML 5 元素,useState 这是我的解决方案:

      const [anchorElement, setAnchorElement] = useState<HTMLButtonElement | null>(null);
      
      const handleMenu = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) : void => {
          setAnchorElement(event.currentTarget);
      };
      

      【讨论】:

        【解决方案7】:

        我在 types.ts 文件中有以下内容,用于 html 输入、选择和文本区域:

        export type InputChangeEventHandler = React.ChangeEventHandler<HTMLInputElement>
        export type TextareaChangeEventHandler = React.ChangeEventHandler<HTMLTextAreaElement>
        export type SelectChangeEventHandler = React.ChangeEventHandler<HTMLSelectElement>
        

        然后导入它们:

        import { InputChangeEventHandler } from '../types'
        

        然后使用它们:

        
        const updateName: InputChangeEventHandler = (event) => {
          // Do something with `event.currentTarget.value`
        }
        const updateBio: TextareaChangeEventHandler = (event) => {
          // Do something with `event.currentTarget.value`
        }
        const updateSize: SelectChangeEventHandler = (event) => {
          // Do something with `event.currentTarget.value`
        }
        

        然后在您的标记上应用函数(将... 替换为其他必要的道具):

        <input onChange={updateName} ... />
        <textarea onChange={updateName} ... />
        <select onChange={updateSize} ... >
          // ...
        </select>
        

        【讨论】:

        • 我想这取决于你想做什么(这很令人困惑),但对我来说,我必须将其更改为 export type InputChangeEventHandler = React.ChangeEvent&lt;HTMLInputElement&gt;; 才能使用 event.target.value。使用ChangeEventHandler 不允许使用event.target,因为它是未定义的。
        【解决方案8】:

        更新:event: React.ChangeEvent 提交:event: React.FormEvent 点击:event: React.MouseEvent

        【讨论】:

        • 我的 ts-react starter 编译器在我省略事件类型时没有报错,编译器的这种行为正常吗?谢谢。
        猜你喜欢
        • 1970-01-01
        • 2021-12-24
        • 2018-03-27
        • 2021-08-05
        • 2019-12-19
        • 2019-06-20
        • 2021-06-14
        • 1970-01-01
        • 2018-10-26
        相关资源
        最近更新 更多