Поддерживаемые конструкции TypeScript

Библиотека SWC (Speedy Web Compiler) предоставляет полноценную поддержку синтаксиса TypeScript и способна выполнять высокоскоростную трансиляцию исходного кода в JavaScript без участия компилятора TypeScript. Основная задача SWC заключается в преобразовании типизированного кода в исполняемый JavaScript с удалением всех конструкций, используемых исключительно во время проверки типов.

Поддержка TypeScript является одной из ключевых возможностей SWC, поскольку современные веб-приложения активно используют типизацию для повышения надежности кода, улучшения поддержки IDE и упрощения сопровождения крупных проектов.

SWC понимает большинство возможностей языка TypeScript и корректно обрабатывает их на этапе трансформации.


Удаление аннотаций типов

Наиболее распространённой конструкцией TypeScript являются аннотации типов.

Исходный код:

const name: string = "John";
const age: number = 25;

После обработки SWC:

const name = "John";
const age = 25;

Типы полностью удаляются, поскольку они не существуют во время выполнения программы.

Поддерживаются:

  • примитивные типы;
  • литеральные типы;
  • объединения;
  • пересечения;
  • пользовательские типы;
  • сложные вложенные структуры.

Пример:

let value: string | number;

Результат:

let value;

Интерфейсы

Интерфейсы используются исключительно системой типов и не влияют на выполнение программы.

Код TypeScript:

interface User {
    id: number;
    name: string;
}

После трансформации:

Интерфейс полностью исчезает из итогового JavaScript.

Более сложный пример:

interface Employee extends User {
    department: string;
}

Результат:

SWC удаляет все объявления интерфейсов независимо от уровня вложенности и сложности наследования.


Type Alias

Псевдонимы типов также относятся исключительно к системе типизации.

Исходный код:

type UserId = number;

type User = {
    id: UserId;
    name: string;
};

После преобразования:

Все объявления type удаляются.

Поддерживаются:

  • объектные типы;
  • объединения;
  • пересечения;
  • условные типы;
  • отображаемые типы;
  • рекурсивные типы.

Пример:

type ApiResponse<T> =
    | { success: true; dat a: T }
    | { success: false; error: string };

После трансиляции:


Generic-параметры

Обобщения (Generics) широко применяются для создания переиспользуемых компонентов.

Код:

function identity<T>(value: T): T {
    return value;
}

Результат:

function identity(value) {
    return value;
}

Параметры типа удаляются полностью.

Пример с несколькими параметрами:

function merge<T, U>(a: T, b: U): T & U {
    return {
        ...a,
        ...b
    };
}

После обработки:

function merge(a, b) {
    return {
        ...a,
        ...b
    };
}

Generic-классы

SWC корректно обрабатывает обобщённые классы.

Исходный код:

class Repository<T> {
    private items: T[] = [];

    add(item: T): void {
        this.items.push(item);
    }
}

Результат:

class Repository {
    items = [];

    add(item) {
        this.items.push(item);
    }
}

Вся информация о типах удаляется.


Enum

Перечисления являются одной из немногих конструкций TypeScript, которые генерируют JavaScript-код.

Числовые перечисления

TypeScript:

enum Status {
    Pending,
    Active,
    Archived
}

SWC генерирует:

var Status;

(function(Status) {
    Status[Status["Pending"] = 0] = "Pending";
    Status[Status["Active"] = 1] = "Active";
    Status[Status["Archived"] = 2] = "Archived";
})(Status || (Status = {}));

Создается объект с прямым и обратным отображением значений.


Строковые перечисления

Исходный код:

enum Role {
    Admin = "admin",
    User = "user"
}

Результат:

var Role;

(function(Role) {
    Role["Admin"] = "admin";
    Role["User"] = "user";
})(Role || (Role = {}));

Обратное отображение для строковых значений не создается.


Const Enum

Константные перечисления могут быть встроены непосредственно в код.

Исходный пример:

const enum Direction {
    Up,
    Down
}

const current = Direction.Up;

После трансформации:

const current = 0;

Подобная оптимизация позволяет избежать генерации дополнительного объекта перечисления.


Namespace

SWC поддерживает пространства имён TypeScript.

Исходный код:

namespace Utils {
    export function log(message: string) {
        console.log(message);
    }
}

После преобразования:

var Utils;

(function(Utils) {
    function log(message) {
        console.log(message);
    }

    Utils.log = log;
})(Utils || (Utils = {}));

Пространство имён преобразуется в JavaScript-модуль на основе IIFE.


Модификаторы доступа

TypeScript предоставляет набор модификаторов доступа:

  • public
  • private
  • protected

Пример:

class User {
    private password: string;
    protected token: string;
    public name: string;
}

После обработки:

class User {
    password;
    token;
    name;
}

Модификаторы удаляются, поскольку они не влияют на выполнение программы.


Parameter Properties

TypeScript позволяет одновременно объявлять свойства класса и параметры конструктора.

Код:

class User {
    constructor(
        private id: number,
        public name: string
    ) {}
}

SWC генерирует:

class User {
    id;
    name;

    constructor(id, name) {
        this.id = id;
        this.name = name;
    }
}

Создаются соответствующие свойства и инициализация внутри конструктора.


Abstract Classes

Абстрактные классы поддерживаются и преобразуются в обычные классы JavaScript.

