Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Typing Components and Props in React Native with TypeScript

Typing Components and Props

~14 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

Now we'll migrate ProductCard – EXACTLY as in "React for Professionals" chapter 41, just with React Native's own event types instead of web DOM event types.

ProductCard.js to ProductCard.tsx

components/ProductCard.tsx
import { memo } from 'react';
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
import { Image } from 'expo-image';
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withSpring,
} from 'react-native-reanimated';

const BLURHASH = '|rF?hV%2WCj[ayj[a|j[az_NaeWBj@ayfRayfQfQM{M|azj[azf6fQfQfQIpWXofj[ayj[j[fQayWCoeoeaya}j[ayfQa{oLj?j[WVj[ayayj[fQoff7azayj[ayj[j[ayofayayayj[fQj[ayayj[ayfjj[j[ayjuayj[';

interface ProductCardProps {
  name: string;
  price: number;
  imageUrl: string;
  onPress: () => void;
  isFavorite: boolean;
  onToggleFavorite: () => void;
}

function ProductCard({
  name,
  price,
  imageUrl,
  onPress,
  isFavorite,
  onToggleFavorite,
}: ProductCardProps) {
  const scale = useSharedValue(1);

  const heartStyle = useAnimatedStyle(() => ({
    transform: [{ scale: scale.value }],
  }));

  function handleToggleFavorite() {
    scale.value = withSpring(1.4, { damping: 4 }, () => {
      scale.value = withSpring(1);
    });
    onToggleFavorite();
  }

  return (
    <TouchableOpacity style={styles.card} onPress={onPress}>
      <Image
        source={imageUrl}
        style={styles.image}
        placeholder={{ blurhash: BLURHASH }}
        contentFit="cover"
        transition={200}
        cachePolicy="memory-disk"
      />
      <View style={styles.info}>
        <Text style={styles.name}>{name}</Text>
        <Text style={styles.price}>${price.toFixed(2)}</Text>
      </View>
      <TouchableOpacity style={styles.favoriteButton} onPress={handleToggleFavorite}>
        <Animated.Text style={[styles.favoriteIcon, heartStyle]}>
          {isFavorite ? '♥' : '♡'}
        </Animated.Text>
      </TouchableOpacity>
    </TouchableOpacity>
  );
}

const styles = StyleSheet.create({
  card: {
    flexDirection: 'row',
    padding: 12,
    marginBottom: 8,
    backgroundColor: '#f9fafb',
    borderRadius: 8,
    alignItems: 'center',
  },
  image: { width: 60, height: 60, borderRadius: 4 },
  info: { marginLeft: 12, flex: 1 },
  name: { fontSize: 16, fontWeight: '600' },
  price: { fontSize: 14, color: '#6b7280' },
  favoriteButton: { padding: 8 },
  favoriteIcon: { fontSize: 20, color: '#ef4444' },
});

export default memo(ProductCard);

Bonus: StyleSheet.create is already typed automatically

A pleasant difference from React web: StyleSheet.create({{...}}) is GENERICALLY typed – if you accidentally type an invalid style name (e.g. colr instead of color), TypeScript reports the error IMMEDIATELY, without you having to define a style type yourself. These types come directly from @types/react-native, which Expo installs automatically.

Passing style objects through as props

For components that expose their own style prop to the outside (e.g. a future, more configurable version of ProductCard), there's a matching React Native type:

import { StyleProp, ViewStyle } from 'react-native';

interface CardProps {
  style?: StyleProp<ViewStyle>;
}

StyleProp<ViewStyle> covers ALL valid shapes React Native accepts for styles: a single style object, an array of styles (as we use with [styles.favoriteIcon, heartStyle] in the example above), or false/null/undefined (for conditional styles like condition && styles.active).

children and generic touchable props

import { ReactNode } from 'react';
import { TouchableOpacityProps } from 'react-native';

// ReactNode works identically to "React for Professionals" chapter 41 (web):
interface WrapperProps {
  children: ReactNode;
}

// Handy for inheriting ALL standard props of a native component,
// plus your own additions - saves listing every standard prop individually:
interface CustomButtonProps extends TouchableOpacityProps {
  label: string;
}

extends TouchableOpacityProps is a React Native-specific pattern with no direct equivalent in "React for Professionals": it automatically inherits ALL of TouchableOpacity's standard props (onPress, disabled, style, activeOpacity, ...), so your own wrapper component doesn't have to redeclare them individually.

Tipp: Rule of thumb for your own, reusable RN components: extends <NativeComponent>Props is almost ALWAYS a better starting point than a props interface written entirely from scratch – you automatically inherit all the standard functionality and only need to add the TRULY new, custom props.