TypeScript ব্যাবহার করা

TypeScript একটি জনপ্রিয় উপায় যা JavaScript কোডবেসে টাইপ ডিফিনিশন যোগ করতে ব্যবহৃত হয়। আউট অফ দ্য বক্স, TypeScript JSX সমর্থন করে এবং আপনি আপনার প্রকল্পে @types/react এবং @types/react-dom যোগ করে পূর্ণ React ওয়েব সমর্থন পেতে পারেন।

ইন্সটলেশন

সব প্রোডাকশন-গ্রেড React ফ্রেমওয়ার্ক TypeScript ব্যবহারের সমর্থন দেয়। ইনস্টলেশনের জন্য ফ্রেমওয়ার্ক স্পেসিফিক গাইড অনুসরণ করুন:

বিদ্যমান React প্রকল্পে টাইপস্ক্রিপ্ট যোগ করা

React-এর সর্বশেষ ভার্ষন টাইপ ডেফিনিশন ইনস্টল করতে:

Terminal
npm install @types/react @types/react-dom

নিম্নলিখিত কম্পাইলার বিকল্পগুলি আপনার tsconfig.json ফাইলে সেট করতে হবে:

  1. lib তে dom অন্তর্ভুক্ত থাকতে হবে। (নোট: যদি কোনো lib বিকল্প নির্দিষ্ট না করা হয়, তবে dom ডিফল্টভাবে অন্তর্ভুক্ত হয়।)
  2. jsx একটি বৈধ অপশনে সেট করতে হবে। অধিকাংশ অ্যাপ্লিকেশনের জন্য preserve যথেষ্ট হবে।
    যদি আপনি একটি লাইব্রেরি প্রকাশ করছেন, তবে কোন মান নির্বাচন করতে হবে তা জানতে jsx ডকুমেন্টেশন পরামর্শ করুন।

React কম্পোনেন্টের সাথে টাইপস্ক্রিপ্ট

খেয়াল করুন

প্রত্যেক ফাইল যেখানে JSX থাকে, সেখানে .tsx ফাইল এক্সটেনশন ব্যবহার করতে হবে। এটি টাইপস্ক্রিপ্টকে জানায় যে এই ফাইলে JSX আছে।

React এর সাথে টাইপস্ক্রিপ্ট ব্যবহার করা বেশিরভাগ ক্ষেত্রেই জাভাস্ক্রিপ্টের সাথে React ব্যবহারের মতো। মূল পার্থক্য হলো আপনার কম্পোনেন্টের প্রপসে টাইপ যোগ করতে পারেন। এই টাইপস সম্পূর্ণতার যাচাই এবং এডিটরে ইনলাইন ডকুমেন্টেশন প্রদান করতে ব্যবহৃত হতে পারে।

Quick Start গাইড থেকে MyButton কম্পোনেন্ট নেওয়ার মাধ্যমে, আমরা বোতামের জন্য title বর্ণনা করতে একটি টাইপ যোগ করতে পারি:

function MyButton({ title }: { title: string }) {
  return (
    <button>{title}</button>
  );
}

export default function MyApp() {
  return (
    <div>
      <h1>Welcome to my app</h1>
      <MyButton title="I'm a button" />
    </div>
  );
}

খেয়াল করুন

এই স্যান্ডবক্সগুলো টাইপস্ক্রিপ্ট কোড হ্যান্ডেল করতে পারে, কিন্তু টাইপ-চেকার চালায় না। এর অর্থ হলো, আপনি টাইপস্ক্রিপ্ট স্যান্ডবক্সগুলো পরিবর্তন করতে পারেন, কিন্তু টাইপ এরর বা সতর্কতা পাবেন না। টাইপ-চেকিং পেতে TypeScript Playground বা অন্য অনলাইন স্যান্ডবক্স ব্যবহার করতে পারেন।

এই ইনলাইন সিনট্যাক্স কম্পোনেন্টের জন্য টাইপ প্রদান করার সহজতম উপায়, যদিও একাধিক ক্ষেত্র থাকলে এটি জটিল হতে পারে। পরিবর্তে, আপনি একটি interface বা type ব্যবহার করতে পারেন:

interface MyButtonProps {
  /** The text to display inside the button */
  title: string;
  /** Whether the button can be interacted with */
  disabled: boolean;
}

function MyButton({ title, disabled }: MyButtonProps) {
  return (
    <button disabled={disabled}>{title}</button>
  );
}

