தமிழ்

வலிமையான, நெகிழ்வான, மற்றும் பராமரிக்கக்கூடிய API-களை உருவாக்க TypeScript நிபந்தனை வகைகளின் ஆற்றலைத் திறந்திடுங்கள். உலகளாவிய மென்பொருள் திட்டங்களுக்கு ஏற்றவாறு மாற்றியமைக்கக்கூடிய இடைமுகங்களை உருவாக்கவும்.

மேம்பட்ட API வடிவமைப்பிற்கான TypeScript நிபந்தனை வகைகள்

மென்பொருள் மேம்பாட்டு உலகில், API-கள் (பயன்பாட்டு நிரலாக்க இடைமுகங்கள்) உருவாக்குவது ஒரு அடிப்படை நடைமுறையாகும். ஒரு நன்கு வடிவமைக்கப்பட்ட API எந்தவொரு பயன்பாட்டின் வெற்றிக்கும், குறிப்பாக உலகளாவிய பயனர் தளத்தைக் கையாளும் போது, ​​முக்கியமானது. TypeScript, அதன் சக்திவாய்ந்த வகை அமைப்புடன், டெவலப்பர்களுக்கு செயல்பாட்டுரீதியாக மட்டுமல்லாமல், வலுவான, பராமரிக்கக்கூடிய மற்றும் புரிந்துகொள்ள எளிதான API-களை உருவாக்குவதற்கான கருவிகளை வழங்குகிறது. இந்த கருவிகளில், நிபந்தனை வகைகள் (Conditional Types) மேம்பட்ட API வடிவமைப்பிற்கான ஒரு முக்கிய அங்கமாக தனித்து நிற்கின்றன. இந்த வலைப்பதிவு இடுகை நிபந்தனை வகைகளின் நுணுக்கங்களை ஆராய்ந்து, மேலும் மாற்றியமைக்கக்கூடிய மற்றும் வகை-பாதுகாப்பான API-களை உருவாக்க அவற்றை எவ்வாறு பயன்படுத்தலாம் என்பதை விளக்கும்.

நிபந்தனை வகைகளைப் புரிந்துகொள்ளுதல்

அடிப்படையில், TypeScript-ல் உள்ள நிபந்தனை வகைகள், மற்ற மதிப்புகளின் வகைகளைப் பொறுத்து வடிவத்தைக் கொண்ட வகைகளை உருவாக்க உங்களை அனுமதிக்கின்றன. உங்கள் குறியீட்டில் `if...else` கூற்றுகளைப் பயன்படுத்துவது போலவே, அவை ஒரு வகை-நிலை தர்க்கத்தை அறிமுகப்படுத்துகின்றன. இந்த நிபந்தனை தர்க்கம், மற்ற மதிப்புகள் அல்லது அளவுருக்களின் பண்புகளைப் பொறுத்து ஒரு மதிப்பின் வகை மாற வேண்டிய சிக்கலான சூழ்நிலைகளைக் கையாளும் போது குறிப்பாக பயனுள்ளதாக இருக்கும். இதன் தொடரியல் மிகவும் உள்ளுணர்வுடன் உள்ளது:


type ResultType = T extends string ? string : number;

இந்த எடுத்துக்காட்டில், `ResultType` ஒரு நிபந்தனை வகையாகும். ஜெனரிக் வகை `T` என்பது `string`-க்கு நீட்டிக்கப்பட்டால் (assignable to), விளைவு வகை `string` ஆக இருக்கும்; இல்லையெனில், அது `number` ஆகும். இந்த எளிய எடுத்துக்காட்டு முக்கிய கருத்தை நிரூபிக்கிறது: உள்ளீட்டு வகையின் அடிப்படையில், நாம் ஒரு ভিন্ন வெளியீட்டு வகையைப் பெறுகிறோம்.

அடிப்படை தொடரியல் மற்றும் எடுத்துக்காட்டுகள்

தொடரியலை மேலும் பிரிப்போம்:

உங்கள் புரிதலை வலுப்படுத்த இன்னும் சில எடுத்துக்காட்டுகள் இங்கே:


