Chapter 4: एडवांस्ड फीचर्स (Advanced Features)

Chapter 4: एडवांस्ड फीचर्स (Advanced Features)

इस अध्याय में, हम TypeScript के कुछ एडवांस्ड फीचर्स के बारे में जानेंगे, जो आपके कोड को और भी अधिक शक्तिशाली और लचीला बना सकते हैं। ये फीचर्स आपको जटिल एप्लिकेशन्स को सरल और प्रभावी तरीके से विकसित करने में मदद करेंगे। हम मॉड्यूल्स (Modules), डेकोरेटर्स (Decorators), और मिक्सिन्स (Mixins) के बारे में विस्तार से चर्चा करेंगे। ये एडवांस्ड फीचर्स TypeScript की पूरी क्षमता का उपयोग करने और आपके कोड को अधिक संगठित और प्रबंधनीय बनाने के लिए आवश्यक हैं।

मॉड्यूल्स TypeScript में कोड को व्यवस्थित और पुनः उपयोग करने योग्य बनाने का एक महत्वपूर्ण साधन हैं। मॉड्यूल्स का उपयोग करके, हम कोड के विभिन्न हिस्सों को अलग-अलग फ़ाइलों में विभाजित कर सकते हैं और उन्हें आवश्यकता अनुसार आयात (import) और निर्यात (export) कर सकते हैं। इस सेक्शन में, हम TypeScript में मॉड्यूल्स के विभिन्न पहलुओं और उनके उपयोग के बारे में जानेंगे।

1. मॉड्यूल्स का परिचय (Introduction to Modules)

मॉड्यूल्स का उपयोग बड़े कोडबेस को छोटे-छोटे हिस्सों में विभाजित करने के लिए किया जाता है। इससे कोड को समझना और प्रबंधित करना आसान हो जाता है।

2. एक्सपोर्ट (Export)

एक्सपोर्ट का उपयोग उन कोड हिस्सों को एक्सपोर्ट करने के लिए किया जाता है जिन्हें हम अन्य मॉड्यूल्स में उपयोग करना चाहते हैं।

2.1 डिफॉल्ट एक्सपोर्ट (Default Export)

डिफॉल्ट एक्सपोर्ट का उपयोग तब किया जाता है जब हम केवल एक मान या क्लास को एक्सपोर्ट करना चाहते हैं।

// person.ts
export default class Person {
    constructor(public name: string, public age: number) {}
}

2.2 नामांकित एक्सपोर्ट (Named Export)

नामांकित एक्सपोर्ट का उपयोग तब किया जाता है जब हम एक ही मॉड्यूल से एक से अधिक मानों या क्लासेस को एक्सपोर्ट करना चाहते हैं।

// utils.ts
export function add(a: number, b: number): number {
    return a + b;
}

export function subtract(a: number, b: number): number {
    return a - b;
}

3. इम्पोर्ट (Import)

इम्पोर्ट का उपयोग उन कोड हिस्सों को आयात करने के लिए किया जाता है जिन्हें हमने किसी अन्य मॉड्यूल में एक्सपोर्ट किया है।

3.1 डिफॉल्ट इम्पोर्ट (Default Import)

डिफॉल्ट इम्पोर्ट का उपयोग डिफॉल्ट एक्सपोर्ट को आयात करने के लिए किया जाता है।

// main.ts
import Person from './person';

let person = new Person("Daniel", 30);
console.log(person);

3.2 नामांकित इम्पोर्ट (Named Import)

नामांकित इम्पोर्ट का उपयोग नामांकित एक्सपोर्ट को आयात करने के लिए किया जाता है।

// main.ts
import { add, subtract } from './utils';

console.log(add(10, 5)); // 15
console.log(subtract(10, 5)); // 5

4. इम्पोर्ट सब कुछ (Import Everything)

हम पूरे मॉड्यूल को भी एक नाम के तहत आयात कर सकते हैं।

// main.ts
import * as Utils from './utils';

console.log(Utils.add(10, 5)); // 15
console.log(Utils.subtract(10, 5)); // 5

5. पुनः निर्यात (Re-export)

कभी-कभी हमें एक मॉड्यूल को दूसरे मॉड्यूल से पुनः निर्यात करने की आवश्यकता होती है। यह पुनः उपयोगिता को बढ़ाता है।

// math.ts
export { add, subtract } from './utils';

डेकोरेटर्स (Decorators)

डेकोरेटर्स TypeScript में एक विशेष प्रकार का सिंटेक्स है जो क्लासेस, मेथड्स, प्रॉपर्टीज, और पैरामीटर्स के व्यवहार को संशोधित करने के लिए उपयोग किया जाता है। डेकोरेटर्स का उपयोग एनोटेशन और मेटाडेटा जोड़ने के लिए भी किया जा सकता है। इस सेक्शन में, हम TypeScript में डेकोरेटर्स के विभिन्न प्रकार और उनके उपयोग के बारे में जानेंगे।

