React Native Paper v4中forwardRef扩展复合组件的TypeScript问题
解决React Native Paper v4中TypeScript结合forwardRef扩展带Icon的TextInput问题
完整正确实现代码
import React, { forwardRef, useTheme } from 'react'; import { View, Text, StyleProp, ViewStyle, TextInput as RNTextInput } from 'react-native'; import { TextInput as RNPInput, TextInputProps, TextInputIconProps } from 'react-native-paper'; // 自定义组件Props:继承RN Paper TextInputProps,移除必填的theme,新增自定义label和容器style type InputComponentProps = Omit<TextInputProps, 'theme'> & { label?: string; style?: StyleProp<ViewStyle>; }; // 正确配置forwardRef泛型:第一个参数是RN原生TextInput实例(RN Paper的TextInput ref指向原生组件),第二个是自定义Props const InputComponent = forwardRef<RNTextInput, InputComponentProps>( ({ label, style, ...rest }, ref) => { const theme = useTheme(); return ( <View style={style}> {label && <Text>{label}</Text>} <RNPInput mode="outlined" outlineColor={theme.colors.backdrop} selectionColor={theme.colors.accent} ref={ref} theme={{ colors: { text: '#000' } }} // 替换为你的实际文本颜色配置 {...rest} /> </View> ); } ); // 定义复合组件类型:将基础输入组件与Icon组件类型合并 type TextInputComponent = typeof InputComponent & { Icon: typeof RNPInput.Icon; }; // 赋值并断言类型,确保TypeScript识别复合组件结构 const TextInput = InputComponent as TextInputComponent; TextInput.Icon = RNPInput.Icon; export { TextInput };
使用示例
const Test = () => { return <TextInput right={<TextInput.Icon name="eye" />} label="测试输入框" />; };
逐个问题解决说明
1. 复合组件Icon的name prop无法被TypeScript识别
直接用Object.assign挂载Icon时,TypeScript无法自动推断复合组件的完整类型。通过显式定义TextInputComponent类型,将基础组件类型与Icon组件类型合并,再将基础组件断言为该类型,就能让TypeScript正确识别TextInput.Icon的所有Props。
2. 移除// @ts-ignore后的ref类型错误
之前错误地将typeof RNPInput作为forwardRef的第一个泛型参数,但该参数需要的是组件实例类型,而非组件本身的类型。RN Paper的TextInput组件的ref指向原生React Native的TextInput实例,因此将泛型第一个参数改为RNTextInput(从react-native导入的TextInput),就能让ref类型完全匹配,无需忽略类型检查。
3. 移除Omit<TextInputProps, 'theme'>后提示theme必填
RN Paper的TextInputProps中theme是必填项,但你的组件内部已经通过useTheme自定义了theme配置,不需要外部传入。保留Omit<TextInputProps, 'theme'>可以从Props中移除该必填项,避免外部使用时的类型报错。
自定义Icon组件的正确写法
如果需要封装自定义Icon(比如默认设置颜色),只需保证类型继承RN Paper的TextInputIconProps即可:
const CustomIcon = (props: TextInputIconProps) => { return <RNPInput.Icon color="green" {...props} />; }; // 调整复合组件类型为自定义Icon的类型 type TextInputComponent = typeof InputComponent & { Icon: typeof CustomIcon; }; const TextInput = InputComponent as TextInputComponent; TextInput.Icon = CustomIcon;
内容的提问来源于stack exchange,提问作者Phil Lucks
相关产品推荐
相关产品推荐