type StringOrNumber = T extends string ? string : number;

let a: StringOrNumber = 'hello'; // string
let b: StringOrNumber = 123; // number

இந்த நேர்வில், நாம் `StringOrNumber` என்ற ஒரு வகையை வரையறுக்கிறோம், அது உள்ளீட்டு வகை `T`-ஐப் பொறுத்து `string` அல்லது `number` ஆக இருக்கும். இந்த எளிய எடுத்துக்காட்டு, மற்றொரு வகையின் பண்புகளை அடிப்படையாகக் கொண்டு ஒரு வகையை வரையறுப்பதில் நிபந்தனை வகைகளின் ஆற்றலை நிரூபிக்கிறது.


type Flatten = T extends (infer U)[] ? U : T;

let arr1: Flatten = 'hello'; // string
let arr2: Flatten = 123; // number

இந்த `Flatten` வகை ஒரு வரிசையிலிருந்து (array) உறுப்பு வகையைப் பிரித்தெடுக்கிறது. இந்த எடுத்துக்காட்டு `infer`-ஐப் பயன்படுத்துகிறது, இது நிபந்தனைக்குள் ஒரு வகையை வரையறுக்கப் பயன்படுகிறது. `infer U` என்பது வரிசையிலிருந்து `U` வகையை அனுமானிக்கிறது, மேலும் `T` ஒரு வரிசையாக இருந்தால், முடிவு வகை `U` ஆக இருக்கும்.

API வடிவமைப்பில் மேம்பட்ட பயன்பாடுகள்

நெகிழ்வான மற்றும் வகை-பாதுகாப்பான API-களை உருவாக்குவதற்கு நிபந்தனை வகைகள் விலைமதிப்பற்றவை. பல்வேறு அளவுகோல்களின் அடிப்படையில் மாற்றியமைக்கக்கூடிய வகைகளை வரையறுக்க அவை உங்களை அனுமதிக்கின்றன. இங்கே சில நடைமுறை பயன்பாடுகள் உள்ளன:

1. டைனமிக் ரெஸ்பான்ஸ் வகைகளை உருவாக்குதல்

கோரிக்கை அளவுருக்களின் அடிப்படையில் வெவ்வேறு தரவை வழங்கும் ஒரு கற்பனையான API-யைக் கவனியுங்கள். நிபந்தனை வகைகள் ரெஸ்பான்ஸ் வகையை டைனமிக்காக மாதிரியாக்க உங்களை அனுமதிக்கின்றன:


interface User {
  id: number;
  name: string;
  email: string;
}

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

type ApiResponse = 
  T extends 'user' ? User : Product;

function fetchData(type: T): ApiResponse {
  if (type === 'user') {
    return { id: 1, name: 'John Doe', email: 'john.doe@example.com' } as ApiResponse; // TypeScript knows this is a User
  } else {
    return { id: 1, name: 'Widget', price: 19.99 } as ApiResponse; // TypeScript knows this is a Product
  }
}

const userData = fetchData('user'); // userData is of type User
const productData = fetchData('product'); // productData is of type Product

இந்த எடுத்துக்காட்டில், `ApiResponse` வகை உள்ளீட்டு அளவுரு `T`-ஐப் பொறுத்து டைனமிக்காக மாறுகிறது. இது வகை பாதுகாப்பை மேம்படுத்துகிறது, ஏனெனில் TypeScript `type` அளவுருவின் அடிப்படையில் வழங்கப்படும் தரவின் சரியான கட்டமைப்பை அறிந்திருக்கிறது. இது யூனியன் வகைகள் போன்ற சாத்தியமான குறைந்த வகை-பாதுகாப்பான மாற்றுகளின் தேவையைத் தவிர்க்கிறது.

2. வகை-பாதுகாப்பான பிழை கையாளுதலை செயல்படுத்துதல்

