Mapped type duyệt qua các key của một type để sinh type mới; mệnh đề as (TS 4.1) cho phép đổi tên key trong lúc duyệt — nhờ đó biến đổi được cả tên, không chỉ giá trị.
ts
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
}
type User = { id: number; name: string }
type UserGetters = Getters<User>
// { getId: () => number; getName: () => string }Lọc key bằng cách remap về never — key nào map thành never sẽ bị loại khỏi kết quả:
ts
type OmitByType<T, U> = {
[K in keyof T as T[K] extends U ? never : K]: T[K]
}
type WithoutFns = OmitByType<{ id: number; save: () => void }, Function>
// { id: number }Modifier đi kèm: readonly [K in keyof T] thêm readonly, -readonly bỏ; [K in keyof T]?: thêm optional, -?: bỏ — đây chính là cách Required<T> được viết.
Dùng thực tế: sinh type cho object event handler (on${Capitalize<K>}), map DTO snake_case sang camelCase, hoặc tách nhóm field theo kiểu giá trị. Lưu ý hai key remap ra cùng tên sẽ gộp thành union kiểu giá trị, dễ tạo kết quả ngoài ý muốn.