বাংলা

টাইপস্ক্রিপ্টের শক্তিশালী ম্যাপড টাইপস এবং কন্ডিশনাল টাইপস-এর একটি সম্পূর্ণ নির্দেশিকা, যেখানে মজবুত ও টাইপ-সেফ অ্যাপ্লিকেশন তৈরির জন্য ব্যবহারিক উদাহরণ এবং উন্নত ব্যবহারের ক্ষেত্র অন্তর্ভুক্ত রয়েছে।

টাইপস্ক্রিপ্টের ম্যাপড টাইপস এবং কন্ডিশনাল টাইপস আয়ত্ত করা

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

ম্যাপড টাইপস কী?

ম্যাপড টাইপস আপনাকে বিদ্যমান টাইপগুলিকে রূপান্তরিত করে নতুন টাইপ তৈরি করার সুযোগ দেয়। এটি একটি বিদ্যমান টাইপের প্রপার্টিগুলির উপর ইটারেট করে এবং প্রতিটি প্রপার্টিতে একটি রূপান্তর প্রয়োগ করে। এটি বিশেষত বিদ্যমান টাইপের বিভিন্ন সংস্করণ তৈরি করার জন্য দরকারী, যেমন সমস্ত প্রপার্টিকে ঐচ্ছিক বা শুধুমাত্র পঠনযোগ্য (read-only) করা।

বেসিক সিনট্যাক্স

একটি ম্যাপড টাইপের সিনট্যাক্স নিম্নরূপ:

type NewType<T> = {
  [K in keyof T]: Transformation;
};

ব্যবহারিক উদাহরণ

প্রপার্টিগুলিকে শুধুমাত্র পঠনযোগ্য (Read-Only) করা

ধরা যাক, আপনার একটি ইন্টারফেস আছে যা একটি ব্যবহারকারীর প্রোফাইল উপস্থাপন করে:

interface UserProfile {
  name: string;
  age: number;
  email: string;
}

আপনি একটি নতুন টাইপ তৈরি করতে পারেন যেখানে সমস্ত প্রপার্টি শুধুমাত্র পঠনযোগ্য:

type ReadOnlyUserProfile = {
  readonly [K in keyof UserProfile]: UserProfile[K];
};

এখন, ReadOnlyUserProfile-এর প্রপার্টিগুলি UserProfile-এর মতোই থাকবে, কিন্তু সেগুলি সবই শুধুমাত্র পঠনযোগ্য হবে।

প্রপার্টিগুলিকে ঐচ্ছিক (Optional) করা

একইভাবে, আপনি সমস্ত প্রপার্টিকে ঐচ্ছিক করতে পারেন:

type OptionalUserProfile = {
  [K in keyof UserProfile]?: UserProfile[K];
};

OptionalUserProfile-এ UserProfile-এর সমস্ত প্রপার্টি থাকবে, কিন্তু প্রতিটি প্রপার্টি ঐচ্ছিক হবে।

প্রপার্টির টাইপ পরিবর্তন করা

আপনি প্রতিটি প্রপার্টির টাইপও পরিবর্তন করতে পারেন। উদাহরণস্বরূপ, আপনি সমস্ত প্রপার্টিকে স্ট্রিং-এ রূপান্তর করতে পারেন:

type StringifiedUserProfile = {
  [K in keyof UserProfile]: string;
};

এই ক্ষেত্রে, StringifiedUserProfile-এর সমস্ত প্রপার্টি string টাইপের হবে।

কন্ডিশনাল টাইপস কী?

কন্ডিশনাল টাইপস আপনাকে এমন টাইপ সংজ্ঞায়িত করতে দেয় যা একটি শর্তের উপর নির্ভর করে। এটি একটি টাইপ কোনো নির্দিষ্ট সীমাবদ্ধতা পূরণ করে কিনা তার উপর ভিত্তি করে টাইপের সম্পর্ক প্রকাশ করার একটি উপায় প্রদান করে। এটি জাভাস্ক্রিপ্টের টারনারি অপারেটরের মতো, কিন্তু এটি টাইপের জন্য।

বেসিক সিনট্যাক্স

একটি কন্ডিশনাল টাইপের সিনট্যাক্স নিম্নরূপ:

T extends U ? X : Y

ব্যবহারিক উদাহরণ

একটি টাইপ স্ট্রিং কিনা তা নির্ধারণ করা

আসুন একটি টাইপ তৈরি করি যা ইনপুট টাইপটি স্ট্রিং হলে string রিটার্ন করে, এবং অন্যথায় number রিটার্ন করে:

type StringOrNumber<T> = T extends string ? string : number;

type Result1 = StringOrNumber<string>;  // string
type Result2 = StringOrNumber<number>;  // number
type Result3 = StringOrNumber<boolean>; // number

একটি ইউনিয়ন থেকে টাইপ এক্সট্র্যাক্ট করা

