Основи синтаксису TypeScript



У 2012 році розробники C# компанії Microsoft створили мову TypeScript — надмножество JavaScript. Він призначений для розробки великих програм, від 100 тисяч рядків. Давайте на прикладах розглянемо синтаксис TypeScript, його основні переваги та недоліки, а також розберемо спосіб взаємодії з популярними бібліотеками.

Кому це буде корисно: Web-розробникам і розробникам клієнтських додатків, які цікавляться можливістю практичного застосування мови TypeScript.

Існують різні інструменти, які дозволяють писати компільований в JavaScript код: CoffeeScript, Dart, Uberscript та інші. До них відноситься і мова програмування TypeScript, що дозволяє виправити деякі недоліки, властиві JavaScript.

Недоліки JavaScript
  • Відсутність модульності — можуть виникати проблеми з-за конфлікту великих файлів.
  • Нелогічну поведінку.
  • Динамічна типізація — немає IntelliSense, з-за чого ми не бачимо, які помилки будуть виникати під час написання, а бачимо їх тільки під час виконання програми.
Основні переваги TypeScript
  • Статична типізація.
  • Компілюється в хороший JavaScript.
  • Наявність інструментів для розробника.
  • Нативний код добре читається, у ньому легко розібратися.
  • TypeScript підтримується багатьма інструментами для розробки: Visual Studio, PHP Storm і інші IDE.
  • Підтримується ECMAScript 6.0.
  • Компілятор знайде і видасть помилку невідповідності типів до початку компілювання.
Типи змінних, які підтримує TypeScript
  1. Number
  2. String
  3. Boolean
  4. Array
  5. Enum
  6. Any
  7. Void
