Expensify TypeScript React Native CheatSheet
December 19, 2025 ยท View on GitHub
Table of Contents
CheatSheet
-
1.1
props.childrenimport type ChildrenProps from '@src/types/utils/ChildrenProps'; type WrapperComponentProps = ChildrenProps & { ... }; function WrapperComponent({ children }: WrapperComponentProps) { return <View>{children}</View>; } function App() { return ( <WrapperComponent> <View /> </WrapperComponent> ); }
-
1.2 Refs as Props
In React 19,
forwardRefis deprecated and no longer necessary. Simply passrefas a prop instead.// CustomTextInput.tsx import type { Ref, ReactNode } from "react"; import { TextInput, View } from "react-native"; export type CustomTextInputProps = { label: string; children?: ReactNode; ref?: Ref<TextInput>; // Note: prop must be named "ref" explicitly }; function CustomTextInput({ ref, ...props }: CustomTextInputProps) { return ( <View> <TextInput ref={ref} /> {props.children} </View> ); }; export default CustomTextInput; // ParentComponent.tsx import { useRef } from "react"; import { TextInput } from "react-native"; function ParentComponent() { const ref = useRef<TextInput>(); return <CustomTextInput ref={ref} label="Press me" />; }For imperative handles, now you can also just pass
refas a prop:import { useImperativeHandle } from "react"; type CustomInputProps = { ref?: React.Ref<CustomHandle>; // Note: prop must be named "ref" explicitly }; type CustomHandle = { focus: () => void; }; function CustomInput({ ref, ...props }: CustomInputProps) { useImperativeHandle(ref, () => ({ focus: () => {/* implementation */} })); return <TextInput {...props} />; } export default CustomInput;
-
1.3 Style Props
Use
StyleProp<T>to type style props. For pass-through style props, use types exported fromreact-nativefor the type parameter (e.g.ViewStyle).import { StyleProp, ViewStyle, TextStyle, ImageStyle } from "react-native"; type MyComponentProps = { containerStyle?: StyleProp<ViewStyle>; textStyle?: StyleProp<TextStyle>; imageStyle?: StyleProp<ImageStyle>; }; function MyComponent({ containerStyle, textStyle, imageStyle }: MyComponentProps) = { <View style={containerStyle}> <Text style={textStyle}>Sample Image</Text> <Image style={imageStyle} src={'https://sample.com/image.png'} /> </View> }
- 1.4 Animated styles
The recommended approach to creating animations is by using the react-native-reanimated library,
as it offers greater efficiency and convenience compared to using the Animated API directly from
React Native.
import React from 'react';
import { View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
import Animated, { useAnimatedStyle, useSharedValue, withTiming, SharedValue, WithTimingConfig } from 'react-native-reanimated';
type MyComponentProps = {
opacity: Animated.SharedValue<number>;
};
const MyComponent = ({ opacity }: MyComponentProps) => {
const animatedStyle = useAnimatedStyle(() => ({
opacity: opacity.value,
}));
return (
<Animated.View style={[styles.box, animatedStyle]} />
);
};
const App = () => {
const opacity = useSharedValue(0);
const startAnimation = () => {
opacity.value = withTiming(1, {
duration: 1000,
easing: Easing.inOut(Easing.quad),
});
};
return (
<View style={styles.container}>
<MyComponent opacity={opacity} />
<Button title="Animate" onPress={startAnimation} />
</View>
);
};
-
1.5 Render Prop
type ParentComponentProps = { children: (label: string) => React.ReactNode; }; function ParentComponent({ children }: ParentComponentProps) { return children("String being injected"); } function App() { return ( <ParentComponent> {(label) => ( <View> <Text>{label}</Text> </View> )} </ParentComponent> ); }
-
1.6 Type Narrowing Narrow types down using
typeof, discriminated unions, or custom type guards. Refer to this guide for more information on when to use discriminated unions and custom type guards.type Manager = { role: "manager"; team: string; }; type Engineer = { role: "engineer"; language: "ts" | "js" | "php"; }; function introduce(employee: Manager | Engineer) { console.log(employee.team); // TypeScript errors: Property 'team' does not exist on type 'Manager | Engineer'. if (employee.role === "manager") { console.log(`I manage ${employee.team}`); // employee: Manager } else { console.log(`I write ${employee.language}`); // employee: Engineer } }In the above code, type narrowing is used to determine whether an employee object is a Manager or an Engineer based on the role property, allowing safe access to the
teamproperty for managers and thelanguageproperty for engineers.We can also create a custom type guard function.
function isManager(employee: Manager | Engineer): employee is Manager { return employee.role === "manager"; } function introduce(employee: Manager | Engineer) { if (isManager(employee)) { console.log(`I manage ${employee.team}`); // employee: Manager } }In the above code,
employee is Manageris a type predicate. It means that the return type ofisManageris abooleanthat indicates whether a value passed to the function is of a certain type (e.g.Manager).
-
1.7 Error in Try-Catch Clauses
Errors in try/catch clauses are inferred as
unknown. If the error data needs to be accessed, the type of the error needs to be checked and narrowed down.try { .... } catch (e) { // `e` is `unknown`. if (e instanceof Error) { // you can access properties on Error console.error(e.message); } }
-
1.8 Use const assertions for rigorous typing
Use
as constwhen you want to ensure that the types and values are as exact as possible and prevent unwanted mutations.const greeting1 = "hello"; // type: string const greeting2 = "goodbye" as const; // type: "goodbye" const person1 = { name: "Alice", age: 20 }; // type: { name: string, age: number } const person2 = { name: "Bob", age: 30 } as const; // type: { readonly name: "Bob", readonly age: 30 } const array1 = ["hello", 1]; // type: (string | number)[] const array2 = ["goodbye", 2] as const; // type: readonly ["goodbye", 2]
-
1.9 Higher Order Components
Typing HOCs is hard. Refer to this article for detailed guideline on typing HOCs for different usages of HOCs.
-
1.10 Function Overloading
Use function overloads to provide more type information for functions. For the following types of functions, function overloading can be beneficial.
- The return type depends on the input type
- When function accepts different number of parameters
- There are type dependencies between parameters
Refer to this guide to learn how to use functional overloads for each situation.