export default function MyApp() {
  return (
    <div>
      <h1>Welcome to my app</h1>
      <MyButton title="I'm a disabled button" disabled={true}/>
    </div>
  );
}

আপনার কম্পোনেন্টের প্রপস বর্ণনা করার টাইপটি যতটা সহজ বা জটিল প্রয়োজন ততটাই হতে পারে, তবে এটি একটি type বা interface দিয়ে বর্ণনা করা একটি অবজেক্ট টাইপ হওয়া উচিত। TypeScript কীভাবে অবজেক্ট বর্ণনা করে তা শিখতে Object Types দেখুন, তবে আপনি Union Types ব্যবহার করতেও আগ্রহী হতে পারেন, যা একটি প্রপকে কয়েকটি ভিন্ন টাইপের মধ্যে একটির বর্ণনা করতে সক্ষম করে এবং Creating Types from Types গাইডটি আরও উন্নত ব্যবহারের জন্য।

হুকের উদাহরণ

@types/react থেকে টাইপ ডিফিনিশনগুলি বিল্ট-ইন হুকগুলোর জন্য টাইপ অন্তর্ভুক্ত করে, তাই আপনি আপনার কম্পোনেন্টে অতিরিক্ত সেটআপ ছাড়াই সেগুলি ব্যবহার করতে পারেন। এগুলি আপনার কম্পোনেন্টে যে কোড আপনি লেখেন তার প্রতি মনোযোগ দিয়ে তৈরি করা হয়েছে, তাই আপনি অনেক সময় inferred types পাবেন এবং আদর্শভাবে টাইপ সরবরাহ করার সূক্ষ্ম বিষয়গুলো পরিচালনা করার প্রয়োজন পড়বে না।

তবে, আমরা হুকগুলোর জন্য টাইপ প্রদান করার কয়েকটি উদাহরণ দেখতে পারি।

useState

useState হুক প্রাথমিক অবস্থার জন্য দেওয়া মানটি পুনঃব্যবহার করবে এটি নির্ধারণ করতে যে মানের টাইপটি কী হওয়া উচিত। উদাহরণস্বরূপ:

// Infer the type as "boolean"
const [enabled, setEnabled] = useState(false);

enabled এর জন্য boolean টাইপ নির্ধারণ করবে, এবং setEnabled হবে একটি ফাংশন যা বা একটি boolean আর্গুমেন্ট গ্রহণ করে, অথবা একটি ফাংশন যা একটি boolean ফেরত দেয়। যদি আপনি অবস্থার জন্য স্পষ্টভাবে একটি টাইপ প্রদান করতে চান, তবে আপনি useState কলের সাথে একটি টাইপ আর্গুমেন্ট প্রদান করে এটি করতে পারেন:

// Explicitly set the type to "boolean"
const [enabled, setEnabled] = useState<boolean>(false);

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

type Status = "idle" | "loading" | "success" | "error";

const [status, setStatus] = useState<Status>("idle");

অথবা, State গঠন করার নীতির অনুসারে, আপনি সম্পর্কিত অবস্থাগুলিকে একটি অবজেক্ট হিসাবে গ্রুপ করতে পারেন এবং অবজেক্ট টাইপের মাধ্যমে বিভিন্ন সম্ভাবনাগুলি বর্ণনা করতে পারেন:

type RequestState =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success', data: any }
| { status: 'error', error: Error };

const [requestState, setRequestState] = useState<RequestState>({ status: 'idle' });

useReducer

useReducer হুক একটি আরও জটিল হুক যা একটি রিডিউসার ফাংশন এবং একটি প্রাথমিক অবস্থা নেয়। রিডিউসার ফাংশনের জন্য টাইপগুলি প্রাথমিক অবস্থাটি থেকে ইনফার করা হয়। আপনি ঐচ্ছিকভাবে useReducer কলের সাথে একটি টাইপ আর্গুমেন্ট প্রদান করে অবস্থার জন্য একটি টাইপ প্রদান করতে পারেন, তবে প্রায়শই এটি প্রাথমিক অবস্থার উপর টাইপ সেট করা ভাল:

import {useReducer} from 'react';

interface State {
   count: number 
};

type CounterAction =
  | { type: "reset" }
  | { type: "setCount"; value: State["count"] }

const initialState: State = { count: 0 };

function stateReducer(state: State, action: CounterAction): State {
  switch (action.type) {
    case "reset":
      return initialState;
    case "setCount":
      return { ...state, count: action.value };
    default:
      throw new Error("Unknown action");
  }
}

