From harness-claude
Transforms object types by iterating over keys with mapped type syntax. Covers key remapping, modifier manipulation, and practical patterns like form state and API wrappers.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:ts-mapped-typesThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Transform object types by iterating over their keys with mapped type syntax
Transform object types by iterating over their keys with mapped type syntax
in keyof:type Readonly<T> = {
readonly [K in keyof T]: T[K];
};
type Optional<T> = {
[K in keyof T]?: T[K];
};
+ and -:type Mutable<T> = {
-readonly [K in keyof T]: T[K];
};
type Required<T> = {
[K in keyof T]-?: T[K];
};
type Nullable<T> = {
[K in keyof T]: T[K] | null;
};
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
type User = { name: string; age: number };
type UserGetters = Getters<User>;
// { getName: () => string; getAge: () => number }
as:type PrefixedKeys<T, P extends string> = {
[K in keyof T as `${P}${Capitalize<string & K>}`]: T[K];
};
type ApiUser = PrefixedKeys<User, 'user'>;
// { userName: string; userAge: number }
as and never:type OnlyStrings<T> = {
[K in keyof T as T[K] extends string ? K : never]: T[K];
};
type StringFields = OnlyStrings<{ name: string; age: number; email: string }>;
// { name: string; email: string }
type EventHandlers<T extends string> = {
[K in T as `on${Capitalize<K>}`]: (event: K) => void;
};
type Handlers = EventHandlers<'click' | 'hover' | 'focus'>;
// { onClick: (event: 'click') => void; onHover: ...; onFocus: ... }
type DeepPartial<T> = {
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
};
// Form state with touched/error tracking
type FormState<T> = {
values: T;
touched: { [K in keyof T]: boolean };
errors: { [K in keyof T]?: string };
};
// Pick and transform
type PickAndNullify<T, K extends keyof T> = {
[P in K]: T[P] | null;
};
Mapped types iterate over a set of keys (from keyof T or a string literal union) and produce a new object type with one property per key. They are the foundation of most built-in utility types (Partial, Required, Readonly, Pick, Record).
Homomorphic mapped types: When the key source is keyof T, the mapped type preserves optional and readonly modifiers from the original type. This is why Partial<T> works correctly on types that already have optional properties.
Key remapping (TypeScript 4.1+): The as clause in a mapped type lets you transform key names, filter keys (by mapping to never), or create entirely new key sets from the original keys.
Template literal types + mapped types: Combining as \prefix${K}`` with mapped types creates patterns like getter/setter generation, event handler typing, and API route typing.
Recursive mapped types: TypeScript allows recursive mapped types for deep transformations (DeepPartial, DeepReadonly). The compiler has a recursion depth limit — extremely deep object nesting can cause issues.
Trade-offs:
as is powerful but the type error messages when it fails are often cryptichttps://typescriptlang.org/docs/handbook/2/mapped-types.html
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeExplains and applies TypeScript utility types (Partial, Required, Pick, Omit, Readonly, Record) plus mapped and conditional types for flexible, type-safe code.
Apply built-in TypeScript utility types (Partial, Pick, Omit, Record, etc.) to transform and compose types without redundancy. Great for form types, API shapes, and partial updates.
Masters TypeScript advanced types including generics, conditional types, mapped types, template literals, and utility types for type-safe applications. Use for complex type logic, reusable utilities, and compile-time safety in TS projects.