API-கள் பெரும்பாலும் ஒரு கோரிக்கை வெற்றி பெறுகிறதா அல்லது தோல்வியடைகிறதா என்பதைப் பொறுத்து வெவ்வேறு ரெஸ்பான்ஸ் வடிவங்களை வழங்குகின்றன. நிபந்தனை வகைகள் இந்த சூழ்நிலைகளை நேர்த்தியாக மாதிரியாக்க முடியும்:


interface SuccessResponse {
  status: 'success';
  data: T;
}

interface ErrorResponse {
  status: 'error';
  message: string;
}

type ApiResult = T extends any ? SuccessResponse | ErrorResponse : never;

function processData(data: T, success: boolean): ApiResult {
  if (success) {
    return { status: 'success', data } as ApiResult;
  } else {
    return { status: 'error', message: 'An error occurred' } as ApiResult;
  }
}

const result1 = processData({ name: 'Test', value: 123 }, true); // SuccessResponse<{ name: string; value: number; }>
const result2 = processData({ name: 'Test', value: 123 }, false); // ErrorResponse

இங்கே, `ApiResult` ஆனது API ரெஸ்பான்ஸின் கட்டமைப்பை வரையறுக்கிறது, இது `SuccessResponse` அல்லது `ErrorResponse` ஆக இருக்கலாம். `processData` ஃபங்ஷன் `success` அளவுருவின் அடிப்படையில் சரியான ரெஸ்பான்ஸ் வகை வழங்கப்படுவதை உறுதி செய்கிறது.

3. நெகிழ்வான ஃபங்ஷன் ஓவர்லோடுகளை உருவாக்குதல்

நிபந்தனை வகைகளை ஃபங்ஷன் ஓவர்லோடுகளுடன் இணைந்து மிகவும் மாற்றியமைக்கக்கூடிய API-களை உருவாக்கவும் பயன்படுத்தலாம். ஃபங்ஷன் ஓவர்லோடுகள் ஒரு ஃபங்ஷனுக்கு பல கையொப்பங்களை (signatures) வைத்திருக்க அனுமதிக்கின்றன, ஒவ்வொன்றும் வெவ்வேறு அளவுரு வகைகள் மற்றும் ரிட்டர்ன் வகைகளைக் கொண்டிருக்கும். வெவ்வேறு மூலங்களிலிருந்து தரவைப் பெறக்கூடிய ஒரு API-யைக் கவனியுங்கள்:


function fetchDataOverload(resource: T): Promise;
function fetchDataOverload(resource: string): Promise;

async function fetchDataOverload(resource: string): Promise {
    if (resource === 'users') {
        // Simulate fetching users from an API
        return new Promise((resolve) => {
            setTimeout(() => resolve([{ id: 1, name: 'User 1', email: 'user1@example.com' }]), 100);
        });
    } else if (resource === 'products') {
        // Simulate fetching products from an API
        return new Promise((resolve) => {
            setTimeout(() => resolve([{ id: 1, name: 'Product 1', price: 10.00 }]), 100);
        });
    } else {
        // Handle other resources or errors
        return new Promise((resolve) => {
            setTimeout(() => resolve([]), 100);
        });
    }
}

(async () => {
    const users = await fetchDataOverload('users'); // users is of type User[]
    const products = await fetchDataOverload('products'); // products is of type Product[]
    console.log(users[0].name); // Access user properties safely
    console.log(products[0].name); // Access product properties safely
})();

இங்கே, முதல் ஓவர்லோட் `resource` என்பது 'users' ஆக இருந்தால், ரிட்டர்ன் வகை `User[]` என்று குறிப்பிடுகிறது. இரண்டாவது ஓவர்லோட், resource 'products' ஆக இருந்தால், ரிட்டர்ன் வகை `Product[]` என்று குறிப்பிடுகிறது. இந்த அமைப்பு ஃபங்ஷனுக்கு வழங்கப்படும் உள்ளீடுகளின் அடிப்படையில் மிகவும் துல்லியமான வகை சரிபார்ப்பை அனுமதிக்கிறது, இது சிறந்த குறியீடு நிறைவு மற்றும் பிழை கண்டறிதலை செயல்படுத்துகிறது.

4. பயன்பாட்டு வகைகளை உருவாக்குதல்

