React Native applications frequently work with user information such as name, email, mobile number, profile image, age, address, and user ID. TypeScript interfaces allow us to clearly define the structure of this data.
Once a user interface is created, it can be reused with state, API responses, FlatList, navigation, forms, and reusable components.
User data is information stored about a person using an application.
For example:
{
id: 101,
name: "Rahul",
email: "rahul@example.com",
age: 21
}
An interface gives user data a clear and reusable structure.
interface User {
id: number;
name: string;
email: string;
}
This interface says that every User object must contain
id, name, and email.
const user: User = {
id: 101,
name: "Rahul",
email: "rahul@example.com"
};
The User interface tells TypeScript what properties the
object should contain.
interface User {
id: number;
name: string;
email: string;
phone: string;
age: number;
}
An interface can contain as many properties as the application needs.
Boolean properties can represent states such as whether a user is active.
interface User {
id: number;
name: string;
active: boolean;
}
const user: User = {
id: 101,
name: "Rahul",
active: true
};
Some user information may not always be available. Use
? for optional properties.
interface User {
id: number;
name: string;
email: string;
phone?: string;
}
The phone number does not have to be included in every User object.
A user ID can be marked as readonly when it should not be changed through the typed object.
interface User {
readonly id: number;
name: string;
email: string;
}
This helps protect the ID from accidental reassignment in TypeScript code.
User data can contain nested objects.
interface Address {
city: string;
state: string;
pincode: string;
}
interface User {
id: number;
name: string;
address: Address;
}
const user: User = {
id: 101,
name: "Rahul",
address: {
city: "Patna",
state: "Bihar",
pincode: "800001"
}
};
The nested address object must follow the Address interface.
interface Profile {
bio: string;
image: string;
}
interface User {
id: number;
name: string;
profile: Profile;
}
Separate interfaces can make complex user data easier to understand.
const [user, setUser] =
useState<User | null>(null);
The state can contain a User object or null when user data
has not been loaded yet.
setUser({
id: 101,
name: "Rahul",
email: "rahul@example.com"
});
TypeScript checks that the object matches the User interface.
{user && (
<View>
<Text>
{user.name}
</Text>
<Text>
{user.email}
</Text>
</View>
)}
The condition makes sure that user data exists before accessing it.
const response =
await fetch(
"https://example.com/api/user"
);
const data: User =
await response.json();
setUser(data);
The response can be represented using the User interface in application code.
If an API returns multiple users, use an array of the User interface.
const users: User[] = [
{
id: 1,
name: "Rahul",
email: "rahul@example.com"
},
{
id: 2,
name: "Priya",
email: "priya@example.com"
}
];
<FlatList<User>
data={users}
keyExtractor={(item) =>
item.id.toString()
}
renderItem={({ item }) => (
<View>
<Text>
{item.name}
</Text>
<Text>
{item.email}
</Text>
</View>
)}
/>
A union type can restrict a user's role to specific values.
interface User {
id: number;
name: string;
role: "admin" | "student" | "teacher";
}
TypeScript will only accept the specified role values.
interface User {
id: number;
name: string;
status: "active" | "inactive";
}
This is useful when an application needs a fixed set of user statuses.
A User interface can also be used as the basis for form data.
interface UserForm {
name: string;
email: string;
phone: string;
}
const [form, setForm] =
useState<UserForm>({
name: "",
email: "",
phone: ""
});
setForm(prev => ({
...prev,
name: "Rahul"
}));
The spread operator keeps the other properties while updating one field.
interface UserCardProps {
user: User;
}
function UserCard(
{ user }: UserCardProps
): React.JSX.Element {
return (
<View>
<Text>
{user.name}
</Text>
<Text>
{user.email}
</Text>
</View>
);
}
interface UserCardProps {
user: User;
onSelect: (user: User) => void;
}
The callback receives a complete User object.
onPress={() =>
onSelect(user)
}
any instead of a User interface.In larger applications, shared interfaces can be placed in a separate types file.
// types/User.ts
export interface User {
id: number;
name: string;
email: string;
}
The interface can then be imported wherever it is required.
import {
User
} from "./types/User";
Shared types help keep the structure of user data consistent throughout the application.
User objects can also be passed between React Navigation screens when the route parameter type is defined appropriately.
interface User {
id: number;
name: string;
email: string;
}
type RootStackParamList = {
Home: undefined;
Profile: {
user: User;
};
};
The Profile screen can then receive a correctly typed User object.
import React, {
useState
} from "react";
import {
View,
Text,
FlatList,
Pressable,
StyleSheet
} from "react-native";
interface User {
readonly id: number;
name: string;
email: string;
phone?: string;
role: "admin" | "student" | "teacher";
}
const users: User[] = [
{
id: 1,
name: "Rahul",
email: "rahul@example.com",
phone: "9876543210",
role: "student"
},
{
id: 2,
name: "Priya",
email: "priya@example.com",
role: "teacher"
}
];
export default function App(): React.JSX.Element {
const [selectedUser, setSelectedUser] =
useState<User | null>(null);
const handleSelect =
(user: User): void => {
setSelectedUser(user);
};
return (
<View style={styles.container}>
<Text style={styles.title}>
User List
</Text>
<FlatList<User>
data={users}
keyExtractor={(item) =>
item.id.toString()
}
renderItem={({ item }) => (
<Pressable
style={styles.card}
onPress={() =>
handleSelect(item)
}
>
<Text style={styles.name}>
{item.name}
</Text>
<Text>
{item.email}
</Text>
<Text>
Role: {item.role}
</Text>
<Text>
Phone: {
item.phone ??
"Not available"
}
</Text>
</Pressable>
)}
/>
{selectedUser && (
<Text style={styles.selected}>
Selected: {selectedUser.name}
</Text>
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20
},
title: {
fontSize: 24,
fontWeight: "bold",
marginBottom: 15
},
card: {
padding: 15,
marginBottom: 10,
borderWidth: 1,
borderRadius: 8
},
name: {
fontSize: 18,
fontWeight: "bold"
},
selected: {
marginTop: 15,
fontSize: 18
}
});
User for the main user model.User data appears in almost every real-world application. TypeScript interfaces provide a clear structure for this data and allow the same structure to be reused across components, forms, API responses, FlatLists, and navigation.
You should now understand how to create User interfaces, use optional and readonly properties, create nested user data, store users in state, display users in FlatList, pass users through props, use callback functions, and organize shared user types.
? for optional user properties.readonly for values that should not be reassigned.User[] for multiple users.User | null for user state that may initially be empty.Question: Which TypeScript syntax correctly defines an array of User objects?