Bundle size considerations when using typescript

Mar 9, 2022 by

Intro

Tras cada nueva versión, Typescript trae nuevas características que hacen la vida del desarrollador mucho más facil.

Como por ejemplo:

  • Enums
  • Null coalescing operator
  • Optional chaining
  • Unions and Intersection Types
  • etc

Es muy tentador usar todas esas nuevas características en nuestros proyectos, pero no todo es oro lo que reluce.

No debemos olvidar que Typescript compila en Javacript. Según el tipo de target que definamos en nuestra configuración de Typescript el tiempo inicial de carga de nuestra app puede verse afectado.

Incluso usando el target de compilación más moderno, puede ser que algunas de las características no estén soportadas aún. Es aquí donde los polyfills o incluso el output the la build de Typescript nos puede dar dolores de cabeza en cuanto de bundle size y de loading time se refiere.

En las secciones siguientes podemos ver dos formas de reducir la salida de código Javascript preveniendo el uso de Enums y Class.

Enums vs Types

Examinemos el siguiente trozo de código:

1
2
3
4
5
export enum ExceptionTypes {
  error = "error",
  info = "info",
  warn = "warn",
}

Este código Typescript producirá una salida Javascript como la siguiente:

1
2
3
4
5
6
export var ExceptionTypes;
(function (ExceptionTypes) {
    ExceptionTypes["error"] = "error";
    ExceptionTypes["info"] = "info";
    ExceptionTypes["warn"] = "warn";
})(ExceptionTypes || (ExceptionTypes = {}));

Comparemos ahora la versión Typescript sin Enum

1
2
3
4
export type ExceptionTypeError = 'error';
export type ExceptionTypeInfo = 'info';
export type ExceptionTypeWarn = 'warn';
export type ExceptionTypes = ExceptionTypeError | ExceptionTypeInfo | ExceptionTypeWarn;

En este caso, todo el typing se omite en la versión Javascript ⚡.

1
export {};

Classes vs Interfaces

Examinemos el siguiente trozo de código:

1
2
3
4
5
6
7
8
9
10
11
12
export abstract class Exception extends Error {
  abstract type: ExceptionTypes;
}
export class ErrorException extends Exception {
  public readonly type = ExceptionTypes.error;
}
export class InfoException extends Exception {
  public readonly type = ExceptionTypes.info;
}
export class WarningException extends Exception {
  public readonly type = ExceptionTypes.warn;
}

Este código Typescript producirá una salida Javascript como la siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
export class Exception extends Error {
}
export class ErrorException extends Exception {
    constructor() {
        super(...arguments);
        this.type = ExceptionTypes.error;
    }
}
export class InfoException extends Exception {
    constructor() {
        super(...arguments);
        this.type = ExceptionTypes.info;
    }
}
export class WarningException extends Exception {
    constructor() {
        super(...arguments);
        this.type = ExceptionTypes.warn;
    }
}

Comparemos ahora la versión Typescript sin clases usando solo interfaces:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
export interface Exception extends Error {
  type: ExceptionTypes;
  message: string;
}
export interface ErrorException extends Exception {
  readonly type: ExceptionTypeError;
}

export interface InfoException extends Exception {
readonly type: ExceptionTypeInfo;
}
export interface WarningException extends Exception {
readonly type: ExceptionTypeWarn;
}

En este caso, todo el typing se omite en la versión Javascript ⚡.

1
export {};

Latest Posts

Adding storybook to nx angular workspace
Published: Apr 29, 2022

In the last days in my team we were moving from a custom “dev ui” written in angular to storybook. During the process we faced several challenges that I would like to share with you here.

Bundle size considerations when using typescript
Published: Mar 9, 2022

Extensions/Plugins based App
Published: Feb 13, 2022

Series about micro front-ends in angular.