Union, Intersection và Literal Types
Bài 4 – Union Type, Intersection Type và Literal Type trong TypeScript theo cách đơn giản, trực quan và tiêu chuẩn.
Union, Intersection và Literal Types
Union, Intersection và Literal types là những công cụ mạnh mẽ giúp bạn kết hợp và kiểm soát kiểu dữ liệu một cách linh hoạt. Chúng giúp code vừa chặt chẽ vừa linh hoạt, đáp ứng các trường hợp sử dụng phức tạp.
1. Nội dung chính
- Union Type (
|): Biến có thể mang một trong nhiều kiểu - Intersection Type (
&): Kết hợp nhiều kiểu thành một - Literal Types: Giá trị cố định, không chỉ kiểu
- Template Literal Types: Tạo kiểu từ string templates
- Ứng dụng thực tế: Configuration, API responses, state management
2. Ví dụ chi tiết
2.1. Union Type
// Union cơ bản
let value: string | number;
value = "hello";
value = 42;
// Function với union parameters
function processId(id: string | number) {
if (typeof id === "string") {
return id.toUpperCase(); // string
}
return id.toFixed(2); // number
}
// Union với arrays
const mixed: (string | number)[] = [1, "two", 3, "four"];
// Discriminated unions - pattern quan trọng
type LoadingState = {
status: "loading";
};
type SuccessState = {
status: "success";
data: any;
};
type ErrorState = {
status: "error";
error: string;
};
type AppState = LoadingState | SuccessState | ErrorState;
function renderUI(state: AppState) {
switch (state.status) {
case "loading":
return "Loading...";
case "success":
return `Data: ${state.data}`;
case "error":
return `Error: ${state.error}`;
}
}
2.2. Intersection Type
// Intersection cơ bản
type Person = {
name: string;
age: number;
};
type Employee = {
id: number;
department: string;
};
type EmployeePerson = Person & Employee;
const emp: EmployeePerson = {
name: "Alice",
age: 30,
id: 123,
department: "Engineering"
};
// Intersection với utility types
type RequiredUser = Required<Person> & {
id: number;
};
// Intersection trong thực tế
type BaseEntity = {
id: string;
createdAt: Date;
updatedAt: Date;
};
type SoftDeletable = {
deletedAt?: Date;
isDeleted: boolean;
};
type User = BaseEntity & {
name: string;
email: string;
} & SoftDeletable;
const user: User = {
id: "123",
createdAt: new Date(),
updatedAt: new Date(),
name: "Bob",
email: "bob@example.com",
isDeleted: false
};
2.3. Literal Types
// String literals
type Theme = "light" | "dark" | "system";
type Status = "pending" | "approved" | "rejected";
function setTheme(theme: Theme) {
// theme chỉ có thể là "light", "dark", hoặc "system"
document.body.setAttribute("data-theme", theme);
}
// Number literals
type Priority = 1 | 2 | 3 | 4 | 5;
type HttpStatus = 200 | 201 | 400 | 401 | 404 | 500;
function checkPriority(priority: Priority) {
if (priority <= 2) {
return "High priority";
}
return "Normal priority";
}
// Boolean literals
type Config = {
debug: true | false;
experimental: boolean;
};
// Mixed literals
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
type ApiResponse = {
method: HttpMethod;
status: HttpStatus;
success: true | false;
};
2.4. Template Literal Types
// Template literals cơ bản
type EventName = `on${Capitalize<string>}`;
type ClickEvent = `onClick${string}`;
// CSS properties
type CssProperty = `margin-${"top" | "bottom" | "left" | "right"}`;
type Padding = `padding-${"top" | "bottom" | "left" | "right"}`;
// API endpoints
type ApiEndpoint = `/api/${"users" | "products" | "orders"}/${string}`;
function makeRequest(endpoint: ApiEndpoint) {
// endpoint có thể là "/api/users/123", "/api/products/456", etc.
}
// Advanced template literals
type Size = "small" | "medium" | "large";
type Color = "red" | "blue" | "green";
type ButtonVariant = `${Size}-${Color}` | "outline";
const button1: ButtonVariant = "small-red";
const button2: ButtonVariant = "outline";
// const button3: ButtonVariant = "extra-large-yellow"; // ❌ Error
3. Kiến thức trọng tâm
3.1. Union Type giúp xử lý nhiều trường hợp
- Flexibility với control: Biến có thể nhận nhiều kiểu khác nhau
- Type narrowing với typeof, instanceof, type guards
- Discriminated unions cho state management và error handling
💡 GHI NHỚ: Union type = “CÓ THỂ là A HOẶC B”
3.2. Intersection Type giúp kết hợp features
- Composition over inheritance: Kết hợp nhiều type thành một
- Mixin pattern: Thêm features vào existing types
- Plugin architecture: Kết hợp các plugin types
💡 GHI NHỚ: Intersection type = “PHẢI CẢ A VÀ B”
3.3. Literal Types giúp constraint values
- Const assertions:
as constđể infer literal types - String enums alternative: Khi không muốn dùng enum
- Configuration: Chỉ cho phép specific values
4. Bài tập thực hành
Bài 1: Union cho User roles
type UserRole = "admin" | "editor" | "viewer" | "guest";
type User = {
id: number;
name: string;
role: UserRole;
permissions?: string[];
};
function canEdit(user: User): boolean {
return user.role === "admin" || user.role === "editor";
}
const admin: User = { id: 1, name: "Alice", role: "admin" };
const guest: User = { id: 2, name: "Bob", role: "guest" };
console.log(canEdit(admin)); // true
console.log(canEdit(guest)); // false
Bài 2: Intersection cho geometry
type Shape2D = {
area: () => number;
};
type Drawable = {
draw: () => void;
};
type Circle = Shape2D & Drawable & {
radius: number;
name: "circle";
};
const circle: Circle = {
radius: 5,
name: "circle",
area: () => Math.PI * 5 * 5,
draw: () => console.log("Drawing circle")
};
Bài 3: Template literals cho CSS
type ResponsiveValue<T> = {
mobile: T;
tablet?: T;
desktop: T;
};
type SpacingScale = 0 | 4 | 8 | 16 | 24 | 32;
type Margin = `m-${SpacingScale}`;
type Padding = `p-${SpacingScale}`;
type ComponentStyles = {
[K in Margin | Padding]?: ResponsiveValue<string>;
};
const styles: ComponentStyles = {
"m-16": {
mobile: "16px",
desktop: "24px"
},
"p-8": {
mobile: "8px",
tablet: "12px",
desktop: "16px"
}
};
5. Sai lầm thường gặp
- Quên type guard: Không kiểm tra type trước khi dùng union
- Union thay vì intersection: Nhầm lẫn “hoặc” và “và”
- Literal type quá rộng: Không bó hẹp giá trị đủ
- Không sử dụng discriminated unions: Code become verbose
- Template literals phức tạp: Over-engineering simple cases
⚠️ GHI NHỚ: Chọn đúng công cụ cho đúng công việc
6. Kết luận
Union, Intersection và Literal types giúp bạn xây dựng type system linh hoạt và mạnh mẽ. Khi kết hợp đúng cách, chúng giúp code vừa an toàn vừa expressive.
🔑 GHI NHỚ QUAN TRỌNG:
- Union (
|): Multiple possibilities- Intersection (
&): Combine requirements- Literal: Specific values
- Template literals: Dynamic type creation
- Discriminated unions: Best practice for state management