# Mapping Types and Decorators in TypeScript

In a previous blog post, we explored the powerful combination of OpenAPI and [NestJS](https://github.com/nestjs/nest), delving into their capabilities within the [NestJS framework](https://nestjs.com/).

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><a target="_blank" rel="noopener noreferrer nofollow" href="https://blog.bytescrum.com/exploring-openapi-boost-your-api-efficiency-and-security" style="pointer-events: none">What is an Open API? (</a><a target="_blank" rel="noopener noreferrer nofollow" href="http://bytescrum.com" style="pointer-events: none">bytescrum.com</a><a target="_blank" rel="noopener noreferrer nofollow" href="https://blog.bytescrum.com/exploring-openapi-boost-your-api-efficiency-and-security" style="pointer-events: none">)</a></div>
</div>

Let's take a look at each component and how they work together: **OpenAI,** [**NestJS**](https://kinsta.com/knowledgebase/nestjs/)**, and** [**Mapped Types**](https://github.com/mapstruct/mapstruct/issues/875)**.**

**OpenAI:** OpenAI developed GPT models, capable of understanding and generating human-like text, for natural language processing tasks like text generation, translation, and content summarization.  
[**NestJS**](https://www.udemy.com/course/nestjs-the-complete-developers-guide/)**:** [NestJS](https://www.turing.com/blog/what-is-nest-js-why-use-it/) is a [TypeScript](https://www.typescriptlang.org/)\-based backend framework for efficient, scalable, and maintainable server-side applications, built on Node.js and inspired by Angular. It supports structured, organized applications like APIs and microservices.

For a comprehensive walkthrough, please refer to the previous post.

[**Mapped Types:**](https://www.ibm.com/docs/en/developer-for-zos/9.1.1?topic=concepts-types-mappings)

[Mapped types](https://reflectoring.io/java-mapping-with-mapstruct/) are a [TypeScript](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html) feature that allows you to modify and control a type's attributes. They are used to generate new kinds from existing types, frequently by altering or converting specific attributes.

## Step by Step [Mapped Types](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html) in TypeScript

### Step 1: Create a [NestJS Project](https://www.educative.io/answers/what-is-nestjs)

* If you haven't already, install Node.js and npm (Node Package Manager).
    
* Install [NestJS](https://www.freecodecamp.org/news/build-web-apis-with-nestjs-beginners-guide/) CLI globally: **<mark>npm install -g @nestjs/cli.</mark>**
    
* Create a new NestJS project: **<mark>nest new my-openai-app</mark>**
    

### Step 2: Add Dependencies

* Go to your project directory by typing **<mark>cd my-openai-app.</mark>**
    
* Install the necessary dependencies by running **<mark>npm install axios @nestjs/common @nestjs/core.</mark>**
    

### Step 3: Develop an OpenAI Service

* Create a new service file, such as **<mark>openai.service.ts</mark>**, within the source code of your project.
    
* To perform HTTP calls to the OpenAI, use the <mark>axios library</mark>.
    
* Define techniques for communicating with the OpenAI API, such as text creation via submitting text.
    

```typescript
//openai.service.ts
import { Injectable } from '@nestjs/common';
import axios from 'axios';

@Injectable()
export class OpenAiService {
  private openAiApiUrl = 'https://api.openai.com/v1';

  async generateText(prompt: string): Promise<string> {
    const response = await axios.post(`${this.openAiApiUrl}/engines/davinci-codex/completions`, {
      prompt,
      max_tokens: 50,
    }, {
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer YOUR_OPENAI_API_KEY',
      },
    });

    return response.data.choices[0]?.text || '';
  }
}
```

### Step 4: Create a new controller file

* Make a new controller file, such as **<mark>app.controller.ts.</mark>**
    
* Import the [**<mark>OpenAiService</mark>**](https://azure.microsoft.com/en-us/products/ai-services/openai-service) into the controller
    
* Create an API endpoint that generates text using the OpenAI service.
    

```typescript
//app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { OpenAiService } from './openai.service';

@Controller()
export class AppController {
  constructor(private readonly openAiService: OpenAiService) {}

  @Get('generate-text')
  async generateText(): Promise<string> {
    const prompt = 'Once upon a time';
    const generatedText = await this.openAiService.generateText(prompt);
    return generatedText;
  }
}
```

### **Step 5: Start your NestJS application**

* Run Your [NestJS Application](https://blog.bytescrum.com/microservices-in-nestjs) <mark>npm run start:dev.</mark>
    
* In your browser or API tool, navigate to the created text endpoint:
    
    [http://localhost:3000/generate-text](http://localhost:3000/generate-text).
    

This example showcases using OpenApi's capabilities in a [NestJS application](https://blog.bytescrum.com/implementing-2fa-in-nestjs-a-step-by-step-guide-for-better-security), using an OpenAi service and controller to generate text based on a prompt. Adjust to suit use case, handle error cases, and follows security best practices.

[**Decorators**](https://sunnysun-5694.medium.com/how-to-map-rest-api-data-using-decorator-pattern-in-angular-6-94eb49ba16b1) **in** [**TypeScript**](https://www.javatpoint.com/typescript-tutorial)**:**

[Decorators](https://shapeshift.krud.dev/features/decorators) are [TypeScript](https://en.wikipedia.org/wiki/TypeScript) feature that allows you to annotate classes, methods, properties, and parameters throughout the design process. They make it possible to add metadata or behavior to your code in a clean and modular fashion.

## Step-by-Step [**Decorators**](https://www.geeksforgeeks.org/decorators-in-python/) **in** [**TypeScript**](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html)

### Step 1: Create a [NestJS Project](https://blog.bytescrum.com/how-to-create-a-graphql-server-with-nestjs-and-typescript)

* If you haven't already, install [Node.js](https://nodejs.org/en) and [npm](https://www.npmjs.com/) (Node Package Manager).
    
* Install [NestJS](https://blog.bytescrum.com/how-to-create-a-graphql-server-with-nestjs-and-typescript) CLI globally: **<mark>npm install -g @nestjs/cli.</mark>**
    
* Create a new [NestJS](https://blog.bytescrum.com/exploring-openapi-boost-your-api-efficiency-and-security) project: **<mark>nest new my-openai-app</mark>**
    

### Step 2: Add Dependencies

* Go to your project directory by typing **<mark>cd my-openai-app.</mark>**
    
* Install the necessary dependencies by running **<mark>npm install axios @nestjs/common @nestjs/core.</mark>**
    

### Step 3: Create a New Decorator File

* Create a new decorator file within your project's source code, such as **<mark>decorators/openai.decorator.ts.</mark>**
    
* Create a custom [decorator](https://www.javatpoint.com/angular-decorators) that will be used to identify methods that need OpenAI text creation.
    

```typescript
//openai.decorator.ts
import { SetMetadata } from '@nestjs/common';

export const OpenAiGeneratedText = (prompt: string) => SetMetadata('openAiPrompt', prompt);
```

### Step 4: Create a New Interceptor File

* Create an [OpenAI Interceptor](https://github.com/TheoKanning/openai-java/blob/main/client/src/main/java/com/theokanning/openai/AuthenticationInterceptor.j) **<mark>interceptors/openai.interceptor.ts.</mark>**
    
* Extract the [OpenAi](https://www.openxcell.com/blog/new-features-you-can-integrate-into-your-web-app-using-openai-api/) prompt from the custom decorator and contact the [OpenAi](https://www.wionews.com/science/openai-may-go-bankrupt-by-end-of-2024-costs-700k-to-operate-chatgpt-daily-report-625016) service to create text in this interceptor.
    
    ```typescript
    //openai.interceptor.ts
    import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
    import { Observable } from 'rxjs';
    import { map } from 'rxjs/operators';
    import { OpenAiService } from '../openai.service';
    
    @Injectable()
    export class OpenAiInterceptor implements NestInterceptor {
      constructor(private readonly openAiService: OpenAiService) {}
    
      intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
        const prompt = Reflect.getMetadata('openAiPrompt', context.getHandler());
        
        return next.handle().pipe(
          map(async (data) => {
            const generatedText = await this.openAiService.generateText(prompt);
            return { ...data, generatedText };
          }),
        );
      }
    }
    ```
    
    ### Step 5: Import and Use the Custom Decorator along with the [OpenAI Interceptor](https://theintercept.com/2023/05/08/chatgpt-ai-pentagon-military/)
    
* Import and utilize the custom decorator along with the [OpenAI interceptor](https://community.openai.com/t/sample-code-for-function-calling/264135) in
    
    your controller to create text for particular methods.
    

```typescript
//app.controller.ts
import { Controller, Get, UseInterceptors } from '@nestjs/common';
import { OpenAiGeneratedText } from './decorators/openai.decorator';
import { OpenAiInterceptor } from './interceptors/openai.interceptor';

@Controller()
export class AppController {
  @Get('story')
  @UseInterceptors(OpenAiInterceptor)
  @OpenAiGeneratedText('Once upon a time')
  async getStory(): Promise<any> {
    return { message: 'Story retrieved successfully' };
  }
}
```

### Step 6: Start your NestJS Application

* Begin your NestJS application by typing: **<mark>npm run start:dev.</mark>**
    
* In your browser or API tool, navigate to the produced narrative endpoint: [**<mark>http://localhost:3000/story</mark>**](http://localhost:3000/story)**<mark>.</mark>**
    

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Custom<a target="_blank" rel="noopener noreferrer nofollow" href="https://machinelearningmastery.com/a-gentle-introduction-to-decorators-in-python/" style="pointer-events: none"> decorators</a> and interceptors integrate OpenAI's text generation into the NestJS application, marking methods with desired prompts and automatically generating text. Real-world scenarios may require additional considerations for error handling, security, and optimization.</div>
</div>

[Mapping Types and Decorators](https://stackoverflow.com/questions/56140221/why-is-this-mapped-type-removing-the-decorator-how-can-we-achieve-a-similar) in [TypeScript](https://www.geeksforgeeks.org/typescript/) investigates the use of OpenAI and NestJS to develop server-side apps. [Decorators](https://realpython.com/primer-on-python-decorators/) provide metadata or behavior to your code, whereas [mapped types](https://www.icsm.gov.au/education/fundamentals-mapping/types-maps) change existing types. The article walks you through the process of integrating [OpenAI](https://blog.gopenai.com/creating-a-grammar-correction-application-with-openai-apis-3e8d4b731e46) text creation into a NestJS application using custom [decorators](https://www.typescriptlang.org/docs/handbook/decorators.html) and interceptors.

to be continued...

<details data-node-type="hn-details-summary"><summary>Summary</summary><div data-type="detailsContent">Finally, <a target="_blank" rel="noopener noreferrer nofollow" href="https://mapstruct.org/documentation/1.0/api/org/mapstruct/DecoratedWith.html" style="pointer-events: none">Mapped Types and Decorators</a> in <a target="_blank" rel="noopener noreferrer nofollow" href="https://github.com/microsoft/TypeScript" style="pointer-events: none">TypeScript </a>allow developers to use the <a target="_blank" rel="noopener noreferrer nofollow" href="https://blog.bytescrum.com/nest-and-openapiswagger-integration-for-development" style="pointer-events: none">NestJS</a> framework to construct fast, scalable, and maintainable server-side applications. By using OpenAI's text-generating capabilities, you may improve the functionality of your application while keeping a clean and modular codebase. In real-world settings, keep error management, security, and optimization in mind.</div></details>
