React Native applications commonly receive data from APIs. The response may contain users, products, students, posts, orders, messages, or other information.
TypeScript interfaces allow us to describe the structure of API data and use that structure consistently throughout the application.
API data is information returned by a server after an application sends a request.
{
"id": 101,
"name": "Rahul",
"email": "rahul@example.com"
}
This data can be displayed and processed inside a React Native application.
interface User {
id: number;
name: string;
email: string;
}
This interface describes the expected structure of a user returned by an API.
const user: User = {
id: 101,
name: "Rahul",
email: "rahul@example.com"
};
TypeScript checks that the object follows the User interface.
interface Student {
id: number;
name: string;
email: string;
course: string;
fee: number;
}
Interfaces can contain multiple properties with different types.
interface User {
id: number;
name: string;
active: boolean;
}
Boolean properties can represent values such as active, verified, enabled, or completed.
Some API fields may not be available for every record.
interface User {
id: number;
name: string;
email: string;
phone?: string;
}
The phone property is optional.
A property can be marked as readonly when it should not be reassigned through the typed object.
interface User {
readonly id: number;
name: string;
email: string;
}
API responses frequently 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 must follow the Address interface.
An API response may contain additional information along with the actual data.
interface UserResponse {
success: boolean;
user: User;
}
This interface describes both the success value and user data.
interface UserResponse {
success: boolean;
users: User[];
}
The users property contains an array of User objects.
const response =
await fetch(
"https://example.com/api/users"
);
const data: User[] =
await response.json();
The response data can be represented as an array of User objects.
async function getUsers():
Promise<User[]> {
const response =
await fetch(
"https://example.com/api/users"
);
const data: User[] =
await response.json();
return data;
}
The return type tells TypeScript that the function returns a Promise containing an array of User objects.
const [users, setUsers] =
useState<User[]>([]);
This tells TypeScript that the state contains an array of User objects.
When a single API record has not been loaded yet, the state can be nullable.
const [user, setUser] =
useState<User | null>(null);
The state can contain either a User object or null.
const [loading, setLoading] =
useState<boolean>(false);
const [error, setError] =
useState<string | null>(null);
Separate states can be used to represent loading and error conditions.
API properties can sometimes have a limited set of possible values.
interface User {
id: number;
name: string;
role: "admin" | "student" | "teacher";
}
Only the specified role values are allowed by the interface.
APIs commonly return dates as strings.
interface User {
id: number;
name: string;
createdAt: string;
}
For example, the API might return:
{
"createdAt": "2026-09-30T10:30:00Z"
}
interface Product {
id: number;
name: string;
price: number;
available: boolean;
}
The same interface approach can be used for products, orders, posts, messages, or any other API resource.
{users.map((user: User) => (
<View key={user.id}>
<Text>
{user.name}
</Text>
<Text>
{user.email}
</Text>
</View>
))}
TypeScript understands the properties available on each user.
<FlatList<User>
data={users}
keyExtractor={(item) =>
item.id.toString()
}
renderItem={({ item }) => (
<View>
<Text>
{item.name}
</Text>
<Text>
{item.email}
</Text>
</View>
)}
/>
interface UserCardProps {
user: User;
}
function UserCard(
{ user }: UserCardProps
): React.JSX.Element {
return (
<View>
<Text>
{user.name}
</Text>
<Text>
{user.email}
</Text>
</View>
);
}
This allows a reusable component to receive correctly typed API data.
any for every API response.In a larger React Native project, API interfaces can be stored in a dedicated types folder.
// types/User.ts
export interface User {
id: number;
name: string;
email: string;
}
Keeping shared types in separate files makes them easier to reuse.
import {
User
} from "./types/User";
The same User interface can now be used by API functions, components, screens, and state.
Some APIs return pagination information along with the records.
interface UserResponse {
success: boolean;
users: User[];
page: number;
totalPages: number;
}
This interface describes both the user data and pagination information.
import React, {
useEffect,
useState
} from "react";
import {
View,
Text,
FlatList,
ActivityIndicator
} from "react-native";
interface User {
readonly id: number;
name: string;
email: string;
phone?: string;
role: "admin" | "student" | "teacher";
}
interface UserResponse {
success: boolean;
users: User[];
}
export default function App(): React.JSX.Element {
const [users, setUsers] =
useState<User[]>([]);
const [loading, setLoading] =
useState<boolean>(true);
const [error, setError] =
useState<string | null>(null);
const loadUsers =
async (): Promise<void> => {
try {
setLoading(true);
setError(null);
const response =
await fetch(
"https://example.com/api/users"
);
if (!response.ok) {
throw new Error(
"Request failed"
);
}
const data: UserResponse =
await response.json();
setUsers(data.users);
} catch (error) {
setError(
"Unable to load users"
);
} finally {
setLoading(false);
}
};
useEffect(() => {
loadUsers();
}, []);
if (loading) {
return (
<View>
<ActivityIndicator />
</View>
);
}
if (error) {
return (
<View>
<Text>{error}</Text>
</View>
);
}
return (
<View>
<Text>
User List
</Text>
<FlatList<User>
data={users}
keyExtractor={(item) =>
item.id.toString()
}
renderItem={({ item }) => (
<View>
<Text>
{item.name}
</Text>
<Text>
{item.email}
</Text>
<Text>
Role: {item.role}
</Text>
<Text>
Phone: {
item.phone ??
"Not available"
}
</Text>
</View>
)}
/>
</View>
);
}
Promise<Type> for typed asynchronous functions.Interfaces make API data easier to understand and safer to use in React Native applications. An interface can describe individual records, arrays, nested objects, API response wrappers, pagination information, optional properties, and fixed values.
You should now understand how to create API interfaces, use them with fetch(), Promise return types, useState, FlatList, reusable components, pagination, and shared type files.
User[] for arrays of API records.Promise<Type> for typed API functions.Type | null for data that may not be loaded yet.Question: Which interface correctly represents an API response containing multiple User objects?