export default function App() {
  const [state, dispatch] = useReducer(stateReducer, initialState);

  const addFive = () => dispatch({ type: "setCount", value: state.count + 5 });
  const reset = () => dispatch({ type: "reset" });

  return (
    <div>
      <h1>Welcome to my counter</h1>

      <p>Count: {state.count}</p>
      <button onClick={addFive}>Add 5</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}

আমরা TypeScript কয়েকটি গুরুত্বপূর্ণ স্থানে ব্যবহার করছি:

  • interface State রিডিউসারের স্টেটের আকৃতি বর্ণনা করে।
  • type CounterAction বিভিন্ন অ্যাকশনগুলো বর্ণনা করে যা রিডিউসারে পাঠানো যেতে পারে।
  • const initialState: State প্রাথমিক স্টেটের জন্য টাইপ প্রদান করে এবং useReducer-এর ডিফল্ট টাইপ হিসেবেও ব্যবহৃত হয়।
  • stateReducer(state: State, action: CounterAction): State রিডিউসার ফাংশনের আর্গুমেন্ট এবং রিটার্ন ভ্যালুর টাইপ সেট করে।

প্রাথমিক স্টেটে টাইপ নির্ধারণের আরেকটি স্পষ্ট পদ্ধতি হলো useReducer-এ টাইপ আর্গুমেন্ট ব্যবহার করা:

import { stateReducer, State } from './your-reducer-implementation';

const initialState = { count: 0 };

export default function App() {
const [state, dispatch] = useReducer<State>(stateReducer, initialState);
}

useContext

useContext হুক হল কম্পোনেন্ট গাছের নিচে ডেটা পাঠানোর একটি কৌশল যা কম্পোনেন্টের মাধ্যমে প্রপ্স প্রেরণের প্রয়োজন নেই। এটি একটি প্রোভাইডার কম্পোনেন্ট তৈরি করে ব্যবহার করা হয় এবং প্রায়ই একটি হুক তৈরি করে একটি শিশু কম্পোনেন্টে মানটি ব্যবহার করতে হয়।

কনটেক্সট দ্বারা প্রদত্ত মানের টাইপটি createContext কলের সাথে দেওয়া মান থেকে ইনফার করা হয়:

import { createContext, useContext, useState } from 'react';

type Theme = "light" | "dark" | "system";
const ThemeContext = createContext<Theme>("system");

const useGetTheme = () => useContext(ThemeContext);

export default function MyApp() {
  const [theme, setTheme] = useState<Theme>('light');

  return (
    <ThemeContext.Provider value={theme}>
      <MyComponent />
    </ThemeContext.Provider>
  )
}

function MyComponent() {
  const theme = useGetTheme();

  return (
    <div>
      <p>Current theme: {theme}</p>
    </div>
  )
}

এই কৌশলটি যখন আপনার কাছে একটি ডিফল্ট মান থাকে যা যুক্তিযুক্ত হয় তখন কাজ করে—কিন্তু মাঝে মাঝে এমন পরিস্থিতি থাকতে পারে যখন আপনার ডিফল্ট মান নেই, এবং সেক্ষেত্রে null একটি যুক্তিযুক্ত ডিফল্ট মান হতে পারে। তবে, টাইপ সিস্টেমকে আপনার কোড বোঝাতে দিতে, আপনাকে createContext-এ স্পষ্টভাবে ContextShape | null সেট করতে হবে।

এটি কনটেক্সট কনজ্যুমারদের জন্য টাইপে | null বাদ দিতে হবে বলে একটি সমস্যা সৃষ্টি করে। আমাদের পরামর্শ হল, হুকটি তার অস্তিত্বের জন্য একটি রানটাইম চেক করতে পারে এবং যখন এটি উপস্থিত না থাকে তখন একটি এরোর থ্রো করে:

import { createContext, useContext, useState, useMemo } from 'react';

// This is a simpler example, but you can imagine a more complex object here
type ComplexObject = {
kind: string
};

// The context is created with `| null` in the type, to accurately reflect the default value.
const Context = createContext<ComplexObject | null>(null);

// The `| null` will be removed via the check in the Hook.
const useGetComplexObject = () => {
const object = useContext(Context);
if (!object) { throw new Error("useGetComplexObject must be used within a Provider") }
return object;
}

export default function MyApp() {
const object = useMemo(() => ({ kind: "complex" }), []);

return (
<Context.Provider value={object}>
<MyComponent />
</Context.Provider>
)
}

function MyComponent() {
const object = useGetComplexObject();

return (
<div>
<p>Current object: {object.kind}</p>
</div>
)
}

useMemo

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

// The type of visibleTodos is inferred from the return value of filterTodos
const visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]);

