Search code examples
reactjstypescriptreact-nativereact-typescriptuse-reducer

React Typescript errors on useReducer login


I am doing a proyect on React Native and Typescript, I am new on them and I had been having an issue lately that I couldn't solve yet. I am trying to do a login on the app and Typescript keeps giving me errors on a useReducer I did. Unfortunately, i am new with Typescript so in order to solve previous errors I just put any on most of the types. This is the code, it is the input from the login screen:

import React, { useEffect, useReducer } from "react";
import { StyleSheet, Text, TextInput, View } from "react-native";

interface InputComponentProps {
    INPUT_CHANGE: any
    INPUT_BLUR: any
    handleBlur: any
}
const INPUT_CHANGE: any = 'INPUT_CHANGE';
const INPUT_BLUR: any = 'INPUT_BLUR';


const inputReducer: any = (state: any, action: any) => {
    switch(action.type) {
      case INPUT_CHANGE:
        return {
          ...state,
          value: action.value,
          isValid: action.isValid,
        };
      case INPUT_BLUR:
        return {
          ...state,
          touched: true,
        };
      default:
        return state;
    }
};

const InputComponent: React.FC<InputComponentProps> = (props: any) => {
    const [inputState, inputDispatch] = useReducer<any>(inputReducer, {
        value: '',
        isValid: false,
        touched: false,
    });

    const { onInputChange, id } = props;

    useEffect((): (() => void) => {
        return onInputChange(id, inputState.value, inputState.isValid);
    }, [onInputChange, id, inputState])

    const handleChangeText = (text: { trim: () => { (): any; new(): any; length: number; }; toLowerCase: () => string; length: number; }) => {
      const emailRegex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
      let isValid = true;

      if (props.required && text.trim().length === 0) isValid = false;
      if (props.email && !emailRegex.test(text.toLowerCase())) isValid = false;
      if (props.minLength && text.length < props.minLength) isValid = false;

      inputDispatch({
        type: INPUT_CHANGE,
        value: text,
        isValid: isValid,
      });
    }    

    const handleBlur = () => inputDispatch({ type: INPUT_BLUR });

    return (
        <>
            <View style={styles.formControl}>
                <Text style={styles.label}>{props.label}</Text>
                <TextInput
                  {...props}
                  style={styles.input}
                  value={inputState.value}
                  onChangeText={handleChangeText}
                  onBlur={handleBlur}
                />
                {!inputState.isValid && inputState.touched && (
                  <View>
                      <Text style={styles.errorText}>{props.errorText}</Text>
                  </View>
                )}
            </View>
        </>
    );
}    
const styles = StyleSheet.create({
    formControl: {
      width: '100%',
    },
    label: {
      fontFamily: 'OpenSansBold',
      marginVertical: 8,
    },
    input: {
      paddingHorizontal: 2,
      paddingVertical: 5,
      borderBottomColor: '#ccc',
      borderBottomWidth: 1,
    },
    errorText: {
      marginVertical: 5,
      color: '#cc7755'
    }
});     
export default InputComponent;

This is a screenshot of the errors: enter image description here

enter image description here

If there is someone that could help me, I would really appreciate it!


Solution

  • You have a few too many explicit anys where you would be better off letting TypeScript infer the type. Specifically, the ones which are causing you trouble are these two:

    const inputReducer: any = (
    
    useReducer<any>(
    

    A reducer must be a function that takes a state and an action and returns the next state. By putting any in these two places, you are telling TypeScript that your reducer is anything and is not necessarily a function.

    But it is a function. If you drop those two anys, then the type which is inferred as the value of inputReducer and the generic on useReducer is (state: any, action: any) => any. This is much more descriptive than just any. We know that it's a function and that it takes the correct amount of arguments.


    When you add vague types where they aren't needed, you are making your code much less type-safe then with no type annotations at all. When you do this:

    const INPUT_CHANGE: any = 'INPUT_CHANGE';
    

    You are overriding all of TypeScript's power to infer the correct type. There is no need to put a type when you are assigning a variable because TypeScript will infer that the type of the variable is the same as the type of the value that you assigned.

    const INPUT_CHANGE = 'INPUT_CHANGE';
    

    Here, the type of the INPUT_CHANGE variable is the literal string "INPUT_CHANGE" instead of any.