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

如何在React Native+TypeScript中定义带组件属性的函数组件?

在React Native TypeScript中实现带Animated复合组件的CharText组件

已知在TypeScript中可以通过定义包含函数签名和属性的类型,给函数添加额外属性,示例如下:

// 定义函数类型,包含函数签名和usedBy属性
type VerifyAgeFunc = {
  (age: number): boolean;
  usedBy: string;
};

// 实现函数并断言类型
let verifyAge = <VerifyAgeFunc>((age: number) => age > 18);

// 添加属性
verifyAge.usedBy = "Admin";

但在React Native的JSX环境中,要实现类似逻辑:定义CharText组件,并为其添加CharText.Animated复合组件(类似官方组件的复合写法),之前的两种尝试都存在问题:

第一种尝试:直接类型断言与JSX冲突

interface CharTextFunc {
  (props: CharTextProps): ReactNode;
  Animated: (props: CharTextProps) => ReactNode;
}

const CharText = <CharTextFunc,>({ mapStyle, style, children, ...restProps }: CharTextProps) => (
  <View style={styles.container} {...restProps}>
    {[...children].map((chr, index) => (
      <Text key={`${chr}-${index}`} style={[styles.char, style, mapStyle && mapStyle(index, chr)]}>
        {chr}
      </Text>
    ))}
  </View>
);

问题:为区分JSX语法添加逗号后仍无法生效,且CharTextFunc出现“已定义但未使用”的警告,类型断言与JSX语法直接冲突。

第二种尝试:高阶组件方案属性可选

interface CharTextFunc {
  (props: CharTextProps): ReactNode;
  Animated?: (props: CharTextProps) => ReactNode;
}

type TextComponent = typeof Animated.Text | typeof Text;

const makeCharText = (Text: TextComponent): CharTextFunc => {
  return ({ mapStyle, style, children, ...restProps }: CharTextProps) => (
    <View style={styles.container} {...restProps}>
      {[...children].map((chr, index) => (
        <Text key={`${chr}-${index}`} style={[styles.char, style, mapStyle && mapStyle(index, chr)]}>
          {chr}
        </Text>
      ))}
    </View>
  );
};

const CharText = makeCharText(Text);
CharText.Animated = makeCharText(Animated.Text);

问题:Animated属性设为可选时,调用CharText.Animated会触发类型警告;设为必填则回到类型断言与JSX冲突的问题。


正确实现方案

1. 定义Props和组件类型

import React, { ReactNode } from 'react';
import { View, Text, Animated, StyleSheet } from 'react-native';

// 定义CharText的Props类型
interface CharTextProps {
  mapStyle?: (index: number, char: string) => object;
  style?: object;
  children: string;
  [key: string]: any; // 支持View组件的其他属性
}

// 定义CharText组件的完整类型:既是函数组件,又包含必填的Animated复合组件
type CharTextComponent = ((props: CharTextProps) => ReactNode) & {
  Animated: (props: CharTextProps) => ReactNode;
};

2. 分别实现基础组件和Animated组件

// 基础CharText组件实现
const CharTextBase = ({ mapStyle, style, children, ...restProps }: CharTextProps) => (
  <View style={styles.container} {...restProps}>
    {[...children].map((chr, index) => (
      <Text
        key={`${chr}-${index}`}
        style={[styles.char, style, mapStyle && mapStyle(index, chr)]}
      >
        {chr}
      </Text>
    ))}
  </View>
);

// Animated版本的CharText组件
const CharTextAnimated = ({ mapStyle, style, children, ...restProps }: CharTextProps) => (
  <View style={styles.container} {...restProps}>
    {[...children].map((chr, index) => (
      <Animated.Text
        key={`${chr}-${index}`}
        style={[styles.char, style, mapStyle && mapStyle(index, chr)]}
      >
        {chr}
      </Animated.Text>
    ))}
  </View>
);

3. 组合组件并添加复合属性

// 将基础组件断言为CharTextComponent类型,允许添加Animated属性
const CharText = CharTextBase as CharTextComponent;
// 挂载Animated组件到基础组件上
CharText.Animated = CharTextAnimated;

// 基础样式定义
const styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    flexWrap: 'wrap',
  },
  char: {
    marginHorizontal: 2,
    // 可添加其他基础字符样式
  },
});

export default CharText;

4. 使用方式

// 使用基础CharText组件
<CharText style={{ fontSize: 24, color: '#333' }}>Hello World</CharText>

// 使用Animated版本
const animatedStyle = useAnimatedStyle(() => ({
  opacity: 1,
  transform: [{ translateY: 0 }],
}));

<CharText.Animated style={animatedStyle}>Hello Animated</CharText>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 08:53:10