Какой правильный тип использовать для этой ловушки поля формы React? - PullRequest
1 голос
/ 29 апреля 2019

У меня есть обработчик React (с использованием машинописи), но я могу заставить его работать, только если я использую any для типа начального значения.

Я пробовал комбинации HTMLInputElement, React.FormEvent (даже React.FormEvent<HTMLInputElement>), а также использовал input type="text", чтобы попытаться ограничить входные элементы type: string.

Это крюк:

import { useCallback, useState } from "react";

export default function useField(initialValue: any) {
  const [value, setValue] = useState(initialValue);

  const handleUpdate = useCallback(
    ({ currentTarget: { type, checked, value } }) => {
      setValue(type === "checkbox" ? checked : value);
    },
    []
  );

  return [value, handleUpdate];
}

И вот где он используется:

import useField from "./hooks/useField";

const App = () => {
  const [firstName, setFirstName] = useField("");
  const [lastName, setLastName] = useField("");
  const [age, setAge] = useField("");

  return (
    <div className="App">
      <form>
        <input value={firstName} name="firstName" onChange={setFirstName} />
        <input value={lastName} name="lastName" onChange={setLastName} />
        <input value={age} name="age" onChange={setAge} />
      </form>
    </div>
  );
};

export default App;

Это на самом деле работает, как есть, используя initialValue: any, но я чувствую, что тип должен быть более конкретным, чем это. Если я изменю его на более конкретный тип (например, строку), я получу следующие две ошибки.

(JSX attribute) React.InputHTMLAttributes<HTMLInputElement>.onChange?: ((event: React.ChangeEvent<HTMLInputElement>) => void) | undefined
Type 'string | (({ currentTarget: { type, checked, value } }: any) => void)' is not assignable to type '((event: ChangeEvent<HTMLInputElement>) => void) | undefined'.
  Type 'string' is not assignable to type '((event: ChangeEvent<HTMLInputElement>) => void) | undefined'.ts(2322)
index.d.ts(1977, 9): The expected type comes from property 'onChange' which is declared here on type 'DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>'

Второй находится на входном событии onChange:

(JSX attribute) React.InputHTMLAttributes<HTMLInputElement>.onChange?: ((event: React.ChangeEvent<HTMLInputElement>) => void) | undefined
Type 'string | (({ currentTarget: { type, checked, value } }: any) => void)' is not assignable to type '((event: ChangeEvent<HTMLInputElement>) => void) | undefined'.
  Type 'string' is not assignable to type '((event: ChangeEvent<HTMLInputElement>) => void) | undefined'.ts(2322)
index.d.ts(1977, 9): The expected type comes from property 'onChange' which is declared here on type 'DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>'

Сегодня мой первый день использования Typescript, так что это может быть что-то очень очевидное!

1 Ответ

1 голос
/ 29 апреля 2019

Если вы не укажете тип возвращаемого значения, TypeScript выведет его. Начну с простого примера:

function strNum() {
  return [1, 'a'];
}

Возвращает тип (string | number)[], то есть массив, который может содержать строковые или числовые элементы.

useField возвращает массив string | (event: ChangeEvent<HTMLInputElement>) => void. Это означает, что любой элемент массива может относиться к одному из этих типов, и они не совместимы друг с другом.

Вместо этого вы можете указать тип возвращаемого значения в виде кортежа. Это массив заданной длины с определенными типами элементов.

useField(initialValue: string): [string, (event: React.ChangeEvent<HTMLInputElement>) => void] {
...