Typescript
Более подробно на caйте dnzl.ru: TypeScript основы
tsconfig.json
- конфигурационный файл для TS
Несколько из возможных опций:
"target": "es5" /* ts будет компилироваться в es5 */
"module": "commonjs" /* формат import и export */
"strict": true /* strict режим */
"sourceMap": true /* ts будет генерировать .map файл, который понимают браузеры */
"noEmitOnError" : false /* ts не будет генерить js, если в ts есть ошибки */
tsc index.ts
// компилируем index.ts в index.js
// команда tsc читает текущий конфиг tsconfig.json
Типы
Все что приведено ниже ставится после объявления переменной:
: string
: number
: boolean
: any
: string | number
: number | null
// Типы массивов
: number[]
: string[]
// OR
: Array<number> // обозначение дженерика
: [number, number, string]
let a: number;
let b: boolean;
let c: string;
let d: any;
let e: number[] = [1,2,3,4,5];
let f: any[] = [1, true, 'a', false];
Несколько примеров:
С помощью enum
мы можем создавать константы и затем использовать их как тип.
// enum
const ColorRed = 0;
const ColorGreen = 1;
const ColorBlue = 2;
enum Color {
Red,
Green,
Blue
};
let backgroundColor = Color.Red; // 0
// or
enum Color {
Red = 0,
Green = 1,
Blue = 2,
Purple = 3
}
console.log(Color.Purple) // 3
Функции и TS
Добавим символ ?
в конце параметра, сделаем такой параметр необязательным.
function greetMe(name: string, greeting?: string): string { // : string означает, что возвращает строку
return greeting ? greeting : 'Hello' + ', ' + name;
}
Или можно использовать непосредственно в шаблоне:
<a > {{currentUser?.nickname}} </a>
Параметры по умолчанию - после типа переменной указываем его значение по умолчанию.
// greeting: string = 'Hello' 'Hello' как параметр по умолчанию
function greetMe(name: string, greeting: string = 'Hello'): string {
return greeting + name;
}
О том, что функция ничего не возвращает можно указать при помощи ключевого слова void
:
function greetMe(name: string, greeting: string): void {
console.log(greeting + name);
}
Обозначение типов функций делается на основе ES6 синтаксиса.
type User = {
name: string,
age: number,
getJobs: () => string[],
jobs: string[],
logName?: (prefix: string) => void // название аргументов неважно, главное ТИП
};
let user: User = {
name: 'John',
age: 21,
jobs: ['a', 'b'],
getJobs(): string[] {
return this.jobs;
},
logName(prefix: string): void {
console.log(prefix + this.name);
}
};
user.logName('hello '); //hello John
Классы
Классы отличаются от интерфейсов тем, что на основе классов мы можем создать объект. То есть в отличие от интерфейсов это не просто описание формы чего-либо.
Интерфейсы могут быть реализованы не только объектами, но и классами. Для этого используется ключевое слово implements
.
Имена классов определяются в стиле UpperCamelCase с добавлением суффикса, указывающего на его тип (компонент, директива, фильтр и т.д.)
Отличная статья по поводу классов и интерфейсов в typescript: Classes vs Interfaces от James Henry.
Абстрактные классы
От абстрактных классов мы не можем делать экземпляров. Абстрактные классы нужны лишь для того, чтобы от них наследовались.
abstract class User {
name: string;
year: number = 1982;
// метод абстрактный, поэтому в классе, например, Employee он может быть реализован со своей логикой
abstract logInfo(info: string): void;
getYear(): number {
return this.year;
}
}
class Employee extends User {
logInfo(info: string): void {
console.log(info);
}
}
const john = new Employee();
console.log(john);
john.logInfo('Info'); // info
console.log(john.getYear()); // 1982
Интерфейс
Интерфейс - описание формы объекта, в котором можно описать как обязательные так и необязательные поля.
Можно описать тип так:
let drawPoint = (point: { x: number, y: number }) => {
//..
}
drawPoint({
x: 1,
y: 2
})
Но, как вы видите, это решение актуально для лишь конкретной функции (drawPoint
).
Решение в использование интерфейсов.
interface Point {
x: number,
y: number
}
let drawPoint = (point: Point) => {
//..
}
drawPoint({
x: 1,
y: 2
})
interface ITodo {
title: string;
completed: boolean;
}
todo: ITodo
При работе с классами интерфейсы определяют контракт (implements
) указывающий, что классы реализующие этот интерфейс должны
определить определенные свойства и методы.
Например, интерфейс OnInit
:
export class ListArticles implements OnInit {
//..
Что нужно знать об интерфейсах: интерфейсы используются только во время компиляции TypeScript, и затем удаляются. В конечном JavaScript их не будет.
// Привести пустой объект к типу интерфейса Task
this.Task = <Task>{ };
Типы в уловых скобках (дженерики)
Иногда мы вынуждены писать тип any
, так, например, в ситуации, когда мы не знаем какой тип придет в функцию.
А в typescript вся идеологияя построена на том, что мы знаем типы.
Дженерики - обозначение типов в общем виде, которые помогают избежать ситуаций опсанных выше.
// здесь <T> дженерик, который будет использоваться в ф-и
// само T это сокращение от Type
function genericGetter<T>(data: T): T {
return data;
}
// Дженерик самостоятельно определяет тип данных:
console.log(genericGetter('Test').length);
let newGenericFunction: <T>(data: T) => T = genericGetter; // <T>(data: T) => T это тип
// Самостоятельно указываем тип данных дженерика:
console.log(genericGetter<string>('Test').length);
// =============================================
// Дженерик может принимать только number или string
class Multiply <T extends number | string> {
constructor(private a: T, private b: T) {}
public getResult(): number {
return +this.a * +this.b;
}
}
const mNum = new Multiply<number>(10, 5);
console.log('Number: ', mNum.getResult());
const mStr = new Multiply<string>('50', '60');
console.log('String: ', mStr.getResult());
Разберем примеры:
getAll(): Promise<Task[]> {
return tasksPromise;
}
Возвращаемый тип данных - Promise
, но при этом с помощью угловых скобок <Task[]>
мы указали, что именно в себе хранит этот Promise
.
Когда мы делаем любую асинхронную операцию, которая возвращает Promise
, мы понимаем, что в Promise
хранится значение, которое появится через какое-то время.
С помощью угловых скообок мы сообщаем это значение.
В данном случае Promise
будет содержать массив задач. <Task[]>
Ниже мы приводим пустой объект к типу интерфейса Task
//Привести пустой объект к типу интерфейса Task
this.Task = <Task>{ };
// определение массива чисел
let list1: number[] = [1, 2, 3];
// определение массива чисел с использования generic типа Array<elemType>
let list2: Array<number> = [1, 2, 3];
// phrase.ts
export class Phrase {
value: string;
language: string;
}
import { Phrase } from "./phrase";
// определяем массив Phrase
let arrPhrase: Phrase[] = [
{ value: "Hello World", language: "English" }
]
assertions (утверждение типа)
assertions
бывают двух видов - <>
или as
let message; // by default type any
message = 'abc';
// Метод endsWith() определяет, заканчивается ли строка символами другой строки, возвращая, соотвественно, true или false.
// https://developer.mozilla.org/ru/docsReference/Global_Objects/String/endsWith
// принудительно указывает тип для переменной message
let endWithC = (<string>message).endsWith('c');
let alternativeEndWithC = (message as string).endsWith('c');
Комментарии к статье