நிபந்தனை வகைகள் ஏற்கனவே உள்ள வகைகளை மாற்றும் பயன்பாட்டு வகைகளை (utility types) உருவாக்குவதற்கான சக்திவாய்ந்த கருவிகளாகும். இந்த பயன்பாட்டு வகைகள் தரவுக் கட்டமைப்புகளைக் கையாளவும், ஒரு API-ல் அதிகளவில் மீண்டும் பயன்படுத்தக்கூடிய கூறுகளை உருவாக்கவும் பயனுள்ளதாக இருக்கும்.


interface Person {
  name: string;
  age: number;
  address: {
    street: string;
    city: string;
    country: string;
  };
}

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

const readonlyPerson: DeepReadonly = {
  name: 'John',
  age: 30,
  address: {
    street: '123 Main St',
    city: 'Anytown',
    country: 'USA',
  },
};

// readonlyPerson.name = 'Jane'; // Error: Cannot assign to 'name' because it is a read-only property.
// readonlyPerson.address.street = '456 Oak Ave'; // Error: Cannot assign to 'street' because it is a read-only property.

இந்த `DeepReadonly` வகை ஒரு ஆப்ஜெக்ட் மற்றும் அதன் உள்ளமைக்கப்பட்ட ஆப்ஜெக்ட்களின் அனைத்து பண்புகளையும் படிக்க மட்டுமே (read-only) கூடியதாக மாற்றுகிறது. இந்த எடுத்துக்காட்டு, சிக்கலான வகை மாற்றங்களை உருவாக்க நிபந்தனை வகைகளை எவ்வாறு மீண்டும் மீண்டும் பயன்படுத்தலாம் என்பதை விளக்குகிறது. மாற்ற முடியாத தரவு விரும்பப்படும் சூழ்நிலைகளுக்கு இது முக்கியமானது, குறிப்பாக ஒரே நேரத்தில் பல நிரலாக்கப் பணிகளைச் செய்யும் போது அல்லது வெவ்வேறு தொகுதிகளுக்கு இடையில் தரவைப் பகிரும்போது கூடுதல் பாதுகாப்பை வழங்குகிறது.

5. API ரெஸ்பான்ஸ் தரவை சுருக்குதல்

நிஜ-உலக API தொடர்புகளில், நீங்கள் அடிக்கடி உறை இடப்பட்ட (wrapped) ரெஸ்பான்ஸ் கட்டமைப்புகளுடன் வேலை செய்கிறீர்கள். நிபந்தனை வகைகள் வெவ்வேறு ரெஸ்பான்ஸ் உறைகளைக் கையாள்வதை எளிதாக்கலாம்.


interface ApiResponseWrapper {
  data: T;
  meta: {
    total: number;
    page: number;
  };
}

type UnwrapApiResponse = T extends ApiResponseWrapper ? U : T;

function processApiResponse(response: ApiResponseWrapper): UnwrapApiResponse {
  return response.data;
}

interface ProductApiData {
  name: string;
  price: number;
}

const productResponse: ApiResponseWrapper = {
  data: {
    name: 'Example Product',
    price: 20,
  },
  meta: {
    total: 1,
    page: 1,
  },
};

const unwrappedProduct = processApiResponse(productResponse); // unwrappedProduct is of type ProductApiData

இந்த நேர்வில், `UnwrapApiResponse` ஆனது `ApiResponseWrapper`-லிருந்து உள் `data` வகையைப் பிரித்தெடுக்கிறது. இது API நுகர்வோர் உறையைக் கையாள வேண்டிய அவசியமின்றி, மைய தரவுக் கட்டமைப்போடு வேலை செய்ய அனுமதிக்கிறது. இது API ரெஸ்பான்ஸ்களை சீராக மாற்றியமைக்க மிகவும் பயனுள்ளதாக இருக்கும்.

நிபந்தனை வகைகளைப் பயன்படுத்துவதற்கான சிறந்த நடைமுறைகள்

நிபந்தனை வகைகள் சக்திவாய்ந்தவை என்றாலும், அவற்றை தவறாகப் பயன்படுத்தினால் உங்கள் குறியீட்டை மேலும் சிக்கலாக்கக்கூடும். நிபந்தனை வகைகளை நீங்கள் திறம்படப் பயன்படுத்துவதை உறுதிப்படுத்த சில சிறந்த நடைமுறைகள் இங்கே:

நிஜ-உலக எடுத்துக்காட்டுகள் மற்றும் உலகளாவிய பரிசீலனைகள்

நிஜ-உலக சூழ்நிலைகள் சிலவற்றை ஆராய்வோம், அங்கு நிபந்தனை வகைகள் பிரகாசிக்கின்றன, குறிப்பாக உலகளாவிய பார்வையாளர்களுக்காக வடிவமைக்கப்பட்ட API-களை உருவாக்கும் போது:

இந்த எடுத்துக்காட்டுகள் உலகமயமாக்கலை திறம்பட நிர்வகிக்கும் மற்றும் சர்வதேச பார்வையாளர்களின் பல்வேறு தேவைகளைப் பூர்த்தி செய்யும் API-களை உருவாக்குவதில் நிபந்தனை வகைகளின் பன்முகத்தன்மையை எடுத்துக்காட்டுகின்றன. உலகளாவிய பார்வையாளர்களுக்காக API-களை உருவாக்கும் போது, நேர மண்டலங்கள், நாணயங்கள், தேதி வடிவங்கள் மற்றும் மொழி விருப்பங்களைக் கருத்தில் கொள்வது மிகவும் முக்கியம். நிபந்தனை வகைகளைப் பயன்படுத்துவதன் மூலம், டெவலப்பர்கள் இருப்பிடத்தைப் பொருட்படுத்தாமல், ஒரு விதிவிலக்கான பயனர் அனுபவத்தை வழங்கும், மாற்றியமைக்கக்கூடிய மற்றும் வகை-பாதுகாப்பான API-களை உருவாக்க முடியும்.

சவால்கள் மற்றும் அவற்றைத் தவிர்ப்பது எப்படி

நிபந்தனை வகைகள் நம்பமுடியாத அளவிற்கு பயனுள்ளதாக இருந்தாலும், தவிர்க்க வேண்டிய சில சாத்தியமான சவால்கள் உள்ளன:

முடிவுரை

TypeScript நிபந்தனை வகைகள் மேம்பட்ட API-களை வடிவமைப்பதற்கான ஒரு சக்திவாய்ந்த வழிமுறையை வழங்குகின்றன. அவை டெவலப்பர்களுக்கு நெகிழ்வான, வகை-பாதுகாப்பான மற்றும் பராமரிக்கக்கூடிய குறியீட்டை உருவாக்க அதிகாரம் அளிக்கின்றன. நிபந்தனை வகைகளில் தேர்ச்சி பெறுவதன் மூலம், உங்கள் திட்டங்களின் மாறிவரும் தேவைகளுக்கு எளிதில் மாற்றியமைக்கக்கூடிய API-களை உருவாக்கலாம், அவற்றை உலகளாவிய மென்பொருள் மேம்பாட்டு நிலப்பரப்பில் வலுவான மற்றும் அளவிடக்கூடிய பயன்பாடுகளை உருவாக்குவதற்கான ஒரு மூலக்கல்லாக மாற்றலாம். நிபந்தனை வகைகளின் சக்தியை ஏற்றுக்கொண்டு, உங்கள் API வடிவமைப்புகளின் தரம் மற்றும் பராமரிப்புத்தன்மையை உயர்த்துங்கள், உங்கள் திட்டங்களை ஒன்றோடொன்று இணைக்கப்பட்ட உலகில் நீண்டகால வெற்றிக்கு அமைக்கவும். இந்த சக்திவாய்ந்த கருவிகளின் முழு திறனையும் முழுமையாகப் பயன்படுத்த, வாசிப்புத்தன்மை, ஆவணப்படுத்தல் மற்றும் முழுமையான சோதனைக்கு முன்னுரிமை அளிக்க நினைவில் கொள்ளுங்கள்.