আপনি একটি ইউনিয়ন টাইপ থেকে একটি নির্দিষ্ট টাইপ এক্সট্র্যাক্ট করতে কন্ডিশনাল টাইপ ব্যবহার করতে পারেন। উদাহরণস্বরূপ, নন-নালেবল টাইপ এক্সট্র্যাক্ট করতে:

type NonNullable<T> = T extends null | undefined ? never : T;

type Result4 = NonNullable<string | null | undefined>; // string

এখানে, যদি T null বা undefined হয়, টাইপটি never হয়ে যায়, যা পরে টাইপস্ক্রিপ্টের ইউনিয়ন টাইপ সরলীকরণ দ্বারা ফিল্টার হয়ে যায়।

টাইপ ইনফার করা

কন্ডিশনাল টাইপগুলি infer কীওয়ার্ড ব্যবহার করে টাইপ ইনফার করার জন্যও ব্যবহার করা যেতে পারে। এটি আপনাকে আরও জটিল টাইপ কাঠামো থেকে একটি টাইপ এক্সট্র্যাক্ট করতে দেয়।

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

function myFunction(x: number): string {
  return x.toString();
}

type Result5 = ReturnType<typeof myFunction>; // string

এই উদাহরণে, ReturnType একটি ফাংশনের রিটার্ন টাইপ এক্সট্র্যাক্ট করে। এটি পরীক্ষা করে যে T এমন একটি ফাংশন কিনা যা কোনো আর্গুমেন্ট নেয় এবং একটি টাইপ R রিটার্ন করে। যদি তাই হয়, এটি R রিটার্ন করে; অন্যথায়, এটি any রিটার্ন করে।

ম্যাপড টাইপস এবং কন্ডিশনাল টাইপস একত্রিত করা

ম্যাপড টাইপস এবং কন্ডিশনাল টাইপসের আসল শক্তি আসে তাদের একত্রিত করার মাধ্যমে। এটি আপনাকে অত্যন্ত নমনীয় এবং অভিব্যক্তিপূর্ণ টাইপ রূপান্তর তৈরি করতে দেয়।

উদাহরণ: ডিপ রিডঅনলি (Deep Readonly)

একটি সাধারণ ব্যবহারের ক্ষেত্র হলো এমন একটি টাইপ তৈরি করা যা একটি অবজেক্টের সমস্ত প্রপার্টি, নেস্টেড প্রপার্টিসহ, শুধুমাত্র পঠনযোগ্য করে তোলে। এটি একটি রিকার্সিভ কন্ডিশনাল টাইপ ব্যবহার করে করা যেতে পারে।

type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};

interface Company {
  name: string;
  address: {
    street: string;
    city: string;
  };
}

type ReadonlyCompany = DeepReadonly<Company>;

এখানে, DeepReadonly রিকার্সিভভাবে সমস্ত প্রপার্টি এবং তাদের নেস্টেড প্রপার্টিগুলিতে readonly মডিফায়ার প্রয়োগ করে। যদি একটি প্রপার্টি একটি অবজেক্ট হয়, তবে এটি সেই অবজেক্টের উপর রিকার্সিভভাবে DeepReadonly কল করে। অন্যথায়, এটি কেবল প্রপার্টিতে readonly মডিফায়ার প্রয়োগ করে।

উদাহরণ: টাইপ দ্বারা প্রপার্টি ফিল্টার করা

ধরা যাক আপনি এমন একটি টাইপ তৈরি করতে চান যা কেবল একটি নির্দিষ্ট টাইপের প্রপার্টি অন্তর্ভুক্ত করে। এটি অর্জন করতে আপনি ম্যাপড টাইপস এবং কন্ডিশনাল টাইপস একত্রিত করতে পারেন।

type FilterByType<T, U> = {
  [K in keyof T as T[K] extends U ? K : never]: T[K];
};

interface Person {
  name: string;
  age: number;
  isEmployed: boolean;
}

type StringProperties = FilterByType<Person, string>; // { name: string; }

type NonStringProperties = Omit<Person, keyof StringProperties>;

এই উদাহরণে, FilterByType T-এর প্রপার্টিগুলির উপর ইটারেট করে এবং প্রতিটি প্রপার্টির টাইপ U-কে এক্সটেন্ড করে কিনা তা পরীক্ষা করে। যদি করে, তবে এটি ফলাফল টাইপে প্রপার্টিটি অন্তর্ভুক্ত করে; অন্যথায়, এটি কী-কে never-এ ম্যাপ করে এটিকে বাদ দেয়। কী রিম্যাপ করার জন্য "as" এর ব্যবহার লক্ষ্য করুন। তারপরে আমরা মূল ইন্টারফেস থেকে স্ট্রিং প্রপার্টিগুলি সরানোর জন্য `Omit` এবং `keyof StringProperties` ব্যবহার করি।

