Pick, Omit, and Record Composition

Derive view and input types from one canonical entity with Pick and Omit, so changes to the source shape propagate to every dependent type.

TypescriptData Integrity

Code

snippet
export interface User {
  id: string;
  email: string;
  passwordHash: string;
  createdAt: Date;
  updatedAt: Date;
}

export type PublicUser = Omit<User, "passwordHash">;
export type UserSummary = Pick<User, "id" | "email">;

export type UpdateUserInput = Partial<Pick<User, "email">>;

export type UserIndex = Record<string, UserSummary>;

export function toPublic(user: User): PublicUser {
  const { passwordHash: _omit, ...rest } = user;
  return rest;
}

export function buildIndex(users: User[]): UserIndex {
  return Object.fromEntries(users.map((u) => [u.id, { id: u.id, email: u.email }]));
}