useCallback

useCallback হুক একটি ফাংশনের স্থিতিশীল রেফারেন্স সরবরাহ করে যতক্ষণ দ্বিতীয় প্যারামিটারে পাস করা নির্ভরশীল উপাদানগুলো একই থাকে। useMemo-র মতো, ফাংশনের টাইপ প্রথম প্যারামিটারে দেওয়া ফাংশনের রিটার্ন মান থেকে অনুমান করা হয়, তবে আপনি চাইলে হুকে একটি টাইপ আর্গুমেন্ট দিয়ে এটিকে আরও স্পষ্ট করতে পারেন।

const handleClick = useCallback(() => {
// ...
}, [todos]);

টাইপস্ক্রিপ্টের স্ট্রিক্ট মোডে কাজ করার সময়, useCallback-এর জন্য কলব্যাক ফাংশনের প্যারামিটারগুলোর টাইপ যোগ করতে হয়। এর কারণ হলো, কলব্যাক ফাংশনের টাইপটি মূলত ফাংশনের রিটার্ন ভ্যালু থেকে নির্ণয় করা হয়, এবং প্যারামিটার ছাড়া টাইপটি সম্পূর্ণভাবে বোঝা যায় না।

আপনার কোড-স্টাইল পছন্দের ওপর নির্ভর করে, আপনি *EventHandler ফাংশনগুলো ব্যবহার করতে পারেন React টাইপ থেকে। এটি আপনাকে একই সাথে কলব্যাক ফাংশন ডিফাইন এবং ইভেন্ট হ্যান্ডলারটির টাইপ প্রদান করতে সহায়তা করে।

import { useState, useCallback } from 'react';

export default function Form() {
const [value, setValue] = useState("Change me");

const handleChange = useCallback<React.ChangeEventHandler<HTMLInputElement>>((event) => {
setValue(event.currentTarget.value);
}, [setValue])

return (
<>
<input value={value} onChange={handleChange} />
<p>Value: {value}</p>
</>
);
}

উপকারী টাইপসমূহ

@types/react প্যাকেজ থেকে আসা একটি বিস্তৃত টাইপ সেট রয়েছে, এটি পড়া উপকারী যখন আপনি বুঝতে পারবেন যে React এবং TypeScript কীভাবে взаимодействуют। আপনি এগুলি DefinitelyTyped-এ React-এর ফোল্ডারে খুঁজে পেতে পারেন। এখানে আমরা কয়েকটি সাধারণ টাইপ নিয়ে আলোচনা করব।

DOM ইভেন্টসমূহ

React-এ DOM ইভেন্ট নিয়ে কাজ করার সময়, সাধারণত ইভেন্ট হ্যান্ডলার থেকে ইভেন্টের টাইপটি নির্ধারণ করা যায়। তবে, যখন আপনি একটি ফাংশনকে ইভেন্ট হ্যান্ডলারে পাস করার জন্য বের করতে চান, তখন আপনাকে স্পষ্টভাবে ইভেন্টের টাইপ সেট করতে হবে।

import { useState } from 'react';

export default function Form() {
  const [value, setValue] = useState("Change me");

  function handleChange(event: React.ChangeEvent<HTMLInputElement>) {
    setValue(event.currentTarget.value);
  }

  return (
    <>
      <input value={value} onChange={handleChange} />
      <p>Value: {value}</p>
    </>
  );
}

React টাইপগুলিতে অনেক ধরনের ইভেন্ট দেওয়া হয়েছে—পূর্ণ তালিকা এখানে পাওয়া যাবে, যা DOM থেকে সবচেয়ে জনপ্রিয় ইভেন্টগুলির উপর ভিত্তি করে।

আপনি যে টাইপটি খুঁজছেন তা নির্ধারণ করার সময়, আপনি প্রথমে যেই ইভেন্ট হ্যান্ডলারটি ব্যবহার করছেন তার হভার তথ্য দেখতে পারেন, যা ইভেন্টের টাইপটি দেখাবে।

