3.5 জেনেরিকস

 

TypeScript-এ, জেনেরিক্স মূলত এক ধরনের টুল যা আপনাকে পুনরায় ব্যবহারযোগ্য কোড উপাদান তৈরি করতে সক্ষম করে, যা একটি একক টাইপ পরিবর্তে বেশ কয়েকটি টাইপের সাথে কাজ করে। এটি ব্যবহারকারীদের এই component ব্যবহার করতে এবং তাদের নিজস্ব প্রকারগুলি ব্যবহার করতে দেয়৷

এই লিখাটি জেনেরিকগুলি কী এবং কীভাবে সেগুলি এই আইটেমগুলির জন্য ব্যবহার করা যেতে পারে তা ব্যাখ্যা করবে।

সাধারণ ভাষায় জেনেরিকের পিছনে ধারণাটি প্রদর্শন করতে, নিম্নলিখিত ফাংশন, identity() টি লক্ষ্য করুন , যা কেবল একটি আর্গুমেন্ট নেয় এবং রিটার্ন করে :

function identity(arg: number): number {
   return arg;
}

 

আমাদের identity() ফাংশনের উদ্দেশ্য হল আমরা যে আর্গুমেন্টটি পাস করি তা ফেরত দেওয়া। এখানে সমস্যা হল যে আমরা আর্গুমেন্ট এবং রিটার্ন টাইপ উভয়ের জন্যই নাম্বার টাইপ বরাদ্দ করেছি, ফাংশনটিকে শুধুমাত্র এই প্রিমিটিভ টাইপের জন্য ব্যবহারযোগ্য, ফাংশনটি খুব বেশি প্রসারণযোগ্য, বা জেনেরিক নয়, আমরা এটি চাই?

আমরা প্রকৃতপক্ষে number কে any তে অদলবদল করতে পারি, তবে প্রক্রিয়াটিতে আমরা কোন টাইপ রিটার্ন করা উচিত তা নির্ধারণ করার ক্ষমতা হারাচ্ছি।

কি করলে identity() ফাংশন নির্দিষ্ট টাইপ এর জন্য কাজ করবে এবং জেনেরিক ব্যবহার করে এটি ঠিক করতে পারে। নীচে একই ফাংশন রয়েছে, এবার একটি টাইপ ভেরিয়েবল সহ:

function identities<T>(arg: T): T {
   return arg;
}

 

ফাংশনের নামের পরে আমরা একটি টাইপ ভেরিয়েবল, T, কোণীয় বন্ধনীতে অন্তর্ভুক্ত করেছি <>. আমরা identify() ফাংশন এর মধ্যে যে টাইপ প্রবেশ করানোর চেষ্টা করছি T এখানে একটি প্লেসহোল্ডার হিসেবে কাজ করবে, এবং arg কে number টাইপ এর পরিবর্তে সঠিক টাইপ এসাইন করবে : সংখ্যার পরিবর্তে , T এখন টাইপ হিসেবে কাজ করছে।

নোট: টাইপ ভেরিয়েবলকে টাইপ প্যারামিটার এবং জেনেরিক প্যারামিটার হিসাবেও উল্লেখ করা হয়। এই নিবন্ধটি অফিসিয়াল টাইপস্ক্রিপ্ট ডকুমেন্টেশনের সাথে মিল রেখে টাইপ ভেরিয়েবল শব্দটি ব্যবহার করতে বেছে নেয়া হয়েছে।

T এর মানে Type, এবং সাধারণত জেনেরিক সংজ্ঞায়িত করার সময় প্রথম প্রকার ভেরিয়েবলের নাম হিসেবে ব্যবহৃত হয়। কিন্তু বাস্তবে T যে কোনো বৈধ নাম দিয়ে প্রতিস্থাপন করা যেতে পারে। শুধু তাই নয়, আমরা শুধুমাত্র একটি টাইপ ভেরিয়েবলের মধ্যে সীমাবদ্ধ নই — আমরা যে পরিমাণ সংজ্ঞায়িত করতে চাই তা আনতে পারি। আসুন T এর পাশে U-এর সাথে পরিচয় করিয়ে দেই এবং আমাদের ফাংশনটি প্রসারিত করি:

function identities<T, U>(arg1: T, arg2: U): T {
   return arg1;
}

 

এখন আমাদের কাছে একটি identities() ফাংশন রয়েছে যা U টাইপ ভেরিয়েবল যোগ করে দুটি জেনেরিক টাইপকে একসেপ্ট করে,কিন্তু রিটার্ন টাইপ T থেকে যায়। আমাদের ফাংশনটি এখন দুটি টাইপ গ্রহণ করে, এবং আমাদের arg1 প্যারামিটারের মতো একই টাইপ ফেরত দেয়।

কিন্তু যদি আমরা উভয় টাইপ এর সাথে একটি object রিটার্ন করতে চাই? এটি করার একাধিক উপায় আছে, আমরা একটি tuple দিয়ে তা করতে পারি, আমাদের জেনেরিক টাইপ tuple কে এইভাবে প্রদান করে:

function identities<T, U>(arg1: T, arg2: U): [T , U ] {
   return [arg1,arg2];
}

 

জেনেরিক ইন্টারফেস