1. डेकोरेटर्स का परिचय (Introduction to Decorators)

डेकोरेटर्स एक प्रकार का विशेष फंक्शन होता है जो किसी क्लास या क्लास के सदस्य को एनोटेट करने के लिए उपयोग किया जाता है। डेकोरेटर्स को @ सिंटेक्स का उपयोग करके लागू किया जाता है।

2. डेकोरेटर्स को सक्षम करना (Enabling Decorators)

डेकोरेटर्स का उपयोग करने के लिए, हमें TypeScript कॉन्फिगरेशन फाइल (tsconfig.json) में experimentalDecorators को सक्षम करना होता है।

{
  "compilerOptions": {
    "experimentalDecorators": true
  }
}

3. क्लास डेकोरेटर्स (Class Decorators)

क्लास डेकोरेटर्स का उपयोग किसी क्लास को एनोटेट करने के लिए किया जाता है। क्लास डेकोरेटर को एक पैरामीटर के रूप में क्लास को प्राप्त करने वाले फंक्शन के रूप में परिभाषित किया जाता है।

function sealed(constructor: Function) {
    Object.seal(constructor);
    Object.seal(constructor.prototype);
}

@sealed
class Greeter {
    greeting: string;

    constructor(message: string) {
    	this.greeting = message;
    }

    greet() {
    	return `Hello, ${this.greeting}`;
    }
}

4. मेथड डेकोरेटर्स (Method Decorators)

मेथड डेकोरेटर्स का उपयोग किसी क्लास मेथड को एनोटेट करने के लिए किया जाता है। मेथड डेकोरेटर को तीन पैरामीटर प्राप्त होते हैं: क्लास का प्रोटोटाइप, मेथड का नाम, और मेथड का डिस्क्रिप्टर।

function enumerable(value: boolean) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    	descriptor.enumerable = value;
    };
}

class Greeter {
    greeting: string;

    constructor(message: string) {
    	this.greeting = message;
    }

    @enumerable(false)
    greet() {
    	return `Hello, ${this.greeting}`;
    }
}

5. प्रॉपर्टी डेकोरेटर्स (Property Decorators)

प्रॉपर्टी डेकोरेटर्स का उपयोग किसी क्लास प्रॉपर्टी को एनोटेट करने के लिए किया जाता है। प्रॉपर्टी डेकोरेटर को दो पैरामीटर प्राप्त होते हैं: क्लास का प्रोटोटाइप और प्रॉपर्टी का नाम।

function format(formatString: string) {
    return function (target: any, propertyKey: string) {
    	let value = target[propertyKey];

    	const getter = () => {
        	return formatString.replace('{value}', value);
    	};

    	const setter = (newVal) => {
        	value = newVal;
    	};

    	Object.defineProperty(target, propertyKey, {
        	get: getter,
        	set: setter,
        	enumerable: true,
        	configurable: true,
    	});
    };
}

class Greeter {
    @format('Hello, {value}')
    greeting: string;

    constructor(message: string) {
    	this.greeting = message;
    }
}

let greeter = new Greeter("World");
console.log(greeter.greeting); // Hello, World

6. पैरामीटर डेकोरेटर्स (Parameter Decorators)

पैरामीटर डेकोरेटर्स का उपयोग किसी क्लास मेथड के पैरामीटर को एनोटेट करने के लिए किया जाता है। पैरामीटर डेकोरेटर को तीन पैरामीटर प्राप्त होते हैं: क्लास का प्रोटोटाइप, मेथड का नाम, और पैरामीटर की स्थिति।

function logParameter(target: any, propertyKey: string, parameterIndex: number) {
    const metadataKey = `__log_${propertyKey}_parameters`;

    if (Array.isArray(target[metadataKey])) {
    	target[metadataKey].push(parameterIndex);
    } else {
    	target[metadataKey] = [parameterIndex];
    }
}

class Greeter {
    greeting: string;

    constructor(message: string) {
    	this.greeting = message;
    }

    greet(@logParameter name: string) {
    	return `Hello, ${name}! ${this.greeting}`;
    }
}

let greeter = new Greeter("Welcome to TypeScript");
console.log(greeter.greet("Daniel")); // Hello, Daniel! Welcome to TypeScript

मिक्सिन्स (Mixins)

