Generic interfaces allow you to create reusable interfaces that can work with different data types. Instead of creating separate interfaces for every type of data, you can create one generic interface and provide the required type when using it.
A generic interface is an interface that uses a type parameter.
interface Box<T> {
value: T;
}
Here, T represents the type of the
value property.
Generic interfaces allow one interface to work with many different data types.
interface Box<T> {
value: T;
}
const numberBox: Box<number> = {
value: 100
};
const stringBox: Box<string> = {
value: "Hello"
};
The same interface works with both numbers and strings.
A generic interface is created by placing the type parameter after the interface name.
interface Container<T> {
value: T;
}
The type parameter can later be replaced with a specific type.
interface Box<T> {
value: T;
}
const box: Box<string> = {
value: "TypeScript"
};
console.log(box.value);
Here, T becomes string.
interface Box<T> {
value: T;
}
const box: Box<number> = {
value: 500
};
console.log(box.value);
In this example, T becomes number.
interface Box<T> {
value: T;
}
const box: Box<boolean> = {
value: true
};
console.log(box.value);
Generic interfaces can also work with boolean values.
interface List<T> {
items: T[];
}
const numbers: List<number> = {
items: [10, 20, 30]
};
const names: List<string> = {
items: ["Amit", "Rahul"]
};
The same interface can represent lists of different types.
interface Student<T> {
id: number;
name: string;
data: T;
}
const student: Student<string> = {
id: 101,
name: "Amit",
data: "TypeScript"
};
The data property can be customized through
the generic type.
interface Student<T> {
id: number;
name: string;
data: T;
}
const student: Student<number> = {
id: 101,
name: "Amit",
data: 95
};
The same student interface can store a number as its generic data.
An interface can contain more than one generic type parameter.
interface Pair<T, U> {
first: T;
second: U;
}
const pair: Pair<string, number> = {
first: "Amit",
second: 25
};
Here, T and U can represent
different types.
A generic interface can define a function that works with a generic type.
interface Processor<T> {
process(value: T): T;
}
const processor: Processor<string> = {
process(value) {
return value.toUpperCase();
}
};
console.log(
processor.process("hello")
);
Generic interfaces are commonly used to describe API responses.
interface ApiResponse<T> {
data: T;
success: boolean;
message: string;
}
The data property can contain different types.
interface ApiResponse<T> {
data: T;
success: boolean;
message: string;
}
const response:
ApiResponse<string> = {
data: "Login successful",
success: true,
message: "Success"
};
interface Student {
id: number;
name: string;
}
interface ApiResponse<T> {
data: T;
success: boolean;
}
const response:
ApiResponse<Student> = {
data: {
id: 101,
name: "Amit"
},
success: true
};
console.log(
response.data.name
);
interface Student {
id: number;
name: string;
}
interface ApiResponse<T> {
data: T;
success: boolean;
}
const response:
ApiResponse<Student[]> = {
data: [
{
id: 101,
name: "Amit"
},
{
id: 102,
name: "Rahul"
}
],
success: true
};
console.log(
response.data
);
interface Response<T> {
data: T;
loading: boolean;
error?: string;
}
const response:
Response<string> = {
data: "Hello",
loading: false
};
Generic interfaces can contain optional properties just like normal interfaces.
interface Data<T> {
readonly id: number;
value: T;
}
const data: Data<string> = {
id: 101,
value: "Hello"
};
data.value = "TypeScript";
The id property cannot be reassigned after
the object is created.
interface ApiResponse<T> {
data: {
result: T;
};
success: boolean;
}
const response:
ApiResponse<number> = {
data: {
result: 95
},
success: true
};
interface Factory<T> {
create(): T;
}
const studentFactory:
Factory<string> = {
create() {
return "Amit";
}
};
console.log(
studentFactory.create()
);
interface Handler<T> {
handle(
value: T
): void;
}
const stringHandler:
Handler<string> = {
handle(value) {
console.log(
value.toUpperCase()
);
}
};
stringHandler.handle(
"hello"
);
interface Storage<T> {
save(value: T): void;
get(): T;
}
class StringStorage
implements Storage<string> {
private value: string = "";
save(value: string): void {
this.value = value;
}
get(): string {
return this.value;
}
}
const storage =
new StringStorage();
storage.save("Hello");
console.log(
storage.get()
);
Generic interfaces can also use constraints.
interface Entity {
id: number;
}
interface Repository<
T extends Entity
> {
getById(id: number): T;
}
interface Student extends Entity {
name: string;
}
const repository:
Repository<Student> = {
getById(id) {
return {
id: id,
name: "Amit"
};
}
};
interface FormState<T> {
values: T;
errors: string[];
submitted: boolean;
}
interface LoginForm {
username: string;
password: string;
}
const form:
FormState<LoginForm> = {
values: {
username: "admin",
password: "12345"
},
errors: [],
submitted: false
};
This pattern is useful when managing forms with different data structures.
Generic interfaces can be used to type reusable React component props.
interface ListProps<T> {
items: T[];
renderItem:
(item: T) => string;
}
function List<T>(
props: ListProps<T>
) {
return (
<div>
{props.items.map(
props.renderItem
)}
</div>
);
}
Generic interfaces are useful for reusable React Native components that can display different types of data.
interface ListProps<T> {
items: T[];
getTitle:
(item: T) => string;
}
function UserList<T>(
props: ListProps<T>
) {
return (
<View>
{props.items.map(
(item, index) => (
<Text key={index}>
{props.getTitle(item)}
</Text>
)
)}
</View>
);
}
A generic interface can have a default type parameter.
interface Response<
T = string
> {
data: T;
success: boolean;
}
const response:
Response = {
data: "Hello",
success: true
};
const numberResponse:
Response<number> = {
data: 100,
success: true
};
Generic interfaces are useful for pagination because the returned data can have different types.
interface PaginatedResponse<T> {
data: T[];
page: number;
totalPages: number;
}
interface Student {
id: number;
name: string;
}
const response:
PaginatedResponse<Student> = {
data: [
{
id: 101,
name: "Amit"
}
],
page: 1,
totalPages: 5
};
any instead of a useful generic type.interface Student {
id: number;
name: string;
course: string;
}
interface ApiResponse<T> {
data: T;
success: boolean;
message: string;
}
const response:
ApiResponse<Student> = {
data: {
id: 101,
name: "Amit",
course: "React Native"
},
success: true,
message: "Student loaded successfully"
};
console.log(
"Student ID:",
response.data.id
);
console.log(
"Name:",
response.data.name
);
console.log(
"Course:",
response.data.course
);
console.log(
"Success:",
response.success
);
This example demonstrates how a generic interface can describe a reusable API response containing student data.
Generic interfaces allow one interface to work with different data types while preserving TypeScript's type safety.
interface ApiResponse<T> {
data: T;
success: boolean;
}
const response:
ApiResponse<string> = {
data: "Hello",
success: true
};
const numberResponse:
ApiResponse<number> = {
data: 100,
success: true
};
Generic interfaces are especially useful for APIs, reusable components, forms, collections, repositories, and React Native applications.
T.Question: Which syntax is used to create a generic interface?