【问题标题】:React Hooks TypeScript event and state typesReact Hooks TypeScript 事件和状态类型
【发布时间】:2020-05-25 00:31:48
【问题描述】:

React.js 的状态和事件有哪些类型?

在下面的代码中,我只能通过使用type: any 使其工作,但这只是一个 hack。我怎样才能为他们使用正确的类型?

在我的自定义钩子中:

如果我使用function useFormFields(initialState: object),我会得到:

// value={inputs.item} error:
Property 'item' does not exist on type 'object'.ts(2339)
// onChange function error:
(JSX attribute) onChange: object
No overload matches this call.

如果我使用function(event: React.FormEvent)(这是真的),我有这个错误:

Property 'id' does not exist on type 'EventTarget'.ts(2339)

如果我使用function(event: object),我有这个错误:

Property 'target' does not exist on type 'object'.ts(2339)

这很奇怪,因为下面我使用 const handleSubmitItem = (event: React.FormEvent) 并且它有效。

我找到的答案(如this one)对我不起作用,因为Property 'id' does not exist on type 'EventTarget'

import React, {useState} from 'react';
import TextField from '@material-ui/core/TextField';
import IconButton from '@material-ui/core/IconButton';
import AddShoppingCartIcon from '@material-ui/icons/AddShoppingCart';

/**
 * Custom hooks for input fields.
 * @param initialState initialState for Input Fields
 */
function useFormFields(initialState: any) {
    const [inputs, setValues] = useState(initialState);

    return [
        inputs,
        function(event: any) {
            setValues({
                ...inputs,
                [event.target.id]: event.target.value
            });
        }
    ];
}

export default function FormPropsTextFields() {
    const [inputs, handleInputChange] = useFormFields({
        item: '',
        quantity: '',
        store: ''
    });

    const handleSubmitItem = (event: React.FormEvent) => {
        event.preventDefault();
        console.log(inputs);
    };

    return (
        <form 
            className={classes.root} 
            noValidate autoComplete="off"
            onSubmit={handleSubmitItem}
        >
            <div>
                <TextField 
                    required id="item" 
                    label="Item" 
                    value={inputs.item}
                    onChange={handleInputChange}
                />
                <TextField
                    id="quantity"
                    label="Quantity"
                    type="number"
                    value={inputs.quantity}
                    onChange={handleInputChange}
                    InputLabelProps={{
                        shrink: true,
                    }}
                />
                <TextField 
                    id="store" 
                    label="Store" 
                    type="search"
                    value={inputs.store}
                    onChange={handleInputChange}
                />
                <IconButton 
                    type="submit"
                    color="primary" 
                    aria-label="add to shopping cart"
                >
                    <AddShoppingCartIcon />
                </IconButton>
            </div>
        </form>
    );
}