मिक्सिन्स TypeScript में कोड पुनः उपयोग और संरचना में सुधार लाने का एक शक्तिशाली तरीका है। मिक्सिन्स का उपयोग करके, हम कई क्लासेस की विशेषताओं को एक ही क्लास में जोड़ सकते हैं, जिससे कोड को अधिक लचीला और पुनः उपयोग करने योग्य बनाया जा सकता है। इस सेक्शन में, हम TypeScript में मिक्सिन्स के विभिन्न पहलुओं और उनके उपयोग के बारे में जानेंगे।

1. मिक्सिन्स का परिचय (Introduction to Mixins)

मिक्सिन्स का उपयोग एक क्लास में कई क्लासेस की विशेषताओं को जोड़ने के लिए किया जाता है। यह inheritance का एक वैकल्पिक तरीका है, जिससे हम कोड को अधिक संगठित और पुनः उपयोग करने योग्य बना सकते हैं।

2. सरल मिक्सिन (Simple Mixin)

एक सरल मिक्सिन को बनाने के लिए, हम एक फंक्शन का उपयोग करते हैं जो एक बेस क्लास लेता है और एक नया क्लास लौटाता है जो अतिरिक्त विशेषताओं को जोड़ता है।

class Person {
    constructor(public name: string) {}
}

function canSayHi<T extends new (...args: any[]) => {}>(Base: T) {
    return class extends Base {
    	sayHi() {
        	console.log(`Hi, my name is ${this.name}`);
    	}
    };
}

const PersonWithSayHi = canSayHi(Person);

const person = new PersonWithSayHi("Daniel");
person.sayHi(); // Hi, my name is Daniel

3. मिक्सिन्स के साथ कई विशेषताएँ जोड़ना (Combining Multiple Mixins)

हम कई मिक्सिन्स को एक ही क्लास में जोड़ सकते हैं, जिससे क्लास में कई विशेषताएँ और मेथड्स जोड़े जा सकते हैं।

class Person {
    constructor(public name: string) {}
}

function canSayHi<T extends new (...args: any[]) => {}>(Base: T) {
    return class extends Base {
    	sayHi() {
        	console.log(`Hi, my name is ${this.name}`);
    	}
    };
}

function canDance<T extends new (...args: any[]) => {}>(Base: T) {
    return class extends Base {
    	dance() {
        	console.log(`${this.name} is dancing`);
    	}
    };
}

const PersonWithSkills = canSayHi(canDance(Person));

const skilledPerson = new PersonWithSkills("Daniel");
skilledPerson.sayHi(); // Hi, my name is Daniel
skilledPerson.dance(); // Daniel is dancing

4. मिक्सिन्स के साथ टाइप सुरक्षा (Type Safety with Mixins)

TypeScript में मिक्सिन्स का उपयोग करते समय टाइप सुरक्षा सुनिश्चित करने के लिए हम इंटरफेसेस का उपयोग कर सकते हैं।

interface CanSayHi {
    sayHi(): void;
}

interface CanDance {
    dance(): void;
}

class Person {
    constructor(public name: string) {}
}

function canSayHi<T extends new (...args: any[]) => {}>(Base: T): T & (new (...args: any[]) => CanSayHi) {
    return class extends Base {
    	sayHi() {
        	console.log(`Hi, my name is ${this.name}`);
    	}
    };
}

function canDance<T extends new (...args: any[]) => {}>(Base: T): T & (new (...args: any[]) => CanDance) {
    return class extends Base {
    	dance() {
        	console.log(`${this.name} is dancing`);
    	}
    };
}

const PersonWithSkills = canSayHi(canDance(Person));

const skilledPerson = new PersonWithSkills("Daniel");
skilledPerson.sayHi(); // Hi, my name is Daniel
skilledPerson.dance(); // Daniel is dancing

5. मिक्सिन्स के साथ क्लास कंपोज़िशन (Class Composition with Mixins)

मिक्सिन्स का उपयोग क्लास कंपोज़िशन के साथ किया जा सकता है, जिससे हम कई क्लासेस की विशेषताओं को एक ही क्लास में जोड़ सकते हैं।

type Constructor<T = {}> = new (...args: any[]) => T;

function canEat<TBase extends Constructor>(Base: TBase) {
    return class extends Base {
    	eat() {
        	console.log(`${this.name} is eating`);
    	}
    };
}

function canSleep<TBase extends Constructor>(Base: TBase) {
    return class extends Base {
    	sleep() {
        	console.log(`${this.name} is sleeping`);
    	}
    };
}

class Person {
    constructor(public name: string) {}
}

const PersonWithHabits = canEat(canSleep(Person));

const personWithHabits = new PersonWithHabits("Daniel");
personWithHabits.eat(); // Daniel is eating
personWithHabits.sleep(); // Daniel is sleeping



Table of Contents

Index