Исходный код:

abstract class Animal {
    abstract speak(): void;
}

После трансформации:

class Animal {
}

Ключевые слова abstract удаляются.

Более сложный пример:

abstract class Animal {
    abstract speak(): void;

    move() {
        console.log("moving");
    }
}

Результат:

class Animal {
    move() {
        console.log("moving");
    }
}

Abstract Methods

Абстрактные методы существуют только на уровне типов.

TypeScript:

abstract class Service {
    abstract execute(): void;
}

Jav * aScript:

class Service {
}

Метод полностью удаляется.


Type Assertion

SWC поддерживает оба синтаксиса приведения типов.

Конструкция через as:

const element = document.body as HTMLBodyElement;

Результат:

const element = document.body;

Конструкция через угловые скобки:

const value = <string>data;

После обработки:

const value = data;

Non-Null Assertion

Оператор ! сообщает компилятору о гарантированном существовании значения.

Исходный код:

const text = element!.textContent;

Результат:

const text = element.textContent;

Оператор полностью удаляется.


Definite Assignment Assertion

Конструкция используется для полей класса.

TypeScript:

class User {
    name!: string;
}

После трансформации:

class User {
    name;
}

Type-only Imports

TypeScript позволяет импортировать сущности исключительно для проверки типов.

Исходный код:

import type { User } from "./types";

После преобразования:

Импорт удаляется полностью.


Type-only Exports

Поддерживаются также экспортируемые типы.

Исходный код:

export type {
    User,
    Product
};

После обработки:

Подобные конструкции не попадают в результирующий код.


Import Equals

TypeScript содержит специальную форму импорта.

Пример:

import fs = require("fs");

SWC способен обрабатывать подобный синтаксис в зависимости от выбранной конфигурации модулей.

После преобразования CommonJS:

const fs = require("fs");

Декораторы TypeScript

SWC поддерживает синтаксис декораторов при соответствующей настройке парсера.

Пример:

@Controller()
class UserController {
}

После трансформации декоратор преобразуется в вызовы вспомогательных функций согласно выбранной стратегии компиляции.

Поддерживаются:

  • декораторы классов;
  • декораторы методов;
  • декораторы свойств;
  • декораторы параметров.

Readonly-свойства

Конструкция:

class User {
    readonly id: number;
}

После обработки:

class User {
    id;
}

Ограничение на изменение значения существует только во время проверки типов.


Optional Properties

Необязательные свойства поддерживаются полностью.

Исходный код:

interface User {
    name?: string;
}

После трансформации:

Поскольку интерфейс удаляется, информация о необязательности свойства также исчезает.


Optional Parameters

Код:

function greet(name?: string) {
    console.log(name);
}

Результат:

function greet(name) {
    console.log(name);
}

Union Types

Объединения типов используются исключительно системой типов.

Исходный код:

let value: string | number;

После преобразования:

let value;

Intersection Types

Пример:

type User = Person & Employee;

После обработки:

Пересечения удаляются вместе с типовыми объявлениями.


Literal Types

Код:

type Method =
    | "GET"
    | "POST";

Результат:

Литеральные типы не оказывают влияния на итоговый JavaScript.


Conditional Types

Условные типы являются одной из самых мощных возможностей TypeScript.

Пример:

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

После трансформации:

SWC полностью удаляет подобные конструкции.


Mapped Types

Исходный код:

type ReadonlyUser = {
    readonly [K in keyof User]: User[K];
};

Результат:

Все отображаемые типы устраняются во время компиляции.


Infer

Поддерживается синтаксис вывода типов через infer.

Пример:

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

После преобразования:

Поскольку механизм работает исключительно на уровне типов, итоговый JavaScript не содержит никаких следов подобных конструкций.


Declare

Ключевое слово declare используется для описания внешних сущностей.

Код:

declare const API_URL: string;

Результат:

Объявление удаляется полностью.


Declare Namespace

Пример:

declare namespace Library {
    function init(): void;
}

После трансформации:

Все декларативные пространства имён исчезают из результирующего кода.


Ambient Modules

Типовые объявления модулей также поддерживаются.

Исходный код:

declare module "*.svg" {
    const content: string;
    export default content;
}

После обработки:

Такие конструкции существуют исключительно для системы типов.


Особенности поддержки TypeScript в SWC

Поддержка TypeScript в SWC строится вокруг фундаментального принципа: всё, что относится исключительно к типизации, удаляется, а всё, что имеет влияние на выполнение программы, преобразуется в эквивалентный JavaScript-код.

К конструкциям, генерирующим JavaScript, относятся:

  • enum;
  • const enum (с возможной инлайновой подстановкой);
  • namespace;
  • parameter properties;
  • декораторы;
  • классы и их поля.

Полностью удаляются:

  • интерфейсы;
  • псевдонимы типов;
  • generic-параметры;
  • условные типы;
  • отображаемые типы;
  • объединения и пересечения;
  • декларативные конструкции;
  • type-only imports и exports;
  • аннотации типов;
  • утверждения типов.

Благодаря такому подходу SWC обеспечивает чрезвычайно быструю трансиляцию TypeScript-кода и успешно используется в современных сборщиках, фреймворках и инструментах разработки как высокопроизводительная альтернатива традиционному компилятору TypeScript.