<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Juan Eneque</title>
    <description>The latest articles on DEV Community by Juan Eneque (@juaneq).</description>
    <link>https://dev.to/juaneq</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F939919%2F61dd40c3-b3fc-4f01-8aff-81119cf97495.jpeg</url>
      <title>DEV Community: Juan Eneque</title>
      <link>https://dev.to/juaneq</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/juaneq"/>
    <language>en</language>
    <item>
      <title>Unit Test #1: doing a simple unit test with typescript + jest</title>
      <dc:creator>Juan Eneque</dc:creator>
      <pubDate>Tue, 18 Jul 2023 23:34:45 +0000</pubDate>
      <link>https://dev.to/juaneq/unit-test-1-doing-a-simple-unit-test-with-typescript-jest-2oe1</link>
      <guid>https://dev.to/juaneq/unit-test-1-doing-a-simple-unit-test-with-typescript-jest-2oe1</guid>
      <description>&lt;p&gt;Hello everyone 🙋‍♂️, in this post I'm going to explain how to do a simple unit test with typescript and jest.&lt;/p&gt;




&lt;p&gt;First of all, I'll make a function that solves the problem known as &lt;strong&gt;fizzbuzz&lt;/strong&gt; and then I'll unit test the solution.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Fizzbuzz problem&lt;/strong&gt;: Write a code that prints numbers from 1 to 100 to the console. If the number is a multiple of 3, print the word “fizz”. If the number is a multiple of 5, print the word "buzz". If the number is a multiple of 3 and 5, print the word "fizzbuzz".&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To solve the problem, let's create a main class and add a function called fizzbuzz that takes a parameter and evaluates it based on the given conditions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 01-basic.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nx"&gt;fizzbuzz&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fizz buzz&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fizz&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;buzz&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's create a &lt;strong&gt;spec file&lt;/strong&gt; and write the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 01-basic.spec.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Main&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./01-basic&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@MainTest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👨‍🏫 &lt;strong&gt;Explanation:&lt;/strong&gt; We just create the container for unit tests. &lt;strong&gt;Describe function&lt;/strong&gt; takes two parameters, the first ('@MainTest') is its name and you can name it whatever you want. The second is a &lt;strong&gt;jest function&lt;/strong&gt; and inside it we create a variable of the type of our class and then initialize it in a structure called beforeEach. As its name says, inside it we put all the variables or functions that need to be initialized or executing before executing the unit test.&lt;/p&gt;




&lt;p&gt;Before writing our first use case for testing, &lt;strong&gt;we need to read about a well-known pattern for writing tests&lt;/strong&gt;: &lt;a href="https://automationpanda.com/2020/07/07/arrange-act-assert-a-pattern-for-writing-good-tests/"&gt;PATTERN ARRANGE-ACT-ASSERT&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Following the pattern, let's write ✍️ the solution to our first use case:&lt;br&gt;
&lt;em&gt;&lt;strong&gt;Test #1:&lt;/strong&gt; call function with a number multiple of 3 and 5 and return 'fizzbuzz'&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Arrange =&amp;gt; create a constant with the number to evaluate.&lt;/li&gt;
&lt;li&gt;Act =&amp;gt; evaluate the number in the fizzbuzz function.&lt;/li&gt;
&lt;li&gt;Assert =&amp;gt; compare the output of the fizzbuzz function and the expected result.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Pattern Arrange-Act-Assert&lt;/span&gt;
&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should return fizz buzz if number es mod 3 and 5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// arrange&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numberToEvaluate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// act&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fizzbuzz&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numberToEvaluate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// assert&lt;/span&gt;
  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fizz buzz&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running jest test command, we get the following output 👍:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oGic4WlA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/afy42et8fii6f7purj4g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oGic4WlA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/afy42et8fii6f7purj4g.png" alt="Result of run first test case" width="613" height="493"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, you need to create all the tests necessary to cover 💯 percent of the class.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;I hope this post has helped you 👍. I'll make other posts with other examples that I know might be helpful 🤝.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution repository:&lt;/strong&gt; &lt;a href="https://github.com/JuanSW18/unit-test-examples/blob/master/01-basic.spec.ts"&gt;https://github.com/JuanSW18/unit-test-examples/blob/master/01-basic.spec.ts&lt;/a&gt;&lt;/p&gt;

</description>
      <category>unittest</category>
      <category>jest</category>
      <category>typescript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Angular +SheetJS: 3 formas para crear un excel</title>
      <dc:creator>Juan Eneque</dc:creator>
      <pubDate>Wed, 19 Oct 2022 04:19:03 +0000</pubDate>
      <link>https://dev.to/juaneq/angular-sheetjs-3-formas-para-crear-un-excel-1f0d</link>
      <guid>https://dev.to/juaneq/angular-sheetjs-3-formas-para-crear-un-excel-1f0d</guid>
      <description>&lt;p&gt;En este tutorial les mostrare 3 formas para generar un Excel con la ayuda de la librería &lt;a href="https://www.npmjs.com/package/xlsx"&gt;SheetJS&lt;/a&gt;. También haré uso de la Pokemon API para trabajar con datos reales.&lt;/p&gt;