এটি আমাদেরকে জেনেরিক ইন্টারফেসে নিয়ে আসে; আসুন একটি জেনেরিক আইডেন্টিটিস ইন্টারফেস তৈরি করি identities() :

interface Identities<V, W> {
   id1: V,
   id2: W
}

 

আমি এখানে আমাদের টাইপ ভেরিয়েবল হিসাবে V এবং W ব্যবহার করেছি যে কোনও অক্ষর (বা বৈধ বর্ণানুক্রমিক নামের সংমিশ্রণ) বৈধ প্রকারগুলি প্রদর্শন করতে – আপনি এগুলিকে কী বলছেন তার কোনও তাৎপর্য নেই৷ আমরা এখন এই ইন্টারফেসটিকে Identities() ফাংশন এর রিটার্ন টাইপ হিসাবে প্রয়োগ করতে পারি, এটি মেনে চলার জন্য আমাদের রিটার্ন টাইপ পরিবর্তন করি । আরও স্পষ্টীকরণের জন্য আর্গুমেন্ট এবং তাদের প্রকারগুলি console.log করি:

function identities<T, U> (arg1: T, arg2: U): Identities<T, U> {
   console.log(arg1 + ": " + typeof (arg1));
   console.log(arg2 + ": " + typeof (arg2));
   let identities: Identities<T, U> = {
    id1: arg1,
    id2: arg2
  };
  return identities;
}

 

জেনেরিক ক্লাস

ক্লাস এর প্রোপারটিস (properties) এন্ড মেথোডস (methods) অর্থে আমরা একটি ক্লাস জেনেরিক করতে পারি । একটি জেনেরিক ক্লাস নিশ্চিত করে যে নির্দিষ্ট ডেটা টাইপগুলা সম্পূর্ণ ক্লাস জুড়ে ধারাবাহিকভাবে ব্যবহার করা হয়। উদাহরণ স্বরূপ, আপনি হয়তো লক্ষ্য করেছেন যে নিম্নলিখিত কনভেনশনটি React Typescript প্রজেক্টে ব্যবহার করা হচ্ছে:

type Props = {
   className?: string
   ...
};
type State = {
   submitted?: bool
   ...
};
class MyComponent extends React.Component<Props, State> {
   ...
}

 

একটি কম্পোনেন্টের প্রপস এবং স্টেট টাইপ-সেফ তা নিশ্চিত করতে আমরা এখানে React Component সাথে জেনেরিক ব্যবহার করছি।

আমরা এতক্ষন যা বুঝেছি ক্লাস জেনেরিক সিনট্যাক্স একইরকম . নিম্নলিখিত ক্লাসটি বিবেচনা করুন যা একজন প্রোগ্রামারের প্রোফাইলের জন্য একাধিক টাইপ প্রদান করে:

class Programmer<T> {
   
   private languageName: string;
   private languageInfo: T;
   constructor(lang: string) {
      this.languageName = lang;
   }
   ...
}
let programmer1 = 
   new Programmer<Language.Typescript>("Typescript");
let programmer2 = 
   new Programmer<Language.Rust>("Rust");

 

আমাদের প্রোগ্রামার ক্লাসের জন্য, প্রোগ্রামিং ল্যাঙ্গুয়েজ মেটা ডেটার জন্য T হল একটি টাইপ ভেরিয়েবল, যা আমাদেরকে languageInfo প্রপার্টিতে বিভিন্ন ধরনের ভাষা নির্ধারণ করতে দেয়। প্রতিটি ভাষার অনিবার্যভাবে আলাদা মেটাডেটা থাকবে, এবং তাই আলাদা ধরনের প্রয়োজন।

টাইপ আর্গুমেন্ট ইনফারেন্স

উপরের উদাহরণে আমরা নিম্নলিখিত সিনট্যাক্স প্যাটার্ন সহ একটি নতুন Programmer ক্লাসে ইনস্ট্যান্টিয়েট করার সময় নির্দিষ্ট ভাষার প্রকারের সাথে কোণীয় বন্ধনী ব্যবহার করেছি:

let myObj = new className<Type>("args");

ক্লাসের ইনস্ট্যান্টিয়েটিং জন্য, আমরা আমাদের প্রোগ্রামারকে কোন ভাষার ধরন বরাদ্দ করতে চাই তা অনুমান করার জন্য কম্পাইলার তেমন কিছু করতে পারে না; এখানে টাইপ পাস করা বাধ্যতামূলক। যাইহোক, ফাংশনগুলির সাথে, কম্পাইলার অনুমান করতে পারে যে আমরা আমাদের জেনেরিকগুলি কোন ধরণের হতে চাই — এবং এটিই সবচেয়ে সাধারণ উপায় যা ডেভেলপাররা জেনেরিক ব্যবহার করতে বেছে নেয়।

identities() ফাংশন কে আমরা আবার উদাহরণ হিসাবে নিতে পারি ।

let result = identities<string, number>("argument 1", 100);

ফাংশন এর ক্ষেত্রে এর দরকার নাই কারণ কম্পাইলার ফাংশন এর জন্য টাইপ অনুমান করতে পারে। এতে আমাদের কোড পরিস্কার রাখা যায়।

let result = identities("argument 1", 100);

কিন্তু ক্লাস এর জন্য এটি বাদ্ধতামূলক।