【问题讨论】:

    标签: javascript reactjs typescript


    【解决方案1】:

    我对您找到的解决方案进行了一些更正。 希望对您有所帮助!

    import React, {useState} from 'react';
    import TextField from '@material-ui/core/TextField';
    import IconButton from '@material-ui/core/IconButton';
    import AddShoppingCartIcon from '@material-ui/icons/AddShoppingCart';
    
    /**
     * Custom hooks for input fields.
     * @param initialState initialState for Input Fields
     */
    
    export interface MyModel {
        item: string
        quantity: string
        store: string
    }
    
    function useFormFields<T>(initialState: T): [T, (event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => void] {
        const [inputs, setValues] = useState<T>(initialState);
    
        return [
            inputs,
            function (event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) {
                setValues({
                    ...inputs,
                    [event.target.id]: event.target.value
                });
            }
        ];
    }
    
    export default function FormPropsTextFields() {
        const [inputs, handleInputChange] = useFormFields<MyModel>({
            item: '',
            quantity: '',
            store: ''
        });
    
        const handleSubmitItem = (event: React.FormEvent) => {
            event.preventDefault();
            console.log(inputs);
        };
    
        return (
            <form 
                className={classes.root} 
                noValidate autoComplete="off"
                onSubmit={handleSubmitItem}
            >
                <div>
                    <TextField 
                        required id="item" 
                        label="Item" 
                        value={inputs.item}
                        onChange={handleInputChange}
                    />
                    <TextField
                        id="quantity"
                        label="Quantity"
                        type="number"
                        value={inputs.quantity}
                        onChange={handleInputChange}
                        InputLabelProps={{
                            shrink: true,
                        }}
                    />
                    <TextField 
                        id="store" 
                        label="Store" 
                        type="search"
                        value={inputs.store}
                        onChange={handleInputChange}
                    />
                    <IconButton 
                        type="submit"
                        color="primary" 
                        aria-label="add to shopping cart"
                    >
                        <AddShoppingCartIcon />
                    </IconButton>
                </div>
            </form>
        );
    }
    

    【讨论】:

    • 谢谢@nightElf,让我试试然后回复你。
    【解决方案2】:

    由于每个组件可能不同,您需要自己定义 state 和 props 类型。为 react 定义了一些基本类型(例如,因为每个组件都可能有 children),但正如我所说,您需要定义自己的类型。

    功能组件的示例:

    const App: React.FC<{ message: string }> = ({ message }) => (
      <div>{message}</div>
    );
    

    上面的例子也可以这样写:

    type MyType = { message: string }
    const App: React.FC<MyType> = ({ message }) => (
      <div>{message}</div>
    );
    

    在此处进一步阅读:

    https://github.com/typescript-cheatsheets/react-typescript-cheatsheet#section-2-getting-started

    【讨论】:

    • 谢谢@messerbill,让我试试,然后回复你。
    【解决方案3】:

    将军们!答案!

    希望对你有帮助!

    
    import IconButton from '@material-ui/core/IconButton';
    import TextField from '@material-ui/core/TextField';
    import AddShoppingCartIcon from '@material-ui/icons/AddShoppingCart';
    import React, { useState } from 'react';
    
    export interface MyModel {
        item: string;
        quantity: string;
        store: string;
     }
    
    /**
     * Custom hooks for input fields.
     * @param initialState initialState for Input Fields
     **/
    function useFormFields<T>(initialState: T) {
        const [inputs, setValues] = useState(initialState);
    
        return [
            inputs,
            function(event: React.FormEvent) {
                const {name, value} = event.currentTarget;
                setValues({
                    ...inputs,
                    [name]: value
                });
            }
        ];
    }
    
    export default function FormPropsTextFields() {
        const [inputs, handleInputChange] = useFormFields<MyModel>({
            item: '',
            quantity: '',
            store: '',
        });
    
        const handleSubmitItem = (event: React.MouseEvent<HTMLButtonElement>) => {
            event.preventDefault();
            /***
               make sure to have whatever attribute you want in the "html tag"
            */
            const { name, value } = event.currentTarget;
            console.log(inputs);
        };
    
        return (
            <form
                className={classes.root}
                noValidate autoComplete="off"
            >
                <div>
                    <TextField
                        required id="item"
                        label="Item"
                        name="Item"
                        value={inputs.item}
                        onChange={handleInputChange}
                    />
                    <TextField
                        id="quantity"
                        label="Quantity"
                        name="Quantity"
                        type="number"
                        value={inputs.quantity}
                        onChange={handleInputChange}
                        InputLabelProps={{
                            shrink: true,
                        }}
                    />
                    <TextField
                        id="store"
                        label="Store"
                        name="Store"
                        type="search"
                        value={inputs.store}
                        onChange={handleInputChange}
                    />
                    <IconButton
                        type="button"
                        color="primary"
                        aria-label="add to shopping cart"
                        onClick={handleSubmitItem}
                    >
                        <AddShoppingCartIcon />
                    </IconButton>
                </div>
            </form>
        );
    }
    
    

    【讨论】:

    • 谢谢@Emesto,让我试试然后回复你。
    • 抱歉,差距过大。你的答案返回这些错误:property 'name' does not exist on type 'EventTarget &amp; Element'. 如果我保留[event.target.id]: event.target.value,它会返回:Property 'id' does not exist on type 'EventTarget'.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-12
    • 1970-01-01
    • 2017-11-28
    • 2023-03-24
    • 2019-11-08
    • 2019-07-08
    • 2016-11-15
    相关资源
    最近更新 更多