&lt;h2&gt;
  
  
  Paso 1: Crear proyecto angular e instalar dependencia
&lt;/h2&gt;

&lt;p&gt;Abrimos una consola CMD y ejecutamos el siguiente comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng new simple-excel-report
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nos ubicamos en la carpeta del proyecto con el comando cd e instalamos la librería SheetJS ejecutando el siguiente comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i xlsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Paso 2: Integrando Pokemon API
&lt;/h2&gt;

&lt;p&gt;Para este caso solo haré uso del siguiente endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://pokeapi.co/api/v2/pokemon/?limit=5&amp;amp;offset=0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Módulo para servicios compartidos
&lt;/h3&gt;

&lt;p&gt;Crearemos nuestro SharedModule y en el servicio para consultar el API. Ejecutamos los siguientes comandos en la consola:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng g module shared

ng g service shared/services/pokemon
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Importar módulo HTTP
&lt;/h3&gt;

&lt;p&gt;Ahora, en el archivo &lt;strong&gt;&lt;em&gt;shared.module.ts&lt;/em&gt;&lt;/strong&gt; importamos el HttpClientModule para poder realizar peticiones http:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* shared.module.ts */
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http'

@NgModule({
  declarations: [],
  imports: [
    CommonModule,
    HttpClientModule
  ]
})
export class SharedModule { }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Interfaces
&lt;/h3&gt;

&lt;p&gt;Dentro de la carpeta &lt;em&gt;&lt;strong&gt;shared&lt;/strong&gt;&lt;/em&gt;, crearemos una subcarpeta llamada &lt;strong&gt;&lt;em&gt;interfaces&lt;/em&gt;&lt;/strong&gt; y dentro de ella, el archivo &lt;strong&gt;&lt;em&gt;pokemon-response.interface.ts&lt;/em&gt;&lt;/strong&gt;, el cual tendrá el siguiente contenido:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* pokemon-response.interface.ts */
export interface IPokemonResponse {
  count: number;
  next: string;
  previous: string;
  results: IPokemonInfo[]
}