যদি আপনার এমন একটি ইভেন্ট ব্যবহার করতে হয় যা এই তালিকায় অন্তর্ভুক্ত নয়, তাহলে আপনি React.SyntheticEvent টাইপ ব্যবহার করতে পারেন, যা সমস্ত ইভেন্টের জন্য বেস টাইপ।

Children

একটি কম্পোনেন্টের চাইল্ড বর্ণনা করার জন্য দুটি সাধারণ পদ্ধতি রয়েছে। প্রথমটি হল React.ReactNode টাইপ ব্যবহার করা, যা JSX-এ চাইল্ড হিসেবে পাস করা সমস্ত সম্ভাব্য টাইপের একটি ইউনিয়ন।

এখানে, “চাইল্ড” হচ্ছে প্রোগ্রামিংয়ের একটি ধারণা, যা নির্দেশ করে যে একটি কম্পোনেন্টের মধ্যে অন্য একটি কম্পোনেন্ট বা উপাদান কিভাবে নেস্ট করা হয়েছে।

interface ModalRendererProps {
title: string;
children: React.ReactNode;
}

এটি চাইল্ডসমূহের একটি খুবই বিস্তৃত সংজ্ঞা। দ্বিতীয়টি হল React.ReactElement টাইপ ব্যবহার করা, যা শুধুমাত্র JSX উপাদান এবং স্ট্রিং বা সংখ্যা মতো জাভাস্ক্রিপ্ট প্রিমিটিভ নয়:

interface ModalRendererProps {
title: string;
children: React.ReactElement;
}

দ্রষ্টব্য, আপনি TypeScript ব্যবহার করে বর্ণনা করতে পারবেন না যে চাইল্ডসমূহের একটি নির্দিষ্ট ধরনের JSX উপাদান, তাই আপনি টাইপ সিস্টেম ব্যবহার করে এমন একটি কম্পোনেন্ট বর্ণনা করতে পারবেন না যা কেবল <li> শিশু গ্রহণ করে।

আপনি উভয় React.ReactNode এবং React.ReactElement এর একটি উদাহরণ টাইপ-চেকার সহ এই TypeScript প্লেগ্রাউন্ডে দেখতে পারেন।

টাইল প্রপস

React-এ ইনলাইন স্টাইল ব্যবহার করার সময়, আপনি React.CSSProperties ব্যবহার করে স্টাইল প্রপে পাস করা অবজেক্টটি বর্ণনা করতে পারেন। এই টাইপটি সমস্ত সম্ভাব্য CSS প্রপার্টির একটি ইউনিয়ন এবং এটি নিশ্চিত করার জন্য একটি ভালো উপায় যে আপনি স্টাইল প্রপে বৈধ CSS প্রপার্টি পাস করছেন, এবং আপনার এডিটরে অটো-কমপ্লিট পাওয়ার জন্য।

interface MyComponentProps {
style: React.CSSProperties;
}

আরও শেখা

এই গাইডে React এর সাথে TypeScript ব্যবহারের মৌলিক বিষয়গুলো আলোচনা করা হয়েছে, তবে শেখার জন্য আরও অনেক কিছু রয়েছে। ডকসের পৃথক API পৃষ্ঠাগুলো TypeScript এর সাথে কীভাবে ব্যবহার করতে হয় সে সম্পর্কে আরও গভীর ডকুমেন্টেশন ধারণ করতে পারে।

আমরা নিম্নলিখিত রিসোর্সগুলোর সুপারিশ করছি:

  • TypeScript হ্যান্ডবুক হল TypeScript এর অফিসিয়াল ডকুমেন্টেশন, যা বেশিরভাগ মূল ভাষার বৈশিষ্ট্যগুলো আলোচনা করে।

  • TypeScript রিলিজ নোটস নতুন বৈশিষ্ট্যগুলো বিস্তারিতভাবে আলোচনা করে।

  • React TypeScript Cheatsheet হল TypeScript এর সাথে React ব্যবহার করার জন্য একটি কমিউনিটি দ্বারা রক্ষণাবেক্ষিত চিটশিট, যা অনেক কার্যকর প্রান্তের কেস এবং এই ডকুমেন্টের চেয়ে আরও বিস্তৃত বিষয়গুলি কভার করে।

  • TypeScript কমিউনিটি ডিসকর্ড TypeScript এবং React সমস্যাগুলির জন্য প্রশ্ন জিজ্ঞাসা করতে এবং সাহায্য পাওয়ার জন্য একটি চমৎকার জায়গা।