Sửa lỗi TypeScript: 'const' assertion chỉ có thể áp dụng cho literal chuỗi, số, boolean, mảng hoặc đối tượng

intermediate🔵 TypeScript2026-04-30| Môi trường TypeScript 3.4+ (Node.js, React, Vue, Angular) sử dụng VS Code hoặc trình biên dịch terminal.

Error Message

A 'const' assertion can only be applied to a string, number, boolean, array, or object literal.
#typescript#const-assertion#as-const#literal-type

Vượt qua dòng kẻ răng cưa màu đỏTôi đang tái cấu trúc (refactoring) một module phân quyền cho bản phát hành sản phẩm thì TypeScript khiến tôi khựng lại. Tôi muốn đảm bảo một đối tượng cấu hình được xử lý như một kiểu literal bất biến sâu (deeply immutable). Thay vì các kiểu chỉ đọc (read-only) sạch sẽ mà tôi mong đợi, trình biên dịch đã ném ra một lỗi quen thuộc: A 'const' assertion can only be applied to a string, number, boolean, array, or object literal.

Điều này xảy ra khi bạn cố gắng áp dụng as const cho một giá trị mà TypeScript không còn coi là một biểu thức literal nữa. Đây là một trở ngại phổ biến khi tăng cường tính an toàn của kiểu (type safety) trong các dự án quy mô lớn.

Thông báo lỗi```

// Đoạn mã này thường gây ra lỗi: const userRoles = ['admin', 'editor', 'viewer']; const ROLES = userRoles as const; // ❌ Lỗi tại đây!


Đầu ra của trình biên dịch rất trực tiếp nhưng có thể gây nhầm lẫn nếu bạn không biết về nới lỏng kiểu (type widening):

error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, or object literal.


## Nguyên nhân gốc rễ: Nới lỏng kiểu (Type Widening)TypeScript đã giới thiệu tính năng `as const` assertion trong phiên bản 3.4. Công việc chính của nó là thông báo cho trình biên dịch rằng một biểu thức nên là một kiểu literal—như chuỗi cụ thể "admin" thay vì kiểu chung `string`—và tất cả các thành phần bên trong phải là `readonly`.
Tuy nhiên, **`as const` phải được áp dụng tại thời điểm tạo ra giá trị.**
Trong ví dụ trên, `userRoles` đã là một biến. Ở dòng thứ hai, TypeScript đã "nới lỏng" `userRoles` thành kiểu chung `string[]`. Bạn không thể áp dụng một const assertion cho một tham chiếu đã mất đi tính đặc thù literal của nó. Trình biên dịch yêu cầu assertion phải nằm trực tiếp trên chính cấu trúc dữ liệu đó.
## Cách khắc phục### Cách 1: Khẳng định (Assert) ngay tại nguồnCách khắc phục hiệu quả nhất là chuyển `as const` assertion sang giá trị literal trước khi gán nó cho một biến. Điều này ngăn trình biên dịch nới lỏng kiểu.

// ✅ Thực hiện theo cách này const ROLES = ['admin', 'editor', 'viewer'] as const;

// ROLES hiện tại là: readonly ["admin", "editor", "viewer"]


Bằng cách đặt assertion trực tiếp sau dấu ngoặc mảng, bạn yêu cầu TypeScript giữ nguyên ba chuỗi cụ thể đó chính xác như hiện tại. Điều này thu hẹp kiểu từ một tập hợp chuỗi vô hạn thành một bộ ba (tuple) cố định.
### Cách 2: Xử lý toán tử ba ngôi và logicBạn có thể gặp lỗi này khi sử dụng toán tử ba ngôi hoặc template literal. Nếu biểu thức phức tạp, trình biên dịch có thể mất dấu các giá trị literal.

// ❌ Điều này thường thất bại trong các trường hợp phức tạp const status = (isActive ? 'active' : 'inactive') as const;

// ✅ Cách sửa: Khẳng định (Assert) từng literal riêng lẻ const status = isActive ? ('active' as const) : ('inactive' as const);


Mặc dù các phiên bản TypeScript hiện đại xử lý toán tử ba ngôi đơn giản tốt hơn, việc bao bọc các kết quả riêng lẻ trong dấu ngoặc đơn là cách an toàn nhất để đảm bảo các kiểu literal.
### Cách 3: Toán tử 'satisfies' (TS 4.9+)Nếu bạn đang sử dụng TypeScript 4.9 trở lên, toán tử `satisfies` thường tốt hơn `as const`. Nó cho phép bạn xác thực cấu trúc (shape) trong khi vẫn giữ lại các kiểu literal.

type Config = Record<string, string[]>;

// ✅ Sự kết hợp hoàn hảo const menu = { home: ['/'], auth: ['/login', '/signup'] } as const satisfies Config;


Cách tiếp cận này đảm bảo đối tượng là `readonly`, giữ các giá trị chuỗi cụ thể và xác minh đối tượng khớp với interface `Config` của bạn.
### Cách 4: Chi tiết về Template LiteralKhi xây dựng các chuỗi động, hãy đảm bảo các thành phần cơ bản là literal. Nếu một tiền tố đã bị nới lỏng thành kiểu `string` chung, template literal cuối cùng không thể được khẳng định lại thành một hằng số.

const prefix = 'API'; // Mặc định là literal "API" const endpoint = ${prefix}_URL as const; // Cách này hoạt động!


## Các bước xác minhĐể xác nhận việc sửa lỗi, hãy di chuột qua biến của bạn trong VS Code. Bạn sẽ thấy các giá trị cụ thể trong định nghĩa kiểu, không chỉ là `string` hay `string[]`.
- **Thành công:** Bạn thấy `readonly ["value1", "value2"]`.- **Thất bại:** Bạn vẫn thấy các kiểu chung như `string[]`.Chạy kiểm tra kiểu nhanh để chắc chắn:

npx tsc --noEmit


## Mẹo phòng ngừa- **Khai báo sớm:** Áp dụng `as const` ngay khi bạn định nghĩa các đối tượng cấu hình.- **Ưu tiên Readonly:** Sử dụng `ReadonlyArray<T>` trong chữ ký hàm để báo hiệu các yêu cầu về tính bất biến.- **Tránh dùng 'let':** Sử dụng `const` cho tất cả các khai báo biến để ngăn trình biên dịch giả định rằng giá trị sẽ thay đổi sau đó.

Related Error Notes