Vì literal widening.
Khi khai báo bằng let hoặc đặt trong object literal, TypeScript mở rộng kiểu literal 'GET' thành string — do giá trị đó có thể bị gán lại. string không gán được vào union hẹp.
type Method = 'GET' | 'POST'
function request(m: Method) {}
const a = 'GET' // kiểu 'GET' — const không đổi được nên giữ literal
request(a) // OK
let b = 'GET' // kiểu string — bị widening
request(b) // error
const opts = { method: 'GET' }
request(opts.method) // error: property của object literal cũng bị wideningCách sửa:
- as const cho object hoặc riêng property: const opts = { method: 'GET' } as const — mọi property thành readonly và giữ kiểu literal.
- Hoặc annotate ngay chỗ khai báo: const opts: { method: Method } = { method: 'GET' }.
Lý do TypeScript làm vậy: const không thể gán lại nên giữ literal là an toàn; còn let và property của object thì có thể đổi, giữ literal sẽ gây lỗi giả ở chỗ khác. Hệ quả hay gặp nữa: mảng ['a', 'b'] suy ra string[]; thêm as const mới thành readonly ['a', 'b'] để rút ra union bằng (typeof arr)[number].