- PVSM.RU - https://www.pvsm.ru -
Язык TypeScript основан на том же синтаксисе и семантике, которые хорошо знакомы миллионам JavaScript-разработчиков. TypeScript даёт возможность работать с самыми свежими и ещё только появляющимися возможностями JS, включая те, которые имеются в ECMAScript 2015, и те, которые пока существуют лишь в виде предложений. Среди таких возможностей, например, асинхронные функции и декораторы. Всё это направлено на то, чтобы помочь разработчику в создании надёжных и современных приложений.
TypeScript-программа компилируется в обычный JavaScript-код, который может выполняться в любом браузере или в среде Node.js. Этот код будет понятен любому JS-движку, который поддерживает стандарт ECMAScript 3 или более новый.
Материал, перевод которого мы сегодня публикуем, содержит разбор двадцати вопросов, которые вполне могут задать тому, кто собирается пройти собеседование, претендуя на позицию TypeScript-программиста.
В скобках, после номера вопроса, указана его сложность, оцениваемая по пятибалльной шкале.
TypeScript (TS) – это надмножество JavaScript (JS), среди основных особенностей которого можно отметить возможность явного статического назначения типов, поддержку классов и интерфейсов. Одним из серьёзных преимуществ TS перед JS является возможность создания, в различных IDE, такой среды разработки, которая позволяет, прямо в процессе ввода кода, выявлять распространённые ошибки. Применение TypeScript в больших проектах может вести к повышению надёжности программ, которые, при этом, можно разворачивать в тех же средах, где работают обычные JS-приложения.
Вот некоторые подробности о TypeScript:
null
(для этого применяется флаг компилятора --strictNullChecks
), компилятор TypeScript не разрешает присвоение null
и undefined
переменным тех типов, в которых, в таком режиме, использование этих значений не допускается.→ Источник [3]
Обобщённые типы (generics) позволяют создавать компоненты или функции, которые могут работать с различными типами, а не с каким-то одним. Рассмотрим пример:
/** Объявление класса с параметром обобщённого типа */
class Queue<t> {
private data = [];
push = (item: T) => this.data.push(item);
pop = (): T => this.data.shift();
}
const queue = new Queue<number>();
queue.push(0);
queue.push("1"); // Ошибка : в такую очередь нельзя добавить строку, тут разрешено использовать лишь числа
→ Источник [4]
Да, поддерживает. Существуют четыре основных принципа объектно-ориентированного программирования:
Пользуясь простыми и понятными средствами TypeScript, можно реализовать все эти принципы.
→ Источник [5]
Для выполнения подобных проверок достаточно воспользоваться следующей конструкцией:
if (value) {
}
Выражение в скобках будет приведено к true
в том случае, если оно не является чем-то из следующего списка:
null
undefined
NaN
false
TypeScript поддерживает те же правила преобразования типов, что и JavaScript.
→ Источник [6]
В TypeScript, при объявлении свойств классов, нельзя использовать ключевое слово const
. При попытке использования этого ключевого слова выводится следующее сообщение об ошибке: A class member cannot have the ‘const’ keyword
. В TypeScript 2.0 имеется модификатор readonly
, позволяющий создавать свойства класса, предназначенные только для чтения:
class MyClass {
readonly myReadonlyProperty = 1;
myMethod() {
console.log(this.myReadonlyProperty);
}
}
new MyClass().myReadonlyProperty = 5; // ошибка, так как свойство предназначено только для чтения
→ Источник [7]
Файлы с расширением .map хранят карты кода (source map), которые содержат данные о соответствии кода, написанного на TypeScript, JavaScript-коду, созданному на его основе. С этим файлами могут работать многие отладчики (например — Visual Studio и инструменты разработчика Chrome). Это позволяет, в ходе отладки, работать с исходным кодом программ на TypeScript, а не с их JS-эквивалентами.
→ Источник [8]
TypeScript поддерживает геттеры и сеттеры, которые позволяют управлять доступом к членам объектов. Они дают разработчику средства контроля над чтением и записью свойств объектов.
class foo {
private _bar:boolean = false;
get bar():boolean {
return this._bar;
}
set bar(theBar:boolean) {
this._bar = theBar;
}
}
var myBar = myFoo.bar; // здесь вызывается геттер
myFoo.bar = true; // здесь вызывается сеттер
→ Источник [9]
Программы, написанные на TypeScript, подходят не только для фронтенд-разработки, но и для создания серверных приложений. Например, на TS можно писать программы для платформы Node.js. Это даёт программисту дополнительные средства по контролю типов и позволяет использовать другие возможности языка. Для создания серверных приложений на TS нужно лишь наладить правильный процесс обработки кода, на вход которого поступают TypeScript-файлы, а на выходе получаются JavaScript-файлы, подходящие для выполнения их в Node.js. Для того чтобы организовать такую среду, сначала надо установить компилятор TypeScript:
npm i -g typescript
Параметры компилятора задают с помощью файла tsconfig.json
, который определяет, кроме прочего, цель компиляции и место, в которое нужно поместиться готовые JS-файлы. В целом, этот файл очень похож на конфигурационные файлы babel или webpack:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"declaration": true,
"outDir": "build"
}
}
Теперь, при условии, что компилятору есть что обрабатывать, нужно его запустить:
tsc
И, наконец, учитывая то, что JS-файлы, пригодные для выполнения в среде Node.js, находятся в папке build
, надо выполнить такую команду, находясь в корневой директории проекта:
node build/index.js
→ Источник
TypeScript включает в себя три основных компонента:
→ Источник [11]
Вот фрагмент кода:
class Point {
x: number;
y: number;
}
interface Point3d extends Point {
z: number;
}
let point3d: Point3d = {x: 1, y: 2, z: 3};
Ошибок в этом коде нет. Объявление класса создаёт две сущности: это тип данных, используемый для создания экземпляров класса, и функция-конструктор. Так как классы создают типы данных, использовать их можно там же, где можно использовать интерфейсы.
→ Источник [9]
Просто очень любим этот фильм )
Декораторы можно использовать для изменения поведения классов, при этом ещё больше пользы от них можно получить при их использовании с каким-либо фреймворком. Например, если в вашем фреймворке есть методы, доступ к которым ограничен (скажем, они предназначены только для администратора), несложно будет написать декоратор метода @admin
, который будет запрещать доступ к соответствующим методам пользователям, не являющимся администраторами. Можно создать декоратор @owner
, который позволяет модифицировать объект только его владельцу. Вот как может выглядеть использование декораторов:
class CRUD {
get() { }
post() { }
@admin
delete() { }
@owner
put() { }
}
→ Источник [12]
Рассмотрим следующий пример:
class Foo {
save(callback: Function) : void {
//Выполняем сохранение
var result : number = 42; //Получаем в ходе операции сохранения некое число
//Можно ли во время выполнения программы как-то обеспечить то, чтобы коллбэк принимал лишь один параметр типа number?
callback(result);
}
}
var foo = new Foo();
var callback = (result: string) : void => {
alert(result);
}
foo.save(callback);
Можно ли в методе save
организовать работу с типизированным коллбэком? Перепишите код для того, чтобы это продемонстрировать.
В TypeScript можно объявить тип коллбэка, после чего переписать код:
type NumberCallback = (n: number) => any;
class Foo {
// Эквивалент
save(callback: NumberCallback): void {
console.log(1)
callback(42);
}
}
var numCallback: NumberCallback = (result: number) : void => {
console.log("numCallback: ", result.toString());
}
var foo = new Foo();
foo.save(numCallback)
→ Источник [3]
Классы, объявленные в модуле, доступны в пределах этого модуля. За его пределами доступ к ним получить нельзя.
module Vehicle {
class Car {
constructor (
public make: string,
public model: string) { }
}
var audiCar = new Car("Audi", "Q7");
}
// Это работать не будет
var fordCar = Vehicle.Car("Ford", "Figo");
В коде, приведённом выше, при попытке инициализации переменной fordCar
произойдёт ошибка. Для того чтобы сделать класс, объявленный в модуле, доступным за пределами этого модуля, нужно воспользоваться ключевым словом export
:
module Vehicle {
export class Car {
constructor (
public make: string,
public model: string) { }
}
var audiCar = new Car("Audi", "Q7");
}
// Теперь этот фрагмент кода работает нормально
var fordCar = Vehicle.Car("Ford", "Figo");
→ Источник [11]
TypeScript поддерживает перегрузку функций, но реализация этого механизма отличается от той, которую можно видеть в других объектно-ориентированных языках. А именно, в TS создают лишь одну функцию и некоторое количество объявлений. Когда такой код компилируется в JavaScript, видимой оказывается лишь одна конкретная функция. Этот механизм работает из-за того, что JS-функции можно вызывать, передавая им разное количество параметров.
class Foo {
myMethod(a: string);
myMethod(a: number);
myMethod(a: number, b: string);
myMethod(a: any, b?: string) {
alert(a.toString());
}
}
→ Источник [13]
Вот код, о котором идёт речь:
/* Неверно*/
interface Fetcher {
getObject(done: (data: any, elapsedTime?: number) => void): void;
}
Рекомендуется использовать необязательные параметры в коллбэках только в том случае, если вы абсолютно точно понимаете последствия такого шага. Этот код имеет весьма специфический смысл: коллбэк done
может быть вызван или с 1 или 2 аргументами. Автор кода, вероятно, намеревался сообщить нам, что коллбэк может не обращать внимания на параметр elapsedTime
, но для того, чтобы этого достичь, всегда можно создать коллбэк, который принимает меньшее число аргументов.
→ Источник [13]
TypeScript позволяет объявлять множество вариантов методов, но реализация может быть лишь одна, и эта реализация должна иметь сигнатуру, совместимую со всеми вариантами перегруженных методов. Для перегрузки конструктора класса можно воспользоваться несколькими подходами:
class Box {
public x: number;
public y: number;
public height: number;
public width: number;
constructor();
constructor(obj: IBox);
constructor(obj?: any) {
this.x = obj && obj.x || 0
this.y = obj && obj.y || 0
this.height = obj && obj.height || 0
this.width = obj && obj.width || 0;
}
}
class Box {
public x: number;
public y: number;
public height: number;
public width: number;
constructor(obj : IBox = {x:0,y:0, height:0, width:0}) {
this.x = obj.x;
this.y = obj.y;
this.height = obj.height;
this.width = obj.width;
}
}
class Person {
static fromData(data: PersonData) {
let { first, last, birthday, gender = 'M' } = data
return new this(
`${last}, ${first}`,
calculateAge(birthday),
gender
)
}
constructor(
public fullName: string,
public age: number,
public gender: 'M' | 'F'
) {}
}
interface PersonData {
first: string
last: string
birthday: string
gender?: 'M' | 'F'
}
let personA = new Person('Doe, John', 31, 'M')
let personB = Person.fromData({
first: 'John',
last: 'Doe',
birthday: '10-09-1986'
})
class foo {
private _name: any;
constructor(name: string | number) {
this._name = name;
}
}
var f1 = new foo("bar");
var f2 = new foo(1);
→ Источник [14]
Вот примеры использования этих ключевых слов:
interface X {
a: number
b: string
}
type X = {
a: number
b: string
};
В отличие от объявления интерфейса, которое всегда представляет именованный тип объекта, применение ключевого слова type
позволяет задать псевдоним для любой разновидности типа, включая примитивные типы, типы-объединения и типы-пересечения.
При использовании ключевого слова type
вместо ключевого слова interface
теряются следующие возможности:
extends
или implements
, а псевдоним для литерала объектного типа — нет.type
эта возможность не доступна.→ Источник [15]
Ключевое слово declare
используется в TypeScript для объявления переменных, источником которых может служить некий файл, не являющийся TypeScript-файлом.
Например, представим, что у нас имеется библиотека, которая называется myLibrary
. У неё нет файла с объявлениями типов TypeScript, у неё имеется лишь пространство имён myLibrary
в глобальном пространстве имён. Если вы хотите использовать эту библиотеку в своём TS-коде, вы можете использовать следующую конструкцию:
declare var myLibrary;
TypeScript назначит переменной myLibrary
тип any
. Проблема тут заключается в том, что у вас не будет, во время разработки, интеллектуальных подсказок по этой библиотеке, хотя использовать её в своём коде вы сможете. В этой ситуации можно воспользоваться и другим подходом, ведущим к тому же результату. Речь идёт об использовании переменной типа any
:
var myLibrary: any;
И в том и в другом случае при компиляции TS-кода в JavaScript, получится одно и то же, но вариант с использованием ключевого слова declare
отличается лучшей читабельностью. Применение этого ключевого слова приводит к созданию так называемого внешнего объявления переменной (ambient declaration).
Внешнее объявление переменной (ambient declaration) — это механизм, который позволяет сообщать компилятору TypeScript о том, что некий исходный код существует где-то за пределами текущего файла. Внешние объявления помогают интегрировать в TS-программы сторонние JavaScript-библиотеки.
Эти объявления делают в файле объявления типов с расширением .d.ts. Внешние переменные или модули объявляют так:
declare module Module_Name {
}
Файлы, в которых находится внешний код, должны быть подключены в TS-файле, использующем их, так:
/// <reference path=" Sample.d.ts"></reference>
→ Источник [16]
JavaScript не всегда содержит достаточно информации, которая позволяет TypeScript автоматически выводить типы. Поэтому практически невозможно автоматически создавать объявления типов, основанные на JavaScript. Однако можно попытаться это сделать, воспользовавшись следующими инструментами:
→ Источник [20]
Надеемся, разбор приведённых в этом материале вопросов поможет вам лучше узнать TypeScript, возможно, обратить внимание на то, на что раньше вы внимания не обращали, и, если вы готовитесь к собеседованию, повысит ваши шансы на его успешное прохождение.
Уважаемые читатели! Какие вопросы вы задали бы тому, кто проходит собеседование, претендуя на должность, требующую знания TypeScript?
Автор: ru_vds
Источник [21]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/razrabotka/289075
Ссылки в тексте:
[1] Image: https://habr.com/company/ruvds/blog/419993/
[2] опенсорсный: https://github.com/Microsoft/TypeScript
[3] Источник: https://stackoverflow.com/questions/12694530/what-is-typescript-and-why-would-i-use-it-in-place-of-javascript
[4] Источник: https://basarat.gitbooks.io/typescript/docs/types/generics.html
[5] Источник: https://jonathanmh.com/typescript-node-js-tutorial-backend-beginner/
[6] Источник: https://stackoverflow.com/questions/28975896/is-there-a-dedicated-function-to-check-null-and-undefined-in-typescript
[7] Источник: https://stackoverflow.com/questions/37265275/how-to-implement-class-constants-in-typescript
[8] Источник: https://stackoverflow.com/questions/17493738/what-is-a-typescript-map-file
[9] Источник: http://www.typescriptlang.org/docs/handbook/classes.html
[10] VS Code: http://www.talkingdotnet.com/what-is-visual-studio-code-and-difference-between-visual-studio-2015/
[11] Источник: http://www.talkingdotnet.com/typescript-interview-questions/
[12] Источник: https://www.sitepen.com/blog/2015/10/20/typescript-decorators/
[13] Источник: https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html
[14] Источник: https://stackoverflow.com/questions/12702548/constructor-overload-in-typescript
[15] Источник: https://stackoverflow.com/questions/37233735/typescript-interfaces-vs-types
[16] Источник: https://stackoverflow.com/questions/35019987/what-does-declare-do-in-export-declare-class-actions
[17] Microsoft/dts-gen: https://github.com/Microsoft/dts-gen
[18] dtsmake: https://github.com/ConquestArrow/dtsmake
[19] Tern: http://ternjs.net/
[20] Источник: https://stackoverflow.com/questions/18301898/generating-typescript-declaration-files-from-javascript
[21] Источник: https://habr.com/post/419993/?utm_campaign=419993
Нажмите здесь для печати.