উন্নত ব্যবহারের ক্ষেত্র এবং প্যাটার্ন

বেসিক উদাহরণগুলির বাইরে, ম্যাপড টাইপস এবং কন্ডিশনাল টাইপস আরও উন্নত পরিস্থিতিতে অত্যন্ত কাস্টমাইজযোগ্য এবং টাইপ-সেফ অ্যাপ্লিকেশন তৈরি করতে ব্যবহার করা যেতে পারে।

ডিস্ট্রিবিউটিভ কন্ডিশনাল টাইপস

কন্ডিশনাল টাইপগুলি ডিস্ট্রিবিউটিভ হয় যখন পরীক্ষিত টাইপটি একটি ইউনিয়ন টাইপ হয়। এর মানে হল যে শর্তটি ইউনিয়নের প্রতিটি সদস্যের উপর পৃথকভাবে প্রয়োগ করা হয়, এবং ফলাফলগুলি তখন একটি নতুন ইউনিয়ন টাইপে একত্রিত হয়।

type ToArray<T> = T extends any ? T[] : never;

type Result6 = ToArray<string | number>; // string[] | number[]

এই উদাহরণে, ToArray ইউনিয়ন string | number-এর প্রতিটি সদস্যের উপর পৃথকভাবে প্রয়োগ করা হয়েছে, যার ফলে string[] | number[] হয়েছে। যদি শর্তটি ডিস্ট্রিবিউটিভ না হত, তবে ফলাফলটি (string | number)[] হত।

ইউটিলিটি টাইপস ব্যবহার করা

টাইপস্ক্রিপ্ট বেশ কিছু বিল্ট-ইন ইউটিলিটি টাইপ সরবরাহ করে যা ম্যাপড টাইপস এবং কন্ডিশনাল টাইপসের উপর ভিত্তি করে তৈরি। এই ইউটিলিটি টাইপগুলি আরও জটিল টাইপ রূপান্তরের জন্য বিল্ডিং ব্লক হিসাবে ব্যবহার করা যেতে পারে।

এই ইউটিলিটি টাইপগুলি শক্তিশালী টুল যা জটিল টাইপ ম্যানিপুলেশনকে সহজ করতে পারে। উদাহরণস্বরূপ, আপনি Pick এবং Partial একত্রিত করে এমন একটি টাইপ তৈরি করতে পারেন যা শুধুমাত্র নির্দিষ্ট কিছু প্রপার্টিকে ঐচ্ছিক করে তোলে:

type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;

interface Product {
  id: number;
  name: string;
  price: number;
  description: string;
}

type OptionalDescriptionProduct = Optional<Product, "description">;

এই উদাহরণে, OptionalDescriptionProduct-এ Product-এর সমস্ত প্রপার্টি রয়েছে, কিন্তু description প্রপার্টিটি ঐচ্ছিক।

টেমপ্লেট লিটারেল টাইপস ব্যবহার করা

টেমপ্লেট লিটারেল টাইপস আপনাকে স্ট্রিং লিটারেলের উপর ভিত্তি করে টাইপ তৈরি করতে দেয়। ডাইনামিক এবং অভিব্যক্তিপূর্ণ টাইপ রূপান্তর তৈরি করতে এগুলি ম্যাপড টাইপস এবং কন্ডিশনাল টাইপসের সাথে একত্রে ব্যবহার করা যেতে পারে। উদাহরণস্বরূপ, আপনি এমন একটি টাইপ তৈরি করতে পারেন যা সমস্ত প্রপার্টির নামের আগে একটি নির্দিষ্ট স্ট্রিং যুক্ত করে:

type Prefix<T, P extends string> = {
  [K in keyof T as `${P}${string & K}`]: T[K];
};

interface Settings {
  apiUrl: string;
  timeout: number;
}

type PrefixedSettings = Prefix<Settings, "data_">;

এই উদাহরণে, PrefixedSettings-এর প্রপার্টিগুলি হবে data_apiUrl এবং data_timeout

সেরা অনুশীলন এবং বিবেচ্য বিষয়

উপসংহার

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

আপনার টাইপস্ক্রিপ্ট যাত্রা চালিয়ে যাওয়ার সময়, অফিসিয়াল টাইপস্ক্রিপ্ট ডকুমেন্টেশন, অনলাইন কমিউনিটি এবং ওপেন-সোর্স প্রকল্প সহ উপলব্ধ প্রচুর রিসোর্স ব্যবহার করার কথা মনে রাখবেন। ম্যাপড টাইপস এবং কন্ডিশনাল টাইপসের শক্তিকে আলিঙ্গন করুন, এবং আপনি সবচেয়ে চ্যালেঞ্জিং টাইপ-সম্পর্কিত সমস্যাগুলি মোকাবেলা করার জন্য সুসজ্জিত হবেন।