দৈনন্দিন কোডের জন্য TypeScript জেনেরিকস: একটি ব্যবহারিক গাইড
আপনি এমন একটি ফাংশন লিখছেন যা যেকোনো টাইপের সাথে কাজ করে, কিন্তু TypeScript বারবার any নিয়ে অভিযোগ করছে। অথবা আপনি বিভিন্ন টাইপ হ্যান্ডেল করার জন্য একই ফাংশন তিনবার কপি করেছেন। জেনেরিকস এটি সমাধান করে—এগুলি আপনাকে একাধিক টাইপের সাথে কাজ করে এমন কোড লিখতে দেয় যখন টাইপ সেফটি বজায় থাকে। কিন্তু অনেক ডেভেলপার হয় এগুলি এড়িয়ে চলেন বা অতিরিক্ত ব্যবহার করেন। এই গাইডটি দেখায় কীভাবে মাথাব্যথা ছাড়াই দৈনন্দিন কোডে জেনেরিকস ব্যবহার করবেন।
জেনেরিকস কী এবং কেন আপনার এটির যত্ন নেওয়া উচিত?
জেনেরিকস হল টাইপ প্যারামিটারাইজ করার একটি উপায়। string বা number এর মতো একটি টাইপ হার্ডকোড করার পরিবর্তে, আপনি একটি টাইপ ভেরিয়েবল (প্রায়শই T) ব্যবহার করেন যা ফাংশন বা ক্লাস ব্যবহার করার সময় একটি কংক্রিট টাইপ দিয়ে প্রতিস্থাপিত হয়।
এটি কেন গুরুত্বপূর্ণ? কারণ এটি আপনাকে পুনরায় ব্যবহারযোগ্য কোড লিখতে দেয় যা টাইপ-সেফ থাকে। জেনেরিকস ছাড়া, আপনি হয় কোড ডুপ্লিকেট করবেন বা any ব্যবহার করবেন, যা TypeScript-এর উদ্দেশ্যকে ব্যর্থ করে।
জেনেরিক ফাংশন: বিল্ডিং ব্লক
একটি সহজ উদাহরণ দিয়ে শুরু করা যাক। ধরুন আপনি একটি ফাংশন চান যা একটি অ্যারের প্রথম উপাদান ফেরত দেয়।
function firstElement(arr: any[]): any {
return arr[0];
}
এটি কাজ করে, কিন্তু আপনি টাইপ তথ্য হারান। যদি আপনি স্ট্রিংগুলির একটি অ্যারে পাস করেন, রিটার্ন টাইপ any, string নয়। এখন জেনেরিকস সহ:
function firstElement<T>(arr: T[]): T | undefined {
return arr[0];
}
এখন TypeScript জানে যে যদি আপনি একটি string[] পাস করেন, আপনি একটি string | undefined ফেরত পাবেন। টাইপ সংরক্ষিত হয়।
আপনি একাধিক টাইপ প্যারামিটারও ব্যবহার করতে পারেন:
function pair<A, B>(a: A, b: B): [A, B] {
return [a, b];
}
জেনেরিক ইন্টারফেস এবং টাইপ অ্যালিয়াস
জেনেরিকস শুধুমাত্র ফাংশনে সীমাবদ্ধ নয়। আপনি নমনীয় ডেটা স্ট্রাকচার বর্ণনা করতে জেনেরিক ইন্টারফেস এবং টাইপ অ্যালিয়াস তৈরি করতে পারেন।
interface Box<T> {
value: T;
}
const stringBox: Box<string> = { value: "hello" };
const numberBox: Box<number> = { value: 42 };
এটি API প্রতিক্রিয়ার জন্য বিশেষভাবে উপযোগী। প্রতিটি এন্ডপয়েন্টের জন্য একটি নতুন ইন্টারফেস সংজ্ঞায়িত করার পরিবর্তে, আপনি একটি জেনেরিক ApiResponse<T> সংজ্ঞায়িত করতে পারেন:
interface ApiResponse<T> {
data: T;
status: number;
}
type User = { id: number; name: string };
const response: ApiResponse<User> = {
data: { id: 1, name: "Alice" },
status: 200,
};
জেনেরিক কনস্ট্রেইন্ট: নিয়ম যোগ করা
কখনও কখনও আপনি সীমাবদ্ধ করতে চান যে আপনার জেনেরিকের সাথে কোন টাইপগুলি ব্যবহার করা যেতে পারে। এখানেই কনস্ট্রেইন্ট আসে। extends কীওয়ার্ড ব্যবহার করে প্রয়োজন যে টাইপের নির্দিষ্ট বৈশিষ্ট্য রয়েছে।
function getLength<T extends { length: number }>(item: T): number {
return item.length;
}
getLength("hello"); // ঠিক আছে
getLength([1, 2, 3]); // ঠিক আছে
getLength(42); // ত্রুটি: number-এ length নেই
কনস্ট্রেইন্ট আপনার জেনেরিকসকে আরও পূর্বানুমেয় করে তোলে এবং রানটাইম ত্রুটি প্রতিরোধ করে।
জেনেরিক ক্লাস
ক্লাসগুলিও জেনেরিক হতে পারে। এটি স্ট্যাক, কিউ বা রিপোজিটরির মতো ডেটা স্ট্রাকচারের জন্য সুবিধাজনক।
class Stack<T> {
private items: T[] = [];
push(item: T): void {
this.items.push(item);
}
pop(): T | undefined {
return this.items.pop();
}
}
const numberStack = new Stack<number>();
numberStack.push(1);
numberStack.push(2);
const top = numberStack.pop(); // number | undefined
কখন জেনেরিকস ব্যবহার করবেন (এবং কখন নয়)
জেনেরিকস শক্তিশালী, কিন্তু অতিরিক্ত ব্যবহার করলে কোড পড়া কঠিন হতে পারে। এখানে একটি দ্রুত গাইড:
| জেনেরিকস ব্যবহার করুন যখন | জেনেরিকস এড়িয়ে চলুন যখন |
|---|---|
| আপনাকে টাইপ সম্পর্ক সংরক্ষণ করতে হবে | একটি সাধারণ ইউনিয়ন টাইপ বা any যথেষ্ট |
| আপনি পুনরায় ব্যবহারযোগ্য ইউটিলিটি লিখছেন | টাইপ সর্বদা একই থাকে |
| আপনি কোড ডুপ্লিকেশন এড়াতে চান | এটি কোড বোঝা কঠিন করে তোলে |
একটি ভাল নিয়ম: যদি আপনি দেখেন যে আপনি একাধিক টাইপের জন্য একই লজিক লিখছেন, জেনেরিকস বিবেচনা করুন। যদি আপনি একটি তৃতীয় টাইপ প্যারামিটার যোগ করেন এবং কেউ এটি বোঝে না, পিছিয়ে যান।
সাধারণ প্যাটার্ন এবং সেরা অনুশীলন
- টাইপ প্যারামিটারের জন্য বর্ণনামূলক নাম ব্যবহার করুন। সহজ ক্ষেত্রে
Tঠিক আছে, কিন্তুTDataবাTResponseআরও স্পষ্ট হতে পারে। anyএর চেয়ে কনস্ট্রেইন্ট পছন্দ করুন। যদি আপনার নমনীয়তা প্রয়োজন হয়, একটি ন্যূনতম আকার প্রয়োগ করতেextendsব্যবহার করুন।- ডিফল্ট টাইপ প্যারামিটার ব্যবহার করুন। আপনি একটি ডিফল্ট প্রদান করতে পারেন:
<T = string>। - ইউটিলিটি টাইপের সাথে জেনেরিকস ব্যবহার করুন। TypeScript-এর অন্তর্নির্মিত
Partial<T>,Readonly<T>, এবংRecord<K, V>সবই জেনেরিক।
বাস্তব-বিশ্বের উদাহরণ: একটি জেনেরিক API ক্লায়েন্ট
আসুন একটি ব্যবহারিক উদাহরণ দিয়ে এটি একসাথে করি: একটি সাধারণ API ক্লায়েন্ট যা ডেটা আনে এবং একটি টাইপড প্রতিক্রিয়া প্রদান করে।
async function fetchData<T>(url: string): Promise<T> {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json() as Promise<T>;
}
interface Post {
userId: number;
id: number;
title: string;
body: string;
}
async function main() {
const post = await fetchData<Post>("https://jsonplaceholder.typicode.com/posts/1");
console.log(post.title); // string
}
এই প্যাটার্নটি ফ্রন্টএন্ড কোডে সাধারণ। আপনি প্রতিটি এন্ডপয়েন্টের জন্য নিজেকে পুনরাবৃত্তি না করে টাইপ সুরক্ষা পান।
সাধারণ জিজ্ঞাসা
TypeScript-এ <T> সিনট্যাক্সের অর্থ কী?
<T> একটি টাইপ প্যারামিটার ঘোষণা করে। এটি একটি টাইপের জন্য একটি প্লেসহোল্ডার যা ফাংশন, ইন্টারফেস বা ক্লাস ব্যবহার করার সময় নির্দিষ্ট করা হবে। আপনি এটির যেকোনো নাম দিতে পারেন, কিন্তু একটি একক টাইপের জন্য T প্রচলিত।
আমি কি একাধিক জেনেরিক টাইপ প্যারামিটার ব্যবহার করতে পারি?
হ্যাঁ। আপনি যতগুলি প্রয়োজন ততগুলি কমা দ্বারা পৃথক করে সংজ্ঞায়িত করতে পারেন: <T, U, V>। আপনার কোড পাঠযোগ্য রাখতে বর্ণনামূলক নাম ব্যবহার করুন।
আমি কীভাবে একটি জেনেরিককে শুধুমাত্র অবজেক্ট গ্রহণ করতে সীমাবদ্ধ করব?
T extends object ব্যবহার করুন। এটি নিশ্চিত করে যে T একটি অবজেক্ট টাইপ এবং string বা number এর মতো প্রিমিটিভ নয়। আপনি নির্দিষ্ট আকারেও সীমাবদ্ধ করতে পারেন, যেমন T extends { id: number }।
জেনেরিকস রক্ষণাবেক্ষণযোগ্য TypeScript লেখার একটি মূল অংশ। যদি আপনি JSON ডেটা নিয়ে কাজ করছেন এবং এটি দ্রুত যাচাই বা ফরম্যাট করতে চান, আপনার API প্রতিক্রিয়াগুলি সুন্দরভাবে প্রিন্ট এবং পরিদর্শন করতে আমাদের JSON Formatter ব্যবহার করে দেখুন।