Вони використовуються для оголошення змінних, функцій, класів, Generic-типів і інших конструкцій.


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

  • Необов'язковий параметр
    function имя_функции (ім'я_змінної?:тип): тип_возвращаемого_значения
     
    
  • Параметр за замовчуванням
    function имя_функции (ім'я_змінної?:тип = "значення"):тип_возвращаемого_значения
     
    
  • Однотипні параметри
    function имя_функции (...ім'я_змінної?:тип ):тип_возвращаемого_значения
     
    
За аналогією з C# знак питання після змінної означає, що її значення не можна передавати.

Оголошення функції

[csharp]
function getCarName(manufacturerName: string, model?: string): string {
if (model) {
return manufacturerName + " " + model;
}
return manufacturerName;
}
[/csharp]

Функції зворотного виклику

Ми також можемо передавати як параметр функцію.

[csharp]
function numberOperation(x: number, y: number, callback: (a: number, b: number) => number) {
return callback(x, y);
}

function addCallBackNumbers(x: number, y: number): number {
return x + y;
}

function multiplyNumbers(x: number, y: number): number {
return x * y;
}

console.log(numberOperation(5, 5, addCallBackNumbers)); // 10
console.log(numberOperation(5, 5, multiplyNumbers)); // 25
[/csharp]

Викликаючи функцію
numberOperation
, ми передаємо два параметра і функцію як callback'а.

Об'єднання і перевантаження функцій
Незважаючи на строгу типізацію, TS є можливість використовувати одну і ту ж функцію з різними типами переданих значень. Наприклад, в залежності від типу переданого значення, одна функція конкатенирует наші числа, а друга складає.

[csharp]
//передаємо 2 параметра стрінг і отримуємо рядок
function addOvverload(x: string, y: string): string;
//передаємо 2 параметра int і отримуємо int результ
function addOvverload(x: number, y: number): number;

function addOvverload(x, y): any {
return x + y;
}
[/csharp]

ООП. Класи
Class имя_класса {

властивості;

методи();

constructor(властивості); }

[csharp]
class Car {
var mazda = new Car(1, "Mazda", "6");
colsole.log(mazda.getCarInfo());

class Car {
// оголошуються три поля
id: number;
name: string;
model: string;

// ініціалізується конструктор, створює модель
constructor(carId: number, carModel: string, model: string) {
this.id = carId;
this.name = carModel;
this.model = model;
}

// буде відображати інформацію про автомобілі
getCarInfo(): string {
return "Car model = " + this.name + " model= " + this.model;
}
}

var mazda = new Car(1, "Mazda", "6");
console.log(mazda.getCarInfo());
[/csharp]

ООП. Статичні властивості та функції
Для визначення статичних функцій і властивостей використовується ключове слово
static
.

[csharp]
class Formula {
static PI: number = 3.14;
static Half = 0.5;
// розраховується площа кола
static getСircleSquare(radius: number): number {
return this.PI * radius * radius;
}
// розраховується площа трикутника
static getTriangleSquare(length: number, height: number): number {
return this.Half * length * height;
}
}

// ств. об'єкт класу Formula і розраховуються значення
var circle = Formula.getСircleSquare(16);
var triangle = Formula.getTriangleSquare(4, 7);
console.log("Площа кола = " + circle);
console.log("Площа трикутника = " + triangle);
[/csharp]

ООП. Спадкування
Одним з ключових елементів ООП є спадкування, яке в TS реалізується з допомогою ключового слова
extended
. За допомогою
extended 
ми можемо успадкувати від базового класу і описати класи спадкоємці.

[csharp]
interface IAnimal {
// властивості інтерфейсу — два поля і один метод
name: string;
danger: number;
getInfo(): void;
}

class Animal implements IAnimal {
// наследуемся від реалізованого інтерфейсу IAnimal
name: string;
danger: number;

constructor(name: string, danger: number) {
this.name = name;
this.danger = danger;
}

getInfo(): void {
console.log("Клас Тварина. Ім'я: " + this.name + ", небезпека: " + this.danger);
}
}

class Fox extends Animal {
tailLength: number;

constructor(name: string, danger: number, tailLength: number) {
super(name, danger);
this.tailLength = tailLength;
// ключове слово super — викликає конструктор базового класу,
// ініціалізує об'єкт з початковими описаними в ньому властивостями,
// а потім ініціалізуються властивості класу спадкоємця.
}

getInfo(): void {
super.getInfo();
console.log("Клас Лисиця. Довжина хвоста: " + this.tailLength + " м");
}
}

var goose: Animal = new Animal("Гусак", 1);
goose.getInfo();

var fox: Animal = new Fox("Фоксик", 10, 1);
fox.getInfo();
[/csharp]

ООП. Інтерфейси
Для визначення кастомного типу даних без реалізації в TS (і не тільки) використовуються інтерфейси. Щоб оголосити інтерфейс, використовується ключове слово
Interface
.

[csharp]
module InterfaceModule {
// оголошується інтерфейс IAnimal і описуються основні поля і методи цього класу
// і потім вони реалізуються безпосередньо на класах спадкоємців.
interface IAnimal {
name: string;
danger: number;

getInfo(): string;
}

class Animal implements IAnimal {
name: string;
danger: number;

constructor(name: string, danger: number) {
this.name = name;
this.danger = danger;
}

getInfo(): string {
return this.name + " " + this.danger;
}
}

var seal: IAnimal = new Animal("Тюлень", 1);
console.log(seal.getInfo());
}
[/csharp]

ООП. Інкапсуляція
Для приховування зовнішнього доступу до стану об'єкта і управління доступом до цього стану, TS використовується два модифікатора:
public 
та
private
.

Всередині нашого класу, ми можемо писати недоступні ззовні методи і маніпулювати з їх допомогою.

Реалізується це як у C#:

[csharp]
module Encapsulation {
class Animal {
private _id: string;
name: string;
danger: number;

constructor(name: string, danger: number) {
// заповнення приватного поля _id при створенні методу в конструкторі.
this._id = this.generateGuid();
this.name = name;
this.danger = danger;
}

private generateGuid(): string {
var d = new Date().getTime();
var uuid = 'хххххххх-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function © {
var r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
return uuid;
}

public getInfo(): string {
return "Id = " + this._id + " name = " + this.name + " danger = " + this.danger;
}
}

var parrot: Animal = new Animal("Кеша", 1);
console.log(parrot.getInfo());
[/csharp]

Таким чином ми обмежили доступ до методу
generateGuid()
. За замовчуванням поля і методи мають доступ public.

ООП. Generic
TypeScript дозволяє створювати Generic-типи.

function имя_функции(ім'я_змінної: Т): Т

Де Т — тип, яким типизирована функція. Також TS підтримує типізацію інтерфейсів і класів.

Class имя_класса

Interface interface name

Де T — тип, яким типизирована функція.

[csharp]
module GenericModule {
function getId<T>(id: T) : T {
return id;
}
// Generic клас Animal, при створенні ми передаємо тип generic типу і встановлюємо id 
class Animal<T> {
private _id: T;

constructor(id: T) {
this._id = id;
}

getId(): T {
return this._id;
}
}

var cat = new Animal<number>(16);
console.log("Cat id = " + cat.getId());

var dog = new Animal<string>("2327c575-2f7c-46c3-99f2-a267fac1db5d");
console.log("Dog id = " + dog.getId());
}
[/csharp]

Передаємо тип, встановлюємо Id для визначення типу і повертаємо нашу тварині інформацію. Таким чином використовуються Generic-типи.

Модулі
Одним з недоліків JavaScript є те, що велика кількість файлів може перетинатися між собою, і виникають своєрідні конфлікти. У TypeScript цю проблему вирішують модулі.

Модулі — це простір імен, всередині якого можна визначити класи, перерахування, змінні, функції, інші модулі. Будь-набір класів, інтерфейсів, функцій можуть бути об'єднані в якусь дужку і названі певним модулем. І потім з цим модулем можна легко і просто взаємодіяти.

Для визначення модуля використовується ключове слово
module
.

[csharp]
import test = MyTestModule.MyTestClass;
module CarModule {
// оголошується модуль CarModule в ньому є інтерфейс iCar.
export interface ICar {
// ключове слово export говорить нам про те, що цей інтерфейс може бути бачить ззовні нашого модуля. Якщо ми приберемо слово export, цей інтерфейс буде видно в дужках цього CarModule. 
id: number;
carModel: string;
model: string;

getCarInfo(): string;
}

export class Car implements ICar {
// створюється клас Car, який імплементує наш ICar
id: number;
carModel: string;
model: string; // якщо ми видалимо це поле, то IntelliSence попередить про те, що не описано поле model

constructor(carId: number, carModel: string, model: string) {
this.id = carId;
this.carModel = carModel;
this.model = model;
}

getCarInfo(): string {
var t = new test().getInfo();
return "Car model = " + this.carModel + " model= " + this.model + " " + t;
}
}
}

let car = new CarModule.Car(16, "ВАЗ", "2107");
console.log(car.getCarInfo());
[/csharp]

Зміни в термінології: важливо, що починаючи з TypeScript 1.5 змінилася номенклатура. Щоб не було розбіжностей з термінологією ECMAScript 2015, «внутрішні модулі» стали називатися «namespaces», а «модулі» тепер просто «modules». Тобто module X { однозначно з більш бажаним namespace X {.

Відмінності файли
Для зв'язки з якимись глобальними змінними необхідно підключати відмінності файли — це один з недоліків TypeScript. Щоб встановити зв'язок з зовнішніми файлами скриптів JavaScript в TS, необхідно використовувати декларативні або відмінності файли з розширенням *.d.ts.

Відмінності файли основних бібліотек вже описані, і з ними досить просто і легко працювати. Для цього необхідно зайти на сайт і підключити потрібний набір заголовних файлів, наприклад, jQuery. Потім оголошуються основні глобальні змінні, які використовуються в jQuery, і в подальшому вони будуть використовуватися в TS-файлі.

[csharp]
/// <reference path="../lib/typings/jquery.d.ts" />
class Cars {
private cars: Array<Car> = new Array<Car>();

load(): void {

$.getJSON('http://localhost:53923/api/Car',
(data) => {
this.cars = data;
alert('дані завантажені');
});
}

displayUsers(): void {
var table = '<table class="table">';
for (var i = 0; i < this.cars.length; i++) {

var tableRow = '<tr>' +
'<td>' + this.cars[i].id + '</td>' +
'<td>' + this.cars[i].name + '</td>' +
'<td>' + this.cars[i].model + '</td>' +
'</tr>';
table += tableRow;
}
table += '</table>';
$('#content').html(table);
}
}

window.onload = () => {
var cars: Cars = new Cars();
$("#loadBtn").click(() => { cars.load(); });
$("#displayBtn").click(() => { cars.displayUsers(); });
};
[/csharp]

Недоліки TypeScript
  • DefinitelyTyped — в деяких випадках відсутні популярні бібліотеки.
  • .ts .d.ts .map — велика кількість додаткових файлів після компілювання ts-файлу.
  • Неявна статична типізація. Якщо оголосимо змінну типу any, то ніякої користі від статичної типізації не отримаємо.


Переваги TypeScript
  • Строга типізація. Величезний плюс — IntelliSence, який на етапі компіляції вказує на помилки, і їх можна виправити до етапу виконання.
  • ООП. Чудово підтримуються всі основні принципи ООП.
  • Надмножество JavaScript'а. Досить скопіювати код з JavaScript і вставити в TS, щоб він запрацював
  • Розробка складних рішень. Завдяки підтримці модульності великі команди розробників можуть створювати великі програми.
Інструменти
Висновок
TypeScript є відмінним враппером, який може в значній мірі підвищити продуктивність команди розробників, із збереженням сумісності з існуючими кодом. TypeScript підтримується в VisualStudio 2015 і взаємодіє з ECMAScript 6.0. Поки в JavaScript немає суворої типізації, TypeScript — це відмінна альтернатива, застосування якої не потребує значних витрат часу на вивчення.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.