//
Search across all documentation pages
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Use TypeScript's built-in utility types to transform and compose React prop types. Derive new types from existing ones instead of duplicating definitions.
// Base type
type User = {
id: string;
name: string;
email: string;
role: "admin" | "editor" | "viewer";
createdAt: Date;
};
// Partial - all fields become optional (great for update forms)
type UpdateUserPayload = Partial<User>;
// Pick - select specific fields
type UserPreview = Pick<User, "id" | "name">;
// Omit - exclude specific fields
type CreateUserPayload = Omit<User, "id" | "createdAt">;
// Record - typed key-value map
type RolePermissions = Record<User["role"], string[]>;
const permissions: RolePermissions = {
admin: ["read", "write", "delete"],
editor: ["read", "write"],
viewer: ["read"],
};// Practical component using derived types
type UserFormProps = {
initialData?: Partial<User>;
onSubmit: (data: CreateUserPayload) => void;
};
function UserForm({ initialData, onSubmit }: UserFormProps) {
const [form, setForm] = useState<CreateUserPayload>({
name: initialData?.name ?? "",
email: initialData?.email ?? "",
role: initialData?.role ?? "viewer",
});
return (
<form
onSubmit={(e) => {
e.preventDefault();
onSubmit(form);
}}
>
<input
value={form.name}
onChange={(e) => setForm({ ...form, name: e.target.value })}
/>
<input
value={form.email}
onChange={(e) => setForm({ ...form, email: e.target.value })}
/>
<button type="submit">Save</button>
</form>
);
}Partial<T> makes every property in T optional. Useful for update payloads where you only change some fields.Required<T> is the inverse of Partial -- makes every property required. Useful for normalizing config objects with defaults.Pick<T, K> creates a type with only the specified keys from T. Use it to create focused sub-types.Omit<T, K> creates a type with all keys except the specified ones. Common for create payloads where the server generates id.Record<K, V> creates an object type with keys of type K and values of type V. Perfect for lookup maps.Extract<T, U> pulls members from a union that match U. Extract<User["role"], "admin" | "editor"> yields "admin" | "editor".Exclude<T, U> removes members from a union that match U. The inverse of Extract.Extracting component prop types:
// Get props from an existing component
type ButtonProps = React.ComponentProps<typeof Button>;
// Get props of an HTML element
type DivProps = React.ComponentPropsWithoutRef<"div">;
// Extend HTML element props
type CardProps = React.ComponentPropsWithoutRef<"div"> & {
title: string;
elevated?: boolean;
};Readonly props:
type ImmutableUser = Readonly<User>;
// All fields are now readonly - prevents accidental mutation
type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};Mapped types for form state:
type FormErrors<T> = Partial<Record<keyof T, string>>;
type UserFormErrors = FormErrors<CreateUserPayload>;
// { name?: string; email?: string; role?: string }NonNullable for stripping null/undefined:
type MaybeUser = User | null | undefined;
type DefiniteUser = NonNullable<MaybeUser>; // UserPartial<Pick<User, "name" | "email">> gives you { name?: string; email?: string }.React.ComponentProps<typeof MyComponent> extracts the props type from any component, even third-party ones where the type is not exported.Parameters<T> and ReturnType<T> work on function types. ReturnType<typeof useAuth> gives you the return type of a custom hook.Omit does not error on keys that do not exist in the original type. Omit<User, "nonExistent"> silently returns the full User type.Partial makes everything optional, including fields that should remain required. Use Partial<Pick<T, K>> & Omit<T, K> to make only some fields optional.Record<string, T> allows any string key. This can hide typos. Prefer union literal keys when the set of keys is known.Partial or Readonly. These only operate on the top-level properties. You need custom recursive types for deep transformations.
| Approach | Pros | Cons |
|---|---|---|
Partial<T> for updates | Derived from source type, stays in sync | Makes all fields optional, not just some |
| Manual sub-types | Full control over each type | Duplicates definitions, drifts from source |
Pick / Omit composition | Precise field selection | Deeply nested compositions are hard to read |
Zod .pick() / .omit() | Runtime validation + type inference | Requires Zod dependency |
satisfies operator | Validates shape without widening | Does not create a reusable type |
T optional.Partial<User> for a PATCH request body.Pick<T, K> creates a type with only the specified keys from T.Omit<T, K> creates a type with all keys except the specified ones.Pick when you want a small subset; use Omit when you want most fields minus a few.type ButtonProps = React.ComponentProps<typeof Button>;
type DivProps = React.ComponentPropsWithoutRef<"div">;K and values of type V.Record<User["role"], string[]> maps each role to an array of permission strings.Extract<T, U> keeps union members that match U.Exclude<T, U> removes union members that match U.Extract<"admin" | "editor" | "viewer", "admin" | "editor"> yields "admin" | "editor".Partial<Pick<User, "name" | "email">> gives { name?: string; email?: string }.Omit<User, "nonExistent"> silently returns the full User type.Partial only affects top-level properties.DeepPartial<T>.type UpdateUser = Partial<Pick<User, "name" | "email">> & Omit<User, "name" | "email">;Partial<Pick<>> for the optional fields with Omit<> for the rest.null and undefined from a type.NonNullable<User | null | undefined> gives User.type AuthData = ReturnType<typeof useAuth>;ReturnType<T> works on any function type, including hooks and utility functions.type FormErrors<T> = Partial<Record<keyof T, string>>;Record<keyof T, string> maps every key of T to a string value.Partial makes each error message optional.Reviewed by Chris St. John·Last updated Jul 19, 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