export interface IPokemonInfo {
  name: string;
  url: string;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Crear consulta http
&lt;/h3&gt;

&lt;p&gt;Abrimos el archivo &lt;em&gt;&lt;strong&gt;pokemon.service.ts&lt;/strong&gt;&lt;/em&gt; y en el constructor inyectamos el HttpClient de la siguiente manera:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;constructor(private network: HttpClient) { }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Luego, creamos nuestro método &lt;em&gt;&lt;strong&gt;getPokemonList&lt;/strong&gt;&lt;/em&gt; para hacer la petición GET que traerá la lista de pokemones:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;readonly API_BASE = 'https://pokeapi.co/api/v2';

getPokemonList(offset: number, limit: number): Observable&amp;lt;IPokemonResponse&amp;gt; {
    const endpoint = `${this.API_BASE}/pokemon/?offset=${offset}&amp;amp;limit=${limit}`;
    return this.network.get&amp;lt;IPokemonResponse&amp;gt;(endpoint);
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como podrán notar, agregamos 2 parámetros (offset y limit) en el método:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;offset&lt;/strong&gt;: ID del pokemon inicial de la lista de respuesta&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;limit&lt;/strong&gt;: cantidad de pokemones subsiguientes al offset.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Paso 3: Servicio para generar reporte
&lt;/h2&gt;

&lt;p&gt;Desde la consola, ejecutamos el siguiente comando para generar el servicio:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng g service shared/services/excel-report
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Forma #1: Configuración por default
&lt;/h3&gt;

&lt;p&gt;Abrimos el archivo &lt;strong&gt;&lt;em&gt;excel-report.service.ts&lt;/em&gt;&lt;/strong&gt; y definimos el método generateDefaultReport:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;generateDefaultReport(data: IPokemonInfo[], filename: string) {
    let workbook = XLSX.utils.book_new();
    let worksheet = XLSX.utils.json_to_sheet(data);

    // first way to add a sheet
    workbook.SheetNames.push('Hoja 1');
    workbook.Sheets['Hoja 1'] = worksheet;

    // second way to add a sheet
    // XLSX.utils.book_append_sheet(workbook, worksheet, "Hoja 1")

    XLSX.writeFileXLSX(workbook, filename, {});
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este método recibe 2 parámetros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;data: Arreglo de objectos de tipo IPokemonInfo.&lt;/li&gt;
&lt;li&gt;filename: Nombre del archivo (Ej: mi_reporte.xlsx).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;El problema con esta forma es que los headers (fila A1 del Excel) son asignados automáticamente y estos serán igual al nombre de los atributos del objeto. En otras palabras, nuestros headers serán name y url (atributos de IPokemonInfo).&lt;/p&gt;

&lt;h3&gt;
  
  
  Forma #2: Usando diccionario
&lt;/h3&gt;

&lt;p&gt;Primero crearemos una interface con el nombre &lt;strong&gt;&lt;em&gt;custom-header.interface.ts&lt;/em&gt;&lt;/strong&gt; y con la siguiente estructura:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export interface ICustomHeader {
  name: string;
  key: string;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta interface nos ayudará a construir un diccionario relación, donde &lt;strong&gt;&lt;em&gt;name&lt;/em&gt;&lt;/strong&gt; es el nombre de la columna y &lt;strong&gt;&lt;em&gt;key&lt;/em&gt;&lt;/strong&gt; es el nombre del atributo de la interface &lt;strong&gt;&lt;em&gt;IPokemonInfo&lt;/em&gt;&lt;/strong&gt;. Ej:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;name: "Info URL"&lt;/li&gt;
&lt;li&gt;key: url
Teniendo esta relación definida, podemos generar un excel con headers personalizados.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A continuación, abrimos el archivo &lt;strong&gt;&lt;em&gt;excel-report.service.ts&lt;/em&gt;&lt;/strong&gt; y definimos el método generateReportWithDict:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;generateReportWithDict(customHeaders: ICustomHeader[], data: IPokemonInfo[], filename: string) {
    let worksheetData: any[] = [];

    Object(data).forEach( (item: any) =&amp;gt; {
      let worksheetItem = Object();
      customHeaders.forEach( header =&amp;gt; {
        worksheetItem[header.name] = item[header.key];
      })
      worksheetData.push(worksheetItem)
    })

    // excel file
    let workbook = XLSX.utils.book_new();
    let worksheet = XLSX.utils.json_to_sheet(worksheetData);
    XLSX.utils.book_append_sheet(workbook, worksheet, "Hoja 1")
    XLSX.writeFileXLSX(workbook, filename, {});
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este método recibe 3 parámetros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;customHeaders: Arreglo de objectos ICustomHeader.&lt;/li&gt;
&lt;li&gt;data: Arreglo de objectos de tipo IPokemonInfo.&lt;/li&gt;
&lt;li&gt;filename: Nombre del archivo (Ej: mi_reporte.xlsx).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Una de las ventajas de trabajar de esta forma es que nosotros podemos definir el orden de las columnas gracias a la relación name-key.&lt;/p&gt;

&lt;h3&gt;
  
  
  Forma #3: Usando un adapter
&lt;/h3&gt;

&lt;p&gt;Creamos una carpeta adapter y dentro de ella, añadimos el archivo &lt;strong&gt;&lt;em&gt;pokemon-report.class.ts&lt;/em&gt;&lt;/strong&gt; con el siguiente contenido:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { IPokemonInfo } from "../interfaces/pokemon-response.interface";

export interface IPokemonReport {
  pokemonId: number;
  pokemonName: string;
  pokemonUrlInfo: string;
}


export class PokemonReportAdapter {
  data: IPokemonReport[] = [];

  constructor(pokemonList: IPokemonInfo[]) {
    pokemonList.forEach( (pokemon, index) =&amp;gt; {
      const reportItem: IPokemonReport = {
        pokemonId: index + 1,
        pokemonName: pokemon.name,
        pokemonUrlInfo: pokemon.url
      }
      this.data.push(reportItem);
    })
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Una ventaja de usar un adapter, es que podemos realizar operaciones y/o procesar los datos de nuestro objeto para posteriormente asignarlos en un nuevo modelo. En este caso, definimos una interface &lt;em&gt;&lt;strong&gt;IPokemonReport&lt;/strong&gt;&lt;/em&gt; que usaremos para generar un nuevo arreglo de datos a partir de nuestra data (IPokemonInfo).&lt;/p&gt;

&lt;p&gt;Finalmente, abrimos el archivo &lt;strong&gt;&lt;em&gt;excel-report.service.ts&lt;/em&gt;&lt;/strong&gt; y definimos el método generateReportWithAdapter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;generateReportWithAdapter(headers: string[], data: IPokemonReport[], filename: string) {
    let workbook = XLSX.utils.book_new();
    let worksheet = XLSX.utils.json_to_sheet([], { header: headers });

    XLSX.utils.sheet_add_json(worksheet, data, { origin: 'A2', skipHeader: true })

    XLSX.utils.book_append_sheet(workbook, worksheet, "Hoja 1")
    XLSX.writeFileXLSX(workbook, filename);
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este método recibe 3 parámetros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;headers: Arreglo de string, donde cada item representa el header de cada columna.&lt;/li&gt;
&lt;li&gt;data: Arreglo de objectos de tipo IPokemonInfo&lt;/li&gt;
&lt;li&gt;filename: Nombre del archivo (Ej: mi_reporte.xlsx)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Una consideración importante respecto a esta forma es el orden en que se definen el nombre de los header ya que tienen que tener el mismo orden en que se definen los atributos de la nueva interface (IPokemonReport).&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Espero les haya sido de utilidad este tutorial 👍.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Link del repositorio:&lt;/strong&gt; &lt;a href="https://github.com/JuanSW18/simple-excel-report"&gt;simple-excel-report&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>angular</category>
      <category>webdev</category>
      <category>community</category>
    </item>
  </channel>
</rss>
