تصویر کھینچو۔ جب API اختتامی نقطہ تک پہنچ جاتا ہے، تو آپ کو API کا جواب واپس ملتا ہے۔ اگر میں ڈیٹا کو براہ راست ایپلی کیشن میں منتقل کرتا ہوں تو ترقی کے دوران سب کچھ ٹھیک لگتا ہے۔ فرضی ڈیٹا صاف ہے، اقسام کو ترتیب دیا جاتا ہے، اور سب کچھ چیک آؤٹ ہوتا ہے۔
پھر کوڈ پیداوار تک پہنچ جاتا ہے۔ API کے اختتامی نقطہ سے فیلڈز کو اس طرح واپس کیا جاتا ہے: null تار کے بجائے. میں ایک صف کی توقع کر رہا تھا، لیکن مجھے کچھ اس طرح واپس ملا: undefinedکسی چیز کی توقع اور وصول کریں۔ number. اچانک، آپ کو ایرر اسکرینز، UI کریشز، اور یہاں تک کہ خاموش ڈیٹا بدعنوانی کا سامنا کرنا پڑتا ہے جس پر کوئی بھی اس وقت تک نوٹس نہیں کرتا جب تک آپ شکایت نہ کریں۔
یہ جاوا اسکرپٹ کی ترقی میں ایک عام اور روکا جا سکتا ہے۔ اس فکس کے لیے تھرڈ پارٹی لائبریریوں یا مکمل فن تعمیر کی بحالی کی ضرورت نہیں ہے۔ ضرورت پڑنے پر اسے استعمال کرنے کے لیے افادیت کی خصوصیات اور نظم و ضبط کا ایک چھوٹا مجموعہ درکار ہے۔
یہ مضمون آپ کو دکھاتا ہے کہ چار TypeScript تحفظ کی افادیت کا استعمال کرتے ہوئے لچکدار ایپلی کیشنز کیسے بنائیں جو آپ کے کوڈ بیس کو مزید مستحکم بناتی ہیں۔ safeArray، safeString، safeNumberاور safeObject. یوٹیلیٹیز فریم ورک ایگنوسٹک ہیں، لہذا آپ انہیں اپنے کوڈ بیس میں چھوڑ سکتے ہیں، چاہے آپ React، سادہ JavaScript، یا اس کے درمیان کسی بھی چیز کے ساتھ کام کر رہے ہوں۔
انڈیکس
شرائط
ڈائیونگ سے پہلے، آپ کے پاس ہونا ضروری ہے:
-
TypeScript کا کام کرنے کا علم۔ آپ کو ماہر بننے کی ضرورت نہیں ہے، لیکن آپ کو اقسام، انٹرفیس اور جنرک سے واقف ہونا چاہیے۔
-
جاوا اسکرپٹ اور بلٹ ان ٹائپ چیکنگ کے طریقے، جیسے
typeofاورArray.isArray.
مسئلہ
JavaScript ایک ڈھیلے طریقے سے ٹائپ کی جانے والی زبان ہے۔ میں آپ کو مجھے کال کرنے دوں گا۔ .map() غیر صفوں پر خصوصیات تک رسائی حاصل کریں۔ nullاور پھر ہم ریاضی کو اس طرح انجام دیتے ہیں: NaN. یہ سب کچھ اس وقت تک ممکن ہے جب تک کہ بہت دیر نہ ہوجائے۔ زبان پیچھے نہیں ہٹتی۔ یہ صرف خاموشی سے ٹوٹ جاتا ہے۔
TypeScript مدد کرتا ہے، لیکن صرف ایک حد تک۔ اقسام کی جانچ مرتب وقت پر کی جاتی ہے، رن ٹائم پر نہیں۔ لہذا جب بیرونی ڈیٹا API، فارم جمع کرانے، مقامی اسٹوریج، یا فریق ثالث SDK سے آتا ہے، TypeScript پہلے ہی عمارت سے نکل چکا ہوتا ہے۔ اس سے کوئی فرق نہیں پڑتا ہے کہ انٹرفیس کیا کہتا ہے، رن ٹائم پر اصل قدر وہی ہے جو جاوا اسکرپٹ کو موصول ہوتی ہے۔
حقیقت میں یہ ہے:
// This looks fine. It is not fine.
type User = {
id: number;
name: string;
tags: string[];
};
function displayUser(user: User) {
const upperName = user.name.toUpperCase();
const tagList = user.tags.map((tag) => `#${tag}`);
return { upperName, tagList };
}
اگر user.name یہ کچھ اس طرح لوٹاتا ہے: nullفون کال .toUpperCase() ایپلیکیشن کریش ہو جاتی ہے۔ اگر user.tags ہے undefinedفون کال .map() ایپلیکیشن بھی کریش ہو جاتی ہے۔ اصل API استعمال کرتے وقت، دونوں منظرنامے مکمل طور پر ممکن ہیں، اور TypeScript آپ کو متنبہ نہیں کرے گا کیونکہ آپ نے اسے قسم پر بھروسہ کرنے کو کہا ہے۔
انتظار کرو! میں نے آپ کو یہ کہتے سنا، "میں دستیاب ہوں۔” optional chaining میری ایپ کو کریش ہونے سے روکنے کے لیے۔ یہ درست ہے، جیسا کہ ذیل کی مثال میں دکھایا گیا ہے۔
// This looks better. But...
type User = {
id: number;
name: string;
tags: string[];
};
function displayUser(user: User) {
const upperName = user?.name?.toUpperCase?.();
const tagList = (user?.tags || [])?.map((tag) => `#${tag}`);
return { upperName, tagList };
}
تاہم، مندرجہ بالا نقطہ نظر کے ساتھ ایک مسئلہ ہے. سب سے پہلے، upperName واپس آ جائے گا undefined اگر user.name یہ تار نہیں ہے۔ دوسرا، user?.tag || [] باؤنسر undefined اور null اقدار تنہا ہیں۔ جب اعتراض واپس کیا جاتا ہے تو کیا ہوتا ہے؟ {...}?.map(...)? اب کیا آپ اصل مسئلہ دیکھتے ہیں؟
تو user?.name?.toUpperCase?.() ہم مندرجہ ذیل معاملات کو محفوظ طریقے سے ہینڈل کرتے ہیں: user، nameیا یہاں تک کہ toUpperCase ہو سکتا ہے یہ خود موجود نہ ہو۔ ڈیٹا کی غیر یقینی اقسام سے نمٹنے کے دوران یہ کارآمد ہے، لیکن ڈیٹا کی تضادات کو نہیں سنبھالتا ہے۔
یہ مسئلہ کیوں موجود ہے؟
قصور جاوا اسکرپٹ کے ٹائپ سسٹم پر ہے، یا اس کے بجائے ٹائپ سسٹم کی کمی ہے۔
JavaScript میں کئی بنیادی اقسام اور کچھ اصول ہیں جو مناسب معلوم ہوتے ہیں جب تک کہ آپ ان کو تفصیل سے نہ دیکھیں۔ مثال کے طور پر، typeof null رپورٹ "object"، typeof [] واپس بھی "object"اور typeof NaN رپورٹ "number". یہ کوئی انتہائی معاملہ نہیں ہے۔ یہ زبان ہے۔
جاوا اسکرپٹ صارفین کو کتنی آسانی سے گمراہ کر سکتا ہے اس کی ایک فوری مثال یہ ہے۔
typeof null; // "object" — not "null"
typeof []; // "object" — not "array"
typeof NaN; // "number" — NaN is technically a number
Array.isArray([]); // true — this is the correct check
isNaN("hello"); // true — because "hello" coerces to NaN
Number.isNaN("hello"); // false — this is the correct check
TypeScript اس کے اوپر ایک جامد قسم کا نظام رکھتا ہے، کوڈ کے چلنے سے پہلے بہت سی غلطیوں کو پکڑتا ہے۔ تاہم، جامد تجزیہ صرف اس کوڈ کے ساتھ کام کرتا ہے جسے آپ پہلے ہی لکھ چکے ہیں۔ اس لمحے جب ڈیٹا نیٹ ورک کی حد کو عبور کرتا ہے یا داخل ہوتا ہے۔ localStorageURL پیرامیٹرز، فریق ثالث کے اسکرپٹس، یا کوڈبیس سے باہر کے ذرائع کے لیے، TypeScript رکنے کی ضمانت دیتا ہے۔
جب آپ لکھتے ہیں:
const data = await response.json() as User;
آپ کسی چیز کی تصدیق نہیں کرتے۔ ٹائپ اسکرپٹ کمپائلر کو بتائیں "میں یہ چاہتا ہوں۔ Userکمپائلر اس وعدے کو قبول کرتا ہے اور چیک کرنا بند کر دیتا ہے۔ تاہم، اگر API واپس آتا ہے۔ null کسی فیلڈ کے لیے، اگر آپ ایک سٹرنگ بھیجتے ہیں جس سے کسی نمبر کی توقع ہوتی ہے، یا اگر آپ اس وصف کو مکمل طور پر چھوڑ دیتے ہیں، تو جاوا اسکرپٹ بہر حال آگے بڑھے گا اور آپ کا کوڈ پہلی چیز پر ٹوٹ جائے گا جو یہ سمجھتا ہے کہ ایسا نہیں ہے۔
"TypeScript کے خیال میں ڈیٹا کیا ہے” اور "ڈیٹا اصل میں رن ٹائم میں کیا ہے” کے درمیان یہ فرق وہیں ہے جہاں زیادہ تر پروڈکشن ڈیٹا بگز رہتے ہیں۔ حل یہ ہے کہ قسم کے دعووں پر بھروسہ کرنا بند کر دیا جائے اور ڈیٹا کو براہ راست درست کرنا شروع کیا جائے۔
حل: محفوظ رسائی کی افادیت
حل یہ ہے کہ باؤنڈری پر ڈیٹا کی توثیق کی جائے۔ جس لمحے متوقع ڈیٹا آپ کی درخواست میں داخل ہوتا ہے، اسے کہیں اور منتقل کرنے سے پہلے پہلے اسے چیک کریں۔
یہ چار افعال بالکل ایسا کرتے ہیں:
export function safeArray(prop: unknown): T[] {
if (Array.isArray(prop)) {
return prop as T[];
} else {
return [] as T[];
}
}
export function safeString(prop: unknown, fallback = ""): string {
if (typeof prop === "string") {
return prop;
} else {
return fallback;
}
}
export function safeNumber(prop: unknown, fallback = 0): number {
if (typeof prop === "number" && !isNaN(prop)) {
return prop;
} else {
return fallback;
}
}
export function safeObject(
prop: unknown,
fallback = {} as T,
): T {
if (prop !== null && typeof prop === "object" && !Array.isArray(prop)) {
return prop as T;
}
return fallback;
}
ہر فنکشن کی اجازت ہے۔ unknownآپ کو اسے استعمال کرنے سے پہلے قیمت کی تصدیق کرنی ہوگی۔ ہر ایک محفوظ ڈیفالٹ قدر واپس کرتا ہے اگر ان پٹ اس سے مختلف ہے جس کی توقع کی گئی تھی۔ کوئی تنازعہ نہیں، کوئی خاموشی نہیں۔ undefinedکوئی کرپٹوگرافک رن ٹائم غلطیاں نہیں ہیں۔
آپ ان کو اپنی React ایپ، Node.js API، vanilla TypeScript ماڈیول، یا کسی بھی JavaScript یا TypeScript پروجیکٹ میں شامل کر سکتے ہیں جو بیرونی ڈیٹا پر کارروائی کرتا ہے۔
ہر یوٹیلیٹی کیسے کام کرتی ہے۔
safeArray
export function safeArray(prop: unknown): T[] {
if (Array.isArray(prop)) {
return prop as T[];
} else {
return [] as T[];
}
}
یہ چیک کرتا ہے کہ آیا نہیں۔ prop یہ دراصل ایک صف ہے جس کا استعمال کرتے ہوئے: Array.isArray. اگر ایسا ہے تو، اسے دوبارہ ٹائپ کریں: T[]. اگر صف اس طرح نہیں ہے: null، undefinedسٹرنگز کی خالی صف یا کچھ بھی لوٹاتا ہے۔
یہ جاوا اسکرپٹ کے نرالا ہونے کی وجہ سے اہم ہے جو ہم نے اوپر دیکھا۔ typeof [] رپورٹ "object"اس کا مطلب ہے نادانی۔ typeof آپ اسے چیک سے نہیں پکڑ سکتے۔ Array.isArray ٹھیک کرو۔
safeString
export function safeString(prop: unknown, fallback = ""): string {
if (typeof prop === "string") {
return prop;
} else {
return fallback;
}
}
یہ فنکشن استعمال کرتا ہے: typeof چیک کرتا ہے کہ آیا قدر ایک تار ہے۔ اختیاری fallback پیرامیٹرز آپ کو بامعنی ڈیفالٹ اقدار کی وضاحت کرنے کی اجازت دیتے ہیں۔ مثال کے طور پر، "Unknown" صارف نام ظاہر کرتے وقت خالی تار کے بجائے۔
safeNumber
export function safeNumber(prop: unknown, fallback = 0): number {
if (typeof prop === "number" && !isNaN(prop)) {
return prop;
} else {
return fallback;
}
}
یہاں اہم تفصیلات یہ ہیں: !isNaN(prop). کیونکہ typeof NaN === "number" یہ جاوا اسکرپٹ میں سچ ہے۔ اس چیک کو چھوڑنے کے نتیجے میں واپسی ہو سکتی ہے۔ NaN ایک بہاو حساب کی خرابی واقع ہوتی ہے۔ یہ خصوصیت اس کو روکتی ہے۔
safeObject
export function safeObject(
prop: unknown,
fallback = {} as T,
): T {
if (prop !== null && typeof prop === "object" && !Array.isArray(prop)) {
return prop as T;
}
return fallback;
}
جاوا اسکرپٹ کی نوعیت کی وجہ سے، تین شرائط درکار ہیں: typeof null === "object" یہ سچ ہے۔ typeof [] === "object" یہ بھی سچ ہے۔ تو یہ فنکشن واضح طور پر دونوں کو خارج کرتا ہے۔ جو آپ کو واپس ملتا ہے وہ ایک سادہ چیز ہے اور کسی اور چیز کی ضمانت نہیں ہے۔
اصل میں اس کا استعمال کیسے کریں۔
API کے جوابات کو معمول بنائیں (سادہ ٹائپ اسکرپٹ)
ان یوٹیلیٹیز کو استعمال کرنے کے لیے بہترین جگہ ان فنکشنز میں ہے جو ڈیٹا کے ایپلیکیشن کے دوسرے حصوں تک پہنچنے سے پہلے API کے جوابات پر کارروائی کرتے ہیں۔ یہ React ایپس، Node.js سروسز، یا سادہ TypeScript ماڈیولز کے لیے اسی طرح کام کرتا ہے۔
// lib/users.ts
import { safeArray, safeString, safeNumber, safeObject } from "@/utils/safe";
type User = {
id: number;
name: string;
email: string;
tags: string[];
};
function normaliseUser(raw: unknown): User {
const obj = safeObject>(raw);
return {
id: safeNumber(obj.id),
name: safeString(obj.name, "Unknown User"),
email: safeString(obj.email),
tags: safeArray(obj.tags),
};
}
async function fetchUser(id: string): Promise {
const response = await fetch(`/api/users/${id}`);
const data = await response.json();
return normaliseUser(data);
}
آپ کا کوڈ User کسی آبجیکٹ کے تمام فیلڈز میں اس قسم کی ضمانت دی جاتی ہے جس کا وہ اعلان کرتے ہیں۔ نیچے کی طرف کچھ بھی حیران کرنے کی ضرورت نہیں ہے۔ name شاید null یا tags شاید undefined.
رد عمل کے اجزاء (دفاعی رینڈرنگ)
بعض اوقات آپ کو پرپس، سیاق و سباق، یا استفسار کے نتائج سے اپنے جزو سے براہ راست ڈیٹا موصول ہوتا ہے، اور آپ اپ اسٹریم کو معمول پر لانے کو کنٹرول نہیں کرتے ہیں۔ اس صورت میں، قیمت کو استعمال کے مقام پر لپیٹ دیں۔
import { safeArray, safeString, safeNumber, safeObject } from "@/utils/safe";
type ProductProps = {
product: unknown;
};
function ProductCard({ product }: ProductProps) {
const p = safeObject>(product);
const name = safeString(p.name, "Unnamed Product");
const price = safeNumber(p.price);
const tags = safeArray(p.tags);
return (
{name}
${price.toFixed(2)}
{tags.map((tag) => (
- {tag}
))}
);
}
اسہال product یہ اس طرح آتا ہے: null یا، اگر یہ مکمل طور پر غیر متوقع نظر آتا ہے، تو یہ جزو کریش ہونے کے بجائے فال بیک اسٹیٹ پیش کرے گا۔
رد عمل کے سوالات پر مشتمل ہے۔
اگر آپ React Query استعمال کرتے ہیں، تو آپ اپنے اندرونی ڈیٹا کو معمول بنا سکتے ہیں۔ select خام API ردعمل کو جزو تک پہنچنے سے پہلے تبدیل کرنے کا اختیار۔
import { useQuery } from "@tanstack/react-query";
import { safeArray, safeString, safeNumber, safeObject } from "@/utils/safe";
type Order = {
id: number;
status: string;
total: number;
items: string[];
};
function normaliseOrder(raw: unknown): Order {
const obj = safeObject>(raw);
return {
id: safeNumber(obj.id),
status: safeString(obj.status, "pending"),
total: safeNumber(obj.total),
items: safeArray(obj.items),
};
}
function useOrder(orderId: string) {
return useQuery({
queryKey: ["order", orderId],
queryFn: () =>
fetch(`/api/orders/${orderId}`).then((res) => res.json()),
select: normaliseOrder,
});
}
کہ select کال بیک استفسار کے حل ہونے کے بعد لیکن ڈیٹا کیش ہونے سے پہلے عمل میں لایا جاتا ہے۔ آپ کا useOrder ہک ہمیشہ صحیح شکل لوٹاتا ہے۔ Orderقطع نظر اس کے کہ API اصل میں کیا واپس بھیجتا ہے۔
React سیاق و سباق فراہم کنندہ کا استعمال کرنا
سیاق و سباق ایک ایسی جگہ ہے جہاں غیر محفوظ ڈیٹا خود بخود پورے جزو کے درخت کے ذریعے پھیل سکتا ہے۔ اس بات کو یقینی بنانے کے لیے فراہم کنندہ کی سطح پر معمول بنائیں کہ تمام صارفین محفوظ ہیں۔
import { createContext, useContext, useEffect, useState } from "react";
import { safeArray, safeString, safeObject } from "@/utils/safe";
type AppConfig = {
theme: string;
features: string[];
};
const defaultConfig: AppConfig = {
theme: "light",
features: [],
};
const ConfigContext = createContext(defaultConfig);
function ConfigProvider({ children }: { children: React.ReactNode }) {
const [config, setConfig] = useState(defaultConfig);
useEffect(() => {
fetch("/api/config")
.then((res) => res.json())
.then((raw: unknown) => {
const obj = safeObject>(raw);
setConfig({
theme: safeString(obj.theme, "light"),
features: safeArray(obj.features),
});
});
}, []);
return (
{children}
);
}
export function useConfig() {
return useContext(ConfigContext);
}
فراہم کنندہ کی سطح پر ایک نارملائزیشن مرحلہ ان تمام اجزاء کی حفاظت کرتا ہے جو سیاق و سباق کو استعمال کرتے ہیں۔
Node.js API پاتھ میں
یہ افادیت بیک اینڈ پر بھی کارآمد ہیں۔ جب Node.js API کو درخواست کا باڈی موصول ہوتا ہے، تو یہ اس بات پر بھروسہ نہیں کر سکتا کہ کلائنٹ نے وہی بھیجا جس کی اس کی توقع تھی۔ براہ کرم داخلے پر چیک کریں۔
// routes/orders.ts (Express)
import { safeArray, safeString, safeNumber, safeObject } from "../utils/safe";
type OrderPayload = {
userId: number;
notes: string;
itemIds: number[];
};
function parseOrderPayload(raw: unknown): OrderPayload {
const obj = safeObject>(raw);
return {
userId: safeNumber(obj.userId),
notes: safeString(obj.notes),
itemIds: safeArray(obj.itemIds),
};
}
app.post("/orders", (req, res) => {
const payload = parseOrderPayload(req.body);
if (!payload.userId) {
return res.status(400).json({ error: "userId is required" });
}
// proceed with validated payload
});
وہی 4 یوٹیلیٹیز، ایک ہی پیٹرن۔ یہ صرف ایک مختلف رن ٹائم ماحول ہے۔
بہترین طرز عمل
کسی اور چیز کی طرح، ان یوٹیلیٹیز کو صحیح اور درست طریقے سے استعمال کرنے میں آپ کی مدد کرنے کے لیے کچھ بہترین طریقے ہیں۔
سب سے پہلے، ہم ہر فنکشن کے اندر کی بجائے حدود پر معمول بناتے ہیں۔ ان یوٹیلیٹیز کو کال کرنے کے لیے بہترین جگہ ایک بار ہے، آپ کے ڈیٹا کی بازیافت کی پرت، API ہینڈلر، یا انٹیگریشن پوائنٹ سے، ڈیٹا کے پھیلنے سے پہلے۔ اگر آپ کال کریں safeString ایک ہی فیلڈ کے لیے 5 مختلف مقامات کا ہونا اس بات کا اشارہ ہے کہ نارملائزیشن اپ اسٹریم سے تعلق رکھتی ہے۔
دوسرا، معنی خیز متبادل استعمال کریں۔ پہلے سے طے شدہ تبدیلی (خالی تار، 0خالی صفیں اور خالی اشیاء) محفوظ ہیں، لیکن بعض اوقات گمراہ کن ہیں۔ صارف کے ڈسپلے نام کے لیے: safeString(name, "Anonymous") سے زیادہ فائدہ مند safeString(name). اس بارے میں سوچیں کہ آپ کے ڈومین میں ہر فیلڈ کے لیے کیا مناسب ہے۔
تیسرا، اپنی قسم کی تعریفوں کو ایماندار رکھیں۔ اگر میدان حقیقتاً ممکن ہے۔ null یا undefined آپ اسے اپنے ڈیٹا سورس کی قسم میں ظاہر کرتے ہیں اور ان یوٹیلیٹیز کا استعمال کرتے ہوئے اس پر کارروائی کرتے ہیں۔ درج ذیل فیلڈز درج کریں: string ایسا کب ہو سکتا ہے؟ null یہ صرف مسئلے کی دستاویز ہے۔ یہ افادیت اس وقت بہترین کام کرتی ہیں جب آپ کی قسم آپ کو موصول ہونے والی حقیقت کی عکاسی کرتی ہے۔
آخر میں، ہم ایک نارملائزیشن ماڈیول بناتے ہیں۔ اپنے تمام نارملائزر فنکشنز کو ایک جگہ پر رکھیں۔ مثال کے طور پر، src/lib/normalise.ts. یہ دفاعی منطق کو مرکزی رکھتا ہے، جانچنے میں آسان، اور اطلاق کی منطق سے دور رہتا ہے۔
کس چیز سے بچنا ہے۔
اسی طرح، کچھ طریقوں سے بچنے کے لئے ہیں.
سب سے پہلے، ان یوٹیلیٹیز کو ڈیٹا کے مناسب معاہدے کی جگہ استعمال نہ کریں۔ اگر آپ کا پورا کوڈ بیس تمام اقدار کو لپیٹ دیتا ہے۔ safeString چونکہ ڈیٹا کے ذرائع بہت متضاد ہیں، اس لیے حقیقی اصلاحات معاہدوں، OpenAPI وضاحتیں، مشترکہ اسکیما، Zod کی توثیق، یا کم از کم دستاویزی جوابات کی شکل میں ہیں۔ یہ افادیت نظامی خلل کے بجائے ایج کیسز اور رن ٹائم کے مسائل کو ہینڈل کرتی ہیں۔
دوسرا، اسے مت چھوڑیں۔ safeObject لفافہ یہ فوری طور پر کاسٹ کرنے کے لئے پرکشش ہے۔ any آپ پراپرٹیز تک براہ راست رسائی حاصل کرسکتے ہیں۔ اس سے اجتناب کریں۔ کہ as any Casts TypeScript اور رسائی کی خصوصیات کو مکمل طور پر باطل کر دیتے ہیں۔ unknown قدر بہرحال تالیف کی غلطی کا سبب بنے گی۔ استعمال کریں safeObject پہلے قدر کو کھولیں، پھر محفوظ طریقے سے اس فیلڈ تک رسائی حاصل کریں۔
اگلا، انٹرمیڈیٹ اقدار کو نکالے بغیر ان افادیت کو متصل نہ کریں۔ کچھ ایسا safeString(safeArray(raw)[0]) یہ کمپیکٹ نظر آ سکتا ہے، لیکن اسے پڑھنا اور ڈیبگ کرنا زیادہ مشکل ہے۔ اس کے بجائے، انٹرمیڈیٹ اقدار کو واضح طور پر نامزد متغیرات میں نکالیں۔
آخر میں، توثیق کو صرف اس وجہ سے نہ چھوڑیں کہ آپ ڈیٹا سورس کو کنٹرول کرتے ہیں۔ "میں نے API لکھا ہے، لہذا میں جانتا ہوں کہ یہ کیا لوٹتا ہے” ایک معقول موقف ہے جب تک کہ دوسری صورت میں ثابت نہ ہو جائے، جیسے اسکیما کو منتقل کرنا، کالعدم کالم شامل کرنا، یا ایج کیسز جن پر غور نہیں کیا گیا۔ ٹرسٹ افادیت، میموری نہیں.
بونس: ان کو یکجا کریں۔ safeData مددگار
اگر آپ اکثر چاروں یوٹیلیٹیز کو ایک ساتھ کال کرتے ہیں (ایک بار جب آپ اپنے API کے جوابات کو مستقل طور پر معمول پر لانا شروع کر دیتے ہیں، تو آپ انہیں ایک روانی سے مددگار میں ترتیب دے سکتے ہیں)۔
// utils/safeData.ts
import { safeArray, safeString, safeNumber, safeObject } from "./safe";
type SafeDataAccessors = {
string: (key: string, fallback?: string) => string;
number: (key: string, fallback?: number) => number;
array: (key: string) => T[];
object: (key: string, fallback?: T) => T;
};
export function safeData(raw: unknown): SafeDataAccessors {
const obj = safeObject>(raw);
return {
string: (key, fallback = "") => safeString(obj[key], fallback),
number: (key, fallback = 0) => safeNumber(obj[key], fallback),
array: (key: string) => safeArray(obj[key]),
object: (key: string, fallback = {} as T) =>
safeObject(obj[key], fallback),
};
}
نارملائزیشن فنکشن پھر صاف پڑھتا ہے، چاہے وہ ری ایکٹ ہک، ایکسپریس روٹ، یا کہیں اور ہو۔
import { safeData } from "@/utils/safeData";
function normaliseUser(raw: unknown) {
const d = safeData(raw);
return {
id: d.number("id"),
name: d.string("name", "Unknown User"),
email: d.string("email"),
tags: d.array("tags"),
};
}
یہ ایک پتلی تجرید ہے۔ کوئی جادو اور تھوڑا سا تکرار نہیں ہے۔ اگر آپ کا ریگولرائزیشن فنکشن لفظی ہو جاتا ہے تو اسے استعمال کریں۔ اگر آپ کی ٹیم کو براہ راست یوٹیلیٹی کال کافی واضح ہے تو اسے چھوڑ دیں۔
نتیجہ
JavaScript کا ڈھیلا قسم کا نظام اور TypeScript کا کمپائل ٹائم صرف ضمانت دیتا ہے کہ تمام ڈیٹا باؤنڈری پر خلا چھوڑ دیا جائے۔ APIs، درخواست کی باڈیز، مقامی سٹوریج، اور فریق ثالث اسکرپٹس سے خارجی ڈیٹا رن ٹائم پر پہنچ جاتا ہے اس بات کی کوئی گارنٹی نہیں کہ یہ اپنی اعلان کردہ شکل سے مماثل ہوگا۔ یہ چار افادیتیں اس خلا کو پُر کرتی ہیں۔
safeArray، safeString، safeNumberاور safeObject ہر ایک قبول کرتا ہے unknownاصل قسم کی توثیق کرتا ہے اور اگر قدر توقع سے مختلف ہو تو محفوظ متبادل لوٹاتا ہے۔ یہ React اجزاء، Node.js روٹس، کسٹم ہکس، سیاق و سباق فراہم کرنے والوں، اور کسی بھی دوسرے JavaScript یا TypeScript کے سیاق و سباق کے ساتھ کام کرتا ہے جہاں ڈیٹا آپ کی درخواست میں داخل ہوتا ہے۔
پیٹرن سادہ ہے. دائرہ میں تصدیق کریں اور اندر اعتماد کریں۔ کوڈبیس میں داخل ہونے کے مقام پر ڈیٹا کو معمول پر لانے سے ہر چیز کو نیچے کی طرف سے غلط ان پٹ کے خلاف دفاع کرنے کے بجائے اصل کام پر توجہ مرکوز کرنے کی اجازت ملتی ہے۔