Cómo (propiamente) escribir un formulario con tipografía (y no bibliotecas externas)

Estoy tratando de crear una forma sencilla y estoy luchando para decirle a Typescript qué valores me gustaría tener mis entradas. Hasta ahora lo que he visto al buscar una respuesta son un montón de bibliotecas y hooks hechos a medida que manejan todo bajo la capucha, pero nada que lo haría sin la ayuda de bibliotecas externas. Espero que alguien por aquí tenga una sugerencia.

Quiero tener un formulario básico de austeridad donde estoy recibiendo el nombre de usuario, correo electrónico y contraseña de los usuarios. Como necesito decirle a Typescript que estoy esperando desde el onChange callback sólo un cierto conjunto de llaves, he extendido HTMLInputElement en mi tipo personalizado. Sin embargo esto parece no ser un enfoque correcto, ya que entonces no soy capaz de proporcionar mi onChange manipulador a los respectivos input de la forma. ¿Alguien sabe cómo Tipo apropiado (sin as <> as unknown as <> o bibliotecas específicas) una forma de este tipo? ¡Gracias!

Mi código:


interface ISignUpState {
    username: string;
    email: string;
    passwordOne: string;
    passwordTwo: string;
    error: string;
}

interface InputProps extends InputHTMLAttributes {
    name: keyof ISignUpState;
    value: ISignUpState[InputProps["name"]]
}

const INITIAL_STATE: ISignUpState = {
    username: '',
    email: '',
    passwordOne: '',
    passwordTwo: '',
    error: ''
}

export const SignUpForm = () => {

    const [state, setState] = React.useState(INITIAL_STATE);

    const onSubmit = (event: React.FormEvent) => {

    }

    const onChange = (event:React.ChangeEvent) => {
        setState(prevState => ({...prevState, [event.target.name]: event.target.value}))
    }

    const {username, email, passwordOne, passwordTwo, error} = state;

    return (
        
) }

Y Typescript se queja de onChange:

Type '(event: React.ChangeEvent) => void' is not assignable to type '(event: ChangeEvent) => void'.
  Types of parameters 'event' and 'event' are incompatible.
    Type 'ChangeEvent' is not assignable to type 'ChangeEvent'.
      Type 'HTMLInputElement' is not assignable to type 'InputProps'.
        Types of property 'name' are incompatible.
          Type 'string' is not assignable to type '"username" | "email" | "passwordOne" | "passwordTwo" | "error"'.

Pregunta hecha hace 3 años, 4 meses, 27 días - Por binaryblossom


3 Respuestas:

  • TipoScript no integra el tipo de name prop en el valor a event.target.name - todo lo que se puede decir es que tal valor es un string, que no se puede utilizar donde una clave ISignUpState se espera (que es más estrecho). Así que... React.ChangeEvent no es usable - tendrá que usar ChangeEvent, como TS dice que es necesario.

    const onChange = (event: React.ChangeEvent) => {
        setState(prevState => ({ ...prevState, [event.target.name]: event.target.value }));
    };
    

    Podrías pensar que el event.target.name allí, escrito como una String, es raro, ya que no se escribe como una llave ISignUpState - pero TypeScript lo acepta.

    Si TipoScript no aceptarlo, usted podría utilizar un tipo de aserción o estrechar el tipo antes de combinar el objeto (quizá inicie un error si el estrechamiento de tipo falla) - pero no es necesario.

    Respondida el Dec 18, 2020 a las 19:39 - por stackscripter

    Votos positivos: 0 | Votos negativos: 0

  • El problema que estás experimentando es debido a que estás definiendo mal la interfaz InputProps al extender InputHTMLAttributes<htmlinputelement>. Para corregirlo, puedes definir InputProps de la siguiente manera:

    typescript
    interface InputProps {
        name: keyof ISignUpState;
        value: ISignUpState[keyof ISignUpState];
        onChange: (event: React.ChangeEvent) => void;
    }
    

    Luego, puedes modificar tu función onChange para que cumpla con la firma correcta del evento:

    typescript
    const onChange = (event: React.ChangeEvent) => {
        setState(prevState => ({...prevState, [event.target.name]: event.target.value}))
    }
    

    Y finalmente, puedes asignar correctamente el onChange a tu input en el formulario:

    typescript
    return (
        
    )

    Con estas correcciones, el error que estás experimentando debe resolverse y tu formulario debería funcionar correctamente sin necesidad de bibliotecas externas.

    Respondida el Dec 19, 2020 a las 19:41 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • El problema con tu código es que intentas extender la interfaz HTMLInputElement con tu interfaz personalizada InputProps. Esto no es posible porque HTMLInputElement es una interfaz nativa de JavaScript y no se puede extender con interfaces personalizadas.

    Para solucionar este problema, puedes crear una interfaz personalizada que extienda ChangeEvent<HTMLInputElement> y agregue las propiedades adicionales que necesitas:

    typescript
    interface InputChangeEvent extends ChangeEvent {
      target: InputProps;
    }
    

    Luego, puedes usar esta interfaz personalizada para escribir tu función onChange:

    typescript
    const onChange = (event: InputChangeEvent) => {
      setState(prevState => ({...prevState, [event.target.name]: event.target.value}))
    }
    

    Esto le dirá a TypeScript que la función onChange espera un evento que tenga un objetivo que sea una instancia de la interfaz InputProps. Esto asegurará que solo se pasen eventos válidos a la función onChange.

    Además, en tu código HTML, debes usar la interfaz InputProps para escribir las propiedades de los elementos de entrada:

    html
    
    

    Esto le dirá a TypeScript que los elementos de entrada tienen propiedades que coinciden con la interfaz InputProps.

    Una vez que hayas realizado estos cambios, TypeScript ya no debería quejarse de los tipos de la función onChange.

    Respondida el Dec 19, 2020 a las 19:42 - por Gemini

    Votos positivos: 0 | Votos negativos: 0