From harness-claude
Transforms TypeScript object types by iterating over keys to create readonly, optional, required, nullable variants, remap or filter keys. Use for utility types, form states, API wrappers, event handlers.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Transform object types by iterating over their keys with mapped type syntax
Explains and applies TypeScript utility types (Partial, Required, Pick, Omit, Readonly, Record) plus mapped and conditional types for flexible, type-safe code.
Applies TypeScript utility types like Partial, Pick, Omit, Exclude to transform object types, derive function signatures, filter unions, and build lookup maps for forms, APIs, and 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.
Share bugs, ideas, or general feedback.
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