You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native + TypeScript登录功能中useReducer的TypeScript报错求助

Fixing TypeScript Errors in Your React Native Input Component's useReducer

Hey there! I see you're stuck with TypeScript errors in your useReducer implementation for the login input component—let's work through this together. The main issue here is overusing any; TypeScript can't properly validate your code when everything is typed as any, which leads to those confusing errors. Let's refactor your code with proper type definitions to fix this.

Step 1: Define Clear Types for State and Actions

First, let's create explicit types for your reducer's state and actions instead of relying on any:

// Shape of the input state managed by the reducer
type InputState = {
  value: string;
  isValid: boolean;
  touched: boolean;
};

// All possible actions the reducer can handle
type InputAction = 
  | { type: 'INPUT_CHANGE'; value: string; isValid: boolean }
  | { type: 'INPUT_BLUR' };

Step 2: Fix the Reducer Function

Update your reducer to use these defined types—no more any here:

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

Step 3: Correct the Component Props Type

Your original InputComponentProps was incorrectly structured—let's replace it with the actual props your component needs:

interface InputComponentProps {
  label: string;
  required?: boolean;
  email?: boolean;
  minLength?: number;
  errorText: string;
  id: string;
  onInputChange: (id: string, value: string, isValid: boolean) => void;
  // Catch-all for extra TextInput props you might spread (like placeholder, keyboardType)
  [key: string]: any;
}

Step 4: Update the Component and useReducer Hook

Now adjust the component to use the new types, and fix the overly complex parameter type in handleChangeText (it's just a string!):

const InputComponent: React.FC<InputComponentProps> = (props) => {
  const [inputState, inputDispatch] = useReducer(
    inputReducer,
    {
      value: '',
      isValid: false,
      touched: false,
    } as InputState // Explicitly type the initial state
  );

  const { onInputChange, id } = props;

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

  const handleChangeText = (text: string) => {
    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 });
  };

  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>
  );
};

Key Fixes Explained

  • Removed unnecessary any types: By defining explicit types for state, actions, and props, TypeScript can now validate your code correctly and catch issues early.
  • Fixed the props interface: The original props had unrelated constants—we replaced it with the actual props your component uses.
  • Simplified handleChangeText: The input from onChangeText is always a string, so we set the parameter type to string instead of that overly complex (and incorrect) type you had.
  • Explicit initial state typing: We added as InputState to the initial state to ensure TypeScript recognizes its shape.

Full Refactored Code

Here's the complete, type-safe version of your component:

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

type InputState = {
  value: string;
  isValid: boolean;
  touched: boolean;
};

type InputAction = 
  | { type: 'INPUT_CHANGE'; value: string; isValid: boolean }
  | { type: 'INPUT_BLUR' };

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

interface InputComponentProps {
  label: string;
  required?: boolean;
  email?: boolean;
  minLength?: number;
  errorText: string;
  id: string;
  onInputChange: (id: string, value: string, isValid: boolean) => void;
  [key: string]: any;
}

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

  const { onInputChange, id } = props;

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

  const handleChangeText = (text: string) => {
    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 });
  };

  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 should resolve those TypeScript errors and make your component type-safe. As you get more comfortable with TypeScript, try to avoid any whenever possible—clear types save you time in the long run by catching bugs early!

内容的提问来源于stack exchange,提问作者Joaquin Palacios

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 13:37:32