தமிழ்

டைப்ஸ்கிரிப்ட்டின் 'infer' முக்கியச்சொல்லுக்கான ஒரு விரிவான வழிகாட்டி. சக்திவாய்ந்த வகை பிரித்தெடுத்தல் மற்றும் கையாளுதலுக்காக நிபந்தனை வகைகளுடன் அதை எவ்வாறு பயன்படுத்துவது என்பதை மேம்பட்ட பயன்பாட்டு நிகழ்வுகளுடன் விளக்குகிறது.

டைப்ஸ்கிரிப்ட் இன்ஃபரில் தேர்ச்சி பெறுதல்: மேம்பட்ட வகை கையாளுதலுக்கான நிபந்தனை வகை பிரித்தெடுத்தல்

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

நிபந்தனை வகைகள் என்றால் என்ன?

நாம் infer பற்றி ஆராய்வதற்கு முன், நிபந்தனை வகைகளை விரைவாக மதிப்பாய்வு செய்வோம். டைப்ஸ்கிரிப்டில் உள்ள நிபந்தனை வகைகள், ஜாவாஸ்கிரிப்டில் உள்ள ஒரு டெர்னரி ஆபரேட்டரைப் போலவே, ஒரு நிபந்தனையின் அடிப்படையில் ஒரு வகையை வரையறுக்க உங்களை அனுமதிக்கின்றன. அதன் அடிப்படை தொடரியல்:

T extends U ? X : Y

இதை இவ்வாறு படிக்கலாம்: "வகை T ஆனது வகை U-க்கு ஒதுக்கக்கூடியதாக இருந்தால், அதன் வகை X ஆகும்; இல்லையெனில், அதன் வகை Y ஆகும்."

உதாரணம்:

type IsString<T> = T extends string ? true : false;

type StringResult = IsString<string>; // type StringResult = true
type NumberResult = IsString<number>; // type NumberResult = false

infer முக்கியச்சொல்லை அறிமுகப்படுத்துதல்

infer முக்கியச்சொல் ஒரு நிபந்தனை வகையின் extends உட்பிரிவில் பயன்படுத்தப்படுகிறது, இது சரிபார்க்கப்படும் வகையிலிருந்து ஊகிக்கக்கூடிய ஒரு வகை மாறியை அறிவிக்க உதவுகிறது. சுருக்கமாக, இது ஒரு வகையின் ஒரு பகுதியை பிற்கால பயன்பாட்டிற்காக "பகிர" உங்களை அனுமதிக்கிறது.

அடிப்படை தொடரியல்:

type MyType<T> = T extends (infer U) ? U : never;

இந்த எடுத்துக்காட்டில், T என்பது சில வகைக்கு ஒதுக்கக்கூடியதாக இருந்தால், டைப்ஸ்கிரிப்ட் U-இன் வகையை ஊகிக்க முயற்சிக்கும். ஊகித்தல் வெற்றிகரமாக இருந்தால், வகை U ஆக இருக்கும்; இல்லையெனில், அது never ஆக இருக்கும்.

infer-இன் எளிய எடுத்துக்காட்டுகள்

1. ஒரு செயல்பாட்டின் ரிட்டர்ன் வகையை ஊகித்தல்

ஒரு பொதுவான பயன்பாட்டு நிகழ்வு ஒரு செயல்பாட்டின் ரிட்டர்ன் வகையை ஊகிப்பதாகும்:

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

function add(a: number, b: number): number {
  return a + b;
}

type AddReturnType = ReturnType<typeof add>; // type AddReturnType = number

function greet(name: string): string {
  return `Hello, ${name}!`;
}

type GreetReturnType = ReturnType<typeof greet>; // type GreetReturnType = string

இந்த எடுத்துக்காட்டில், ReturnType<T> ஒரு செயல்பாட்டு வகை T-ஐ உள்ளீடாக எடுத்துக்கொள்கிறது. இது T என்பது எந்த ஆர்குமெண்ட்டுகளையும் ஏற்றுக்கொண்டு ஒரு மதிப்பைத் தரும் செயல்பாட்டிற்கு ஒதுக்கக்கூடியதா என்று சரிபார்க்கிறது. அவ்வாறு இருந்தால், அது ரிட்டர்ன் வகையை R என ஊகித்து அதைத் தருகிறது. இல்லையெனில், அது any-ஐத் தருகிறது.

2. அரே உறுப்பு வகையை ஊகித்தல்

மற்றொரு பயனுள்ள சூழ்நிலை, ஒரு அரேயிலிருந்து உறுப்பு வகையைப் பிரித்தெடுப்பதாகும்:

type ArrayElementType<T> = T extends (infer U)[] ? U : never;

type NumberArrayType = ArrayElementType<number[]>; // type NumberArrayType = number
type StringArrayType = ArrayElementType<string[]>; // type StringArrayType = string
type MixedArrayType = ArrayElementType<(string | number)[]>; // type MixedArrayType = string | number
type NotAnArrayType = ArrayElementType<number>; // type NotAnArrayType = never

இங்கே, ArrayElementType<T> என்பது T ஒரு அரே வகையா என்று சரிபார்க்கிறது. அவ்வாறு இருந்தால், அது உறுப்பு வகையை U என ஊகித்து அதைத் தருகிறது. இல்லையெனில், அது never-ஐத் தருகிறது.

infer-இன் மேம்பட்ட பயன்பாட்டு நிகழ்வுகள்

1. ஒரு கன்ஸ்ட்ரக்டரின் பாராமீட்டர்களை ஊகித்தல்

ஒரு கன்ஸ்ட்ரக்டர் செயல்பாட்டின் பாராமீட்டர் வகைகளைப் பிரித்தெடுக்க infer-ஐப் பயன்படுத்தலாம்:

type ConstructorParameters<T extends new (...args: any) => any> = T extends new (...args: infer P) => any ? P : never;

class Person {
  constructor(public name: string, public age: number) {}
}

type PersonConstructorParams = ConstructorParameters<typeof Person>; // type PersonConstructorParams = [string, number]

class Point {
    constructor(public x: number, public y: number) {}
}

type PointConstructorParams = ConstructorParameters<typeof Point>; // type PointConstructorParams = [number, number]

இந்த நிலையில், ConstructorParameters<T> ஒரு கன்ஸ்ட்ரக்டர் செயல்பாட்டு வகை T-ஐ எடுத்துக்கொள்கிறது. இது கன்ஸ்ட்ரக்டர் பாராமீட்டர்களின் வகைகளை P என ஊகித்து அவற்றை ஒரு டூப்பிளாகத் தருகிறது.

2. ஆப்ஜெக்ட் வகைகளிலிருந்து பண்புகளைப் பிரித்தெடுத்தல்

மேப் செய்யப்பட்ட வகைகள் மற்றும் நிபந்தனை வகைகளைப் பயன்படுத்தி ஆப்ஜெக்ட் வகைகளிலிருந்து குறிப்பிட்ட பண்புகளைப் பிரித்தெடுக்கவும் infer-ஐப் பயன்படுத்தலாம்:

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

interface User {
  id: number;
  name: string;
  age: number;
  email: string;
  isActive: boolean;
}

type StringProperties = PickByType<User, keyof User, string>; // type StringProperties = { name: string; email: string; }

type NumberProperties = PickByType<User, keyof User, number>; // type NumberProperties = { id: number; age: number; }

//An interface representing geographic coordinates.
interface GeoCoordinates {
    latitude: number;
    longitude: number;
    altitude: number;
    country: string;
    city: string;
    timezone: string;
}

type NumberCoordinateProperties = PickByType<GeoCoordinates, keyof GeoCoordinates, number>; // type NumberCoordinateProperties = { latitude: number; longitude: number; altitude: number; }

இங்கே, PickByType<T, K, U> ஒரு புதிய வகையை உருவாக்குகிறது, அதில் T-இன் பண்புகள் (K-இல் உள்ள கீ-களுடன்) மட்டுமே அடங்கும், அவற்றின் மதிப்புகள் U வகைக்கு ஒதுக்கக்கூடியதாக இருக்கும். மேப் செய்யப்பட்ட வகை T-இன் கீ-கள் மீது செயல்படுகிறது, மற்றும் நிபந்தனை வகை குறிப்பிட்ட வகையுடன் பொருந்தாத கீ-களை வடிகட்டுகிறது.

3. ப்ராமிஸ்களுடன் வேலை செய்தல்

ஒரு Promise-இன் ரிசால்வ் செய்யப்பட்ட வகையை நீங்கள் ஊகிக்கலாம்:

type Awaited<T> = T extends Promise<infer U> ? U : T;

async function fetchData(): Promise<string> {
  return 'Data from API';
}

type FetchDataType = Awaited<ReturnType<typeof fetchData>>; // type FetchDataType = string

async function fetchNumbers(): Promise<number[]> {
    return [1, 2, 3];
}

type FetchedNumbersType = Awaited<ReturnType<typeof fetchNumbers>>; //type FetchedNumbersType = number[]

Awaited<T> வகை T என்ற வகையை எடுத்துக்கொள்கிறது, இது ஒரு ப்ராமிஸ் என்று எதிர்பார்க்கப்படுகிறது. இந்த வகை பின்னர் ப்ராமிஸின் ரிசால்வ் செய்யப்பட்ட வகை U-ஐ ஊகித்து, அதைத் தருகிறது. T ஒரு ப்ராமிஸ் இல்லையென்றால், அது T-ஐத் தருகிறது. இது டைப்ஸ்கிரிப்ட்டின் புதிய பதிப்புகளில் உள்ளமைக்கப்பட்ட பயன்பாட்டு வகையாகும்.

4. ப்ராமிஸ்களின் அரேயின் வகையைப் பிரித்தெடுத்தல்

Awaited மற்றும் அரே வகை ஊகிப்பை இணைப்பது, ப்ராமிஸ்களின் அரே மூலம் ரிசால்வ் செய்யப்படும் வகையை ஊகிக்க உங்களை அனுமதிக்கிறது. இது Promise.all-ஐக் கையாளும் போது குறிப்பாக பயனுள்ளதாக இருக்கும்.

type PromiseArrayReturnType<T extends Promise<any>[]> = {
    [K in keyof T]: Awaited<T[K]>;
};


async function getUSDRate(): Promise<number> {
  return 0.0069;
}

async function getEURRate(): Promise<number> {
  return 0.0064;
}

const rates = [getUSDRate(), getEURRate()];

type RatesType = PromiseArrayReturnType<typeof rates>;
// type RatesType = [number, number]

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

பல்வேறு களங்களில் நடைமுறை எடுத்துக்காட்டுகள்

1. மின்-வணிகப் பயன்பாடு

ஒரு மின்-வணிகப் பயன்பாட்டை கருத்தில் கொள்ளுங்கள், அங்கு நீங்கள் ஒரு API-இலிருந்து தயாரிப்பு விவரங்களைப் பெறுகிறீர்கள். தயாரிப்பு தரவின் வகையைப் பிரித்தெடுக்க infer-ஐப் பயன்படுத்தலாம்:

interface Product {
  id: number;
  name: string;
  price: number;
  description: string;
  imageUrl: string;
  category: string;
  rating: number;
  countryOfOrigin: string;
}

async function fetchProduct(productId: number): Promise<Product> {
  // Simulate API call
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        id: productId,
        name: 'Example Product',
        price: 29.99,
        description: 'A sample product',
        imageUrl: 'https://example.com/image.jpg',
        category: 'Electronics',
        rating: 4.5,
        countryOfOrigin: 'Canada'
      });
    }, 500);
  });
}


type ProductType = Awaited<ReturnType<typeof fetchProduct>>; // type ProductType = Product

function displayProductDetails(product: ProductType) {
  console.log(`Product Name: ${product.name}`);
  console.log(`Price: ${product.price} ${product.countryOfOrigin === 'Canada' ? 'CAD' : (product.countryOfOrigin === 'USA' ? 'USD' : 'EUR')}`);
}

fetchProduct(123).then(displayProductDetails);

இந்த எடுத்துக்காட்டில், நாம் ஒரு Product இன்டர்ஃபேஸையும், ஒரு API-இலிருந்து தயாரிப்பு விவரங்களைப் பெறும் fetchProduct செயல்பாட்டையும் வரையறுக்கிறோம். fetchProduct செயல்பாட்டின் ரிட்டர்ன் வகையிலிருந்து Product வகையைப் பிரித்தெடுக்க Awaited மற்றும் ReturnType-ஐப் பயன்படுத்துகிறோம், இது displayProductDetails செயல்பாட்டை வகை-சரிபார்க்க அனுமதிக்கிறது.

2. சர்வதேசமயமாக்கல் (i18n)

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

interface Translations {
  greeting: string;
  farewell: string;
  welcomeMessage: (name: string) => string;
}

const enTranslations: Translations = {
  greeting: 'Hello',
  farewell: 'Goodbye',
  welcomeMessage: (name: string) => `Welcome, ${name}!`, 
};

const frTranslations: Translations = {
  greeting: 'Bonjour',
  farewell: 'Au revoir',
  welcomeMessage: (name: string) => `Bienvenue, ${name}!`, 
};

function getTranslation(locale: 'en' | 'fr'): Translations {
  return locale === 'en' ? enTranslations : frTranslations;
}

type TranslationType = ReturnType<typeof getTranslation>;

function greetUser(locale: 'en' | 'fr', name: string) {
  const translations = getTranslation(locale);
  console.log(translations.welcomeMessage(name));
}

greetUser('fr', 'Jean'); // Output: Bienvenue, Jean!

இங்கே, TranslationType என்பது Translations இன்டர்ஃபேஸ் என ஊகிக்கப்படுகிறது, இது greetUser செயல்பாட்டிற்கு மொழிபெயர்க்கப்பட்ட ஸ்டிரிங்குகளை அணுகுவதற்கான சரியான வகை தகவலை உறுதி செய்கிறது.

3. API ரெஸ்பான்ஸ் கையாளுதல்

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

interface ApiResponse<T> {
  status: number;
  data: T;
  message?: string;
}

interface UserData {
  id: number;
  username: string;
  email: string;
  profile: {
    firstName: string;
    lastName: string;
    country: string;
    language: string;
  }
}

async function fetchUser(userId: number): Promise<ApiResponse<UserData>> {
  // Simulate API call
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        status: 200,
        data: {
          id: userId,
          username: 'johndoe',
          email: 'john.doe@example.com',
          profile: {
            firstName: 'John',
            lastName: 'Doe',
            country: 'USA',
            language: 'en'
          }
        }
      });
    }, 500);
  });
}


type UserApiResponse = Awaited<ReturnType<typeof fetchUser>>;

type UserProfileType = UserApiResponse['data']['profile'];

function displayUserProfile(profile: UserProfileType) {
  console.log(`Name: ${profile.firstName} ${profile.lastName}`);
  console.log(`Country: ${profile.country}`);
}

fetchUser(123).then((response) => {
  if (response.status === 200) {
    displayUserProfile(response.data.profile);
  }
});

இந்த எடுத்துக்காட்டில், நாம் ஒரு ApiResponse இன்டர்ஃபேஸையும், ஒரு UserData இன்டர்ஃபேஸையும் வரையறுக்கிறோம். API ரெஸ்பான்ஸிலிருந்து UserProfileType-ஐப் பிரித்தெடுக்க infer மற்றும் வகை இன்டெக்சிங்கைப் பயன்படுத்துகிறோம், இது displayUserProfile செயல்பாடு சரியான வகையைப் பெறுவதை உறுதி செய்கிறது.

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

பொதுவான ஆபத்துகள்

infer-க்கு மாற்றுகள்

infer ஒரு சக்திவாய்ந்த கருவியாக இருந்தாலும், மாற்று அணுகுமுறைகள் மிகவும் பொருத்தமானதாக இருக்கும் சூழ்நிலைகள் உள்ளன:

முடிவுரை

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

டைப்ஸ்கிரிப்ட் இன்ஃபரில் தேர்ச்சி பெறுதல்: மேம்பட்ட வகை கையாளுதலுக்கான நிபந்தனை வகை பிரித்தெடுத்தல் | MLOG