Tips & Tricks (अपडेट: 2/6/2026)

Claude Code के साथ TypeScript Utility Types: प्रैक्टिकल शुरुआती गाइड

Claude Code के साथ Pick, Omit, Partial, Record, ReturnType और Awaited को चलने वाले उदाहरणों से सीखें।

Claude Code के साथ TypeScript Utility Types: प्रैक्टिकल शुरुआती गाइड

TypeScript utility types ऐसे tools हैं जिनसे आप किसी मौजूदा type को लेकर किसी खास उपयोग के लिए नया type बना सकते हैं। अगर आप User type को manually copy करके public view, form input और API update के लिए अलग-अलग type बनाते हैं, तो field बदलते ही copies में अंतर आ जाता है। Claude Code इस refactor में मदद कर सकता है, लेकिन generated code review करने के लिए आपको हर utility type का उद्देश्य समझना होगा।

इस guide में Pick, Omit, Partial, Required, Readonly, Record, ReturnType और Awaited को आसान भाषा में समझाया गया है। फिर copy-paste करके चलाए जा सकने वाले examples से दिखाया गया है कि Claude Code से practical type design कैसे करवाना है। Official reference के लिए TypeScript Handbook Utility Types देखें, और errors जल्दी पकड़ने के लिए TSConfig strict भी उपयोग करें।

ClaudeCodeLab में संबंधित पढ़ाई के लिए TypeScript practical tips और TypeScript generics guide उपयोगी हैं।

आसान mental model

Utility type को type का “safe copy और reshape” समझें। यह वैसा है जैसे spreadsheet copy करके कुछ columns हटाना, कुछ columns optional बनाना, और उस version को दूसरे workflow में इस्तेमाल करना। फर्क यह है कि TypeScript इस बदलाव को code चलने से पहले check करता है।

Pick<User, "id" | "name"> का मतलब है User से सिर्फ id और name लेना। Omit<User, "passwordHash"> का मतलब है लगभग सब रखना, लेकिन passwordHash हटाना। अगर target type छोटा और साफ है तो Pick पढ़ना आसान है। अगर target type source जैसा ही है, बस कुछ dangerous fields हटाने हैं, तो Omit बेहतर है।

Partial<User> सभी properties को optional बनाता है। यह draft, PATCH और अधूरे form के लिए अच्छा है, पर account create करते समय जरूरी email को भी optional बना सकता है। Required<User> इसका उलटा है और optional properties को required बनाता है। Readonly<User> reassignment रोकता है, इसलिए settings और master data के लिए अच्छा है।

Record<Keys, Type> known keys वाला dictionary बनाता है। ReturnType<typeof fn> function return type निकालता है। Awaited<Promise<T>> await के बाद मिलने वाले value का type निकालता है। Awaited<ReturnType<typeof fetchSomething>> API function और UI types को sync रखने में मदद करता है।

flowchart LR
  A["Source type: User"] --> B["Pick: public view"]
  A --> C["Omit: remove secrets"]
  A --> D["Partial: update input"]
  A --> E["Required: validated input"]
  A --> F["Readonly: fixed settings"]
  G["Function"] --> H["ReturnType"]
  I["Promise"] --> J["Awaited"]

Quick comparison

Typeक्या करता हैPractical useध्यान रखें
Pick<T, K>चुनी हुई keys रखता हैlists, public profiles, cardsबाकी keys available नहीं होतीं
Omit<T, K>चुनी हुई keys हटाता हैcreate inputs, public output, logsruntime values नहीं हटाता
Partial<T>सभी keys optional करता हैdrafts, PATCH, in-progress formsshallow होता है
Required<T>सभी keys required करता हैsave से पहले validated dataजल्दी लगाने पर form कठोर हो सकता है
Readonly<T>reassignment रोकता हैsettings, permissions, constantsnested objects अलग संभालें
Record<K, T>fixed-key dictionary बनाता हैrole permissions, labels, pricesRecord<string, T> अक्सर बहुत broad होता है
ReturnType<T>function return type निकालता हैAPI और UI types sync करनाtypeof functionName लिखें
Awaited<T>Promise resolved value type निकालता हैasync resultsruntime await नहीं करता

इस table को Claude Code में paste करके पूछें कि हर utility type use case से match करता है या नहीं। strict: true project में vague types जल्दी टूटते हैं, और यही practical safety देता है।

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "skipLibCheck": true
  }
}

Use case 1: User से UI और form types बनाना

Admin screens में अक्सर एक ही entity के कई रूप चाहिए होते हैं। Database type, public display type और form input type को अलग-अलग manually maintain करना अच्छा तरीका नहीं है। एक source type रखें और बाकी utility types से derive करें।

type UserRole = "admin" | "editor" | "viewer";

interface User {
  id: string;
  name: string;
  email: string;
  role: UserRole;
  bio: string;
  passwordHash: string;
  createdAt: Date;
  updatedAt: Date;
}

type PublicUser = Pick<User, "id" | "name" | "role" | "bio">;
type UserDraft = Partial<Omit<User, "id" | "passwordHash" | "createdAt" | "updatedAt">>;

type CreateUserInput =
  Required<Pick<User, "name" | "email" | "role">> &
  Partial<Pick<User, "bio">>;

function buildCreatePayload(input: CreateUserInput): Omit<User, "id" | "createdAt" | "updatedAt"> {
  return {
    name: input.name,
    email: input.email,
    role: input.role,
    bio: input.bio ?? "",
    passwordHash: "hashed-by-server",
  };
}

const publicUser: PublicUser = {
  id: "u_001",
  name: "Masa",
  role: "admin",
  bio: "Claude Code workflow designer",
};

const draft: UserDraft = {
  name: "Draft user",
  bio: "Saved before email is confirmed",
};

console.log(publicUser);
console.log(buildCreatePayload({ name: "Aki", email: "aki@example.com", role: "editor" }));
console.log(draft);

Claude Code prompt में साफ लिखें कि क्या रखना है, क्या हटाना है और कब कौन सा field required है।

Create public display, form draft, and create-API types from the User type.
Do not expose passwordHash.
For creation, require only name, email, and role. Keep bio optional.
Use Pick/Omit/Partial/Required and briefly explain why each utility type is used.

Production में इन types के साथ runtime validation भी चाहिए, जैसे Zod। Utility types compile-time shape check करते हैं; वे यह prove नहीं करते कि user-submitted data सच में valid है।

Use case 2: Record से plan features lock करना

Pricing plans, roles और status tables के लिए Record बहुत उपयोगी है। Compiler बता सकता है कि team plan missing है या prioritySupport गलत लिखा गया है।

type Plan = "free" | "pro" | "team";
type Feature = "exportPdf" | "inviteMember" | "prioritySupport";

const featureMatrix: Readonly<Record<Plan, Readonly<Record<Feature, boolean>>>> = {
  free: {
    exportPdf: false,
    inviteMember: false,
    prioritySupport: false,
  },
  pro: {
    exportPdf: true,
    inviteMember: false,
    prioritySupport: false,
  },
  team: {
    exportPdf: true,
    inviteMember: true,
    prioritySupport: true,
  },
};

function canUse(plan: Plan, feature: Feature): boolean {
  return featureMatrix[plan][feature];
}

console.log(canUse("pro", "exportPdf"));
console.log(canUse("free", "prioritySupport"));

Readonly यह intention दिखाता है कि matrix runtime में mutate नहीं होनी चाहिए। यह shallow होता है, इसलिए example में inner Record पर भी Readonly लगाया गया है। Deep data के लिए as const या project-specific deep readonly helper सोचें।

Use case 3: ReturnType और Awaited से API result reuse करना

API client type और UI type अलग-अलग लिखने पर response changes महंगे हो जाते हैं। ReturnType और Awaited async function से result type सीधे derive करते हैं।

async function fetchInvoice(invoiceId: string) {
  return {
    id: invoiceId,
    status: "paid" as const,
    amount: 48000,
    currency: "JPY" as const,
    paidAt: new Date("2026-06-02T10:00:00+09:00"),
  };
}

type Invoice = Awaited<ReturnType<typeof fetchInvoice>>;
type InvoiceSummary = Pick<Invoice, "id" | "status" | "amount" | "currency">;

function formatInvoice(invoice: InvoiceSummary): string {
  return `${invoice.id}: ${invoice.amount.toLocaleString()} ${invoice.currency} (${invoice.status})`;
}

async function main() {
  const invoice = await fetchInvoice("inv_20260602");
  console.log(formatInvoice(invoice));
}

main();

अगर API function trusted boundary है, Claude Code से कहें कि duplicate response type manually न लिखे। External API या user input boundary हो तो runtime validation और error handling जरूर रखें।

Use case 4: Partial को सही depth पर लगाना

Partial<T> shallow है। Nested object के अंदर fields automatic optional नहीं होते, और beginners यहां अक्सर अटकते हैं।

interface Profile {
  id: string;
  displayName: string;
  settings: {
    emailNotification: boolean;
    smsNotification: boolean;
  };
}

type ProfilePatch =
  Omit<Partial<Profile>, "settings"> & {
    settings?: Partial<Profile["settings"]>;
  };

function patchProfile(current: Profile, patch: ProfilePatch): Profile {
  return {
    ...current,
    ...patch,
    settings: {
      ...current.settings,
      ...patch.settings,
    },
  };
}

const profile: Profile = {
  id: "p_001",
  displayName: "Masa",
  settings: {
    emailNotification: true,
    smsNotification: false,
  },
};

console.log(patchProfile(profile, { settings: { smsNotification: true } }));

अगर सिर्फ ProfilePatch = Partial<Profile> लिखें, तो settings update करते समय पूरा settings object चाहिए होगा। Beginner-friendly team code में ऐसा concrete patch type अक्सर generic deep partial से ज्यादा maintainable होता है।

जिन failure cases से बचना है

Omit type से key हटाता है, runtime object से property नहीं। अगर logs या public API response लौटाते हैं, तो secret value सच में remove करें।

interface Account {
  id: string;
  email: string;
  passwordHash: string;
}

type SafeAccount = Omit<Account, "passwordHash">;

function toSafeAccount(account: Account): SafeAccount {
  const { passwordHash, ...safeAccount } = account;
  return safeAccount;
}

console.log(toSafeAccount({
  id: "a_001",
  email: "masa@example.com",
  passwordHash: "secret",
}));

Record<string, T> business rules के लिए अक्सर बहुत wide होता है। अगर allowed keys पता हैं, तो type Plan = "free" | "pro" | "team" जैसी union बेहतर है।

Required<T> को form पर बहुत जल्दी लगाने से unnecessary required fields बढ़ सकते हैं। इसे validation के बाद, save से ठीक पहले complete data के लिए उपयोग करें।

Awaited<T> सिर्फ Promise resolved type बताता है। यह runtime wait नहीं करता; उसके लिए await या .then() चाहिए। अगर यह फर्क clear नहीं है, Claude Code types तो साफ कर देगा लेकिन loading और error states छोड़ सकता है।

Claude Code review prompt

Implementation के बाद vague cleanup न मांगें। Risk-focused review के लिए यह prompt दें।

Review this TypeScript type design.
1. Are Pick/Omit/Partial/Required/Readonly/Record matched to their use cases?
2. Are secrets removed at runtime, not only with Omit?
3. Does Partial make create inputs too loose?
4. Do ReturnType and Awaited reduce duplicated API types?
5. Are any vague any or broad string types left under strict settings?

यह prompt type को सुंदर बनाने से ज्यादा defects रोकने पर केंद्रित है। Masa ने एक छोटे admin screen में यही गलती देखी थी: हर जगह Partial लगाने से empty email save flow तक acceptable दिख रहा था। “draft”, “create” और “saved” को अलग derived types में बांटने के बाद Claude Code patches review करना आसान हुआ।

निष्कर्ष

TypeScript utility types कोई कठिन type gymnastics नहीं हैं। वे public data, drafts, validated inputs, fixed settings और async API results के फर्क को duplicate definitions के बिना व्यक्त करने के practical tools हैं। Fields control करने के लिए Pick और Omit, workflow stages के लिए Partial और Required, configuration safety के लिए Readonly और Record, और API type duplication घटाने के लिए ReturnType plus Awaited उपयोग करें।

ClaudeCodeLab teams को TypeScript architecture, content CMS, internal tools और monetized funnels में Claude Code लागू करने में मदद करता है। अगर आपके project में types हैं फिर भी avoidable mistakes आती हैं, तो Claude Code training and consulting से बात करें।

इस article के examples को strict TypeScript mindset के साथ verify किया गया। सबसे बड़ा practical फायदा ReturnType और Awaited से मिला: API response बदलने पर UI में बदलने वाली जगहें जल्दी दिखती हैं। महत्वपूर्ण caveat यह है कि Omit runtime secrets नहीं हटाता, इसलिए public response functions में explicit property stripping जरूरी है।

#Claude Code #TypeScript #utility types #type safety #code quality
मुफ़्त

मुफ़्त PDF: Claude Code cheatsheet

Email डालें और commands, review habits तथा safe workflow वाली एक-page PDF पाएँ.

हम आपका data सुरक्षित रखते हैं और spam नहीं भेजते.

Masa

लेखक के बारे में

Masa

Claude Code workflow और team adoption पर काम करने वाला engineer.