TypeScript-программа компилируется в обычный JavaScript-код, который может выполняться в любом браузере или в среде Node.js. Этот код будет понятен любому JS-движку, который поддерживает стандарт ECMAScript 3 или более новый.
Материал, перевод которого мы сегодня публикуем, содержит разбор двадцати вопросов, которые вполне могут задать тому, кто собирается пройти собеседование, претендуя на позицию TypeScript-программиста.
Вопрос №1 (1). Что такое TypeScript и зачем использовать его вместо JavaScript?
В скобках, после номера вопроса, указана его сложность, оцениваемая по пятибалльной шкале.
TypeScript (TS) – это надмножество JavaScript (JS), среди основных особенностей которого можно отметить возможность явного статического назначения типов, поддержку классов и интерфейсов. Одним из серьёзных преимуществ TS перед JS является возможность создания, в различных IDE, такой среды разработки, которая позволяет, прямо в процессе ввода кода, выявлять распространённые ошибки. Применение TypeScript в больших проектах может вести к повышению надёжности программ, которые, при этом, можно разворачивать в тех же средах, где работают обычные JS-приложения.
Вот некоторые подробности о TypeScript:
- TypeScript поддерживает современные редакции стандартов ECMAScript, код, написанный с использованием которых, компилируется с учётом возможности его выполнения на платформах, поддерживающих более старые версии стандартов. Это означает, что TS-программист может использовать возможности ES2015 и более новых стандартов, наподобие модулей, стрелочных функций, классов, оператора spread, деструктурирования, и выполнять то, что у него получается, в существующих средах, которые пока этих стандартов не поддерживают.
- TypeScript – это надстройка над JavaScript. Код, написанный на чистом JavaScript, является действительным TypeScript-кодом.
- TypeScript расширяет JavaScript возможностью статического назначения типов. Система типов TS отличается довольно обширными возможностями. А именно, она включает в себя интерфейсы, перечисления, гибридные типы, обобщённые типы (generics), типы-объединения и типы-пересечения, модификаторы доступа и многое другое. Применение TypeScript, кроме того, немного упрощает работу за счёт использования вывода типов.
- Применение TypeScript, в сравнении с JavaScript, значительно улучшает процесс разработки. Дело в том, что IDE, в реальном времени, получает сведения о типах от TS-компилятора.
- При использовании режима строгой проверки на
null
(для этого применяется флаг компилятора--strictNullChecks
), компилятор TypeScript не разрешает присвоениеnull
иundefined
переменным тех типов, в которых, в таком режиме, использование этих значений не допускается. - Для использования TypeScript нужно организовать процесс сборки проекта, включающий в себя этап компиляции TS-кода в JavaScript. Компилятор может встроить карту кода (source map) в сгенерированные им JS-файлы, или создавать отдельные .map-файлы. Это позволяет устанавливать точки останова и исследовать значения переменных во время выполнения программ, работая непосредственно с TypeScript-кодом.
- TypeScript — это опенсорсный проект Microsoft, выпущенный под лицензией Apache 2. Инициатором разработки TypeScript является Андерс Хейлсберг. Он причастен к созданию Turbo Pascal, Delphi и C#.
> Источник
Вопрос №2 (1). Расскажите об обобщённых типах в TypeScript.
Обобщённые типы (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"); // Ошибка : в такую очередь нельзя добавить строку, тут разрешено использовать лишь числа
> Источник
Вопрос №3 (2). Поддерживает ли TypeScript все принципы объектно-ориентированного программирования?
Да, поддерживает. Существуют четыре основных принципа объектно-ориентированного программирования:
- Инкапсуляция
- Наследование
- Абстракция
- Полиморфизм
Пользуясь простыми и понятными средствами TypeScript, можно реализовать все эти принципы.
> Источник
Вопрос №4 (2). Как в TypeScript проверять значения на равенство null и undefined?
Для выполнения подобных проверок достаточно воспользоваться следующей конструкцией:
if (value) {
}
Выражение в скобках будет приведено к
true
в том случае, если оно не является чем-то из следующего списка:null
undefined
NaN
- Пустая строка
- 0
false
TypeScript поддерживает те же правила преобразования типов, что и JavaScript.
> Источник
Вопрос №5 (2). Как в TypeScript реализовать свойства класса, являющиеся константами?
В 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; // ошибка, так как свойство предназначено только для чтения
> Источник
Вопрос №6 (2). Что представляют собой .map-файлы в TypeScript?
Файлы с расширением .map хранят карты кода (source map), которые содержат данные о соответствии кода, написанного на TypeScript, JavaScript-коду, созданному на его основе. С этим файлами могут работать многие отладчики (например — Visual Studio и инструменты разработчика Chrome). Это позволяет, в ходе отладки, работать с исходным кодом программ на TypeScript, а не с их JS-эквивалентами.
> Источник
Вопрос №7 (2). Что такое геттеры и сеттеры в TypeScript?
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; // здесь вызывается сеттер
> Источник
Вопрос №8 (2). Можно ли использовать TypeScript в серверной разработке, и если да — то как?
Программы, написанные на 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
> Источник
Вопрос №9 (3). Расскажите об основных компонентах TypeScript.
TypeScript включает в себя три основных компонента:
- Язык. Это, с точки зрения разработчиков, самая важная часть TypeScript. «Язык» — это синтаксис, ключевые слова, всё то, что позволяет писать программы на TypeScript.
- Компилятор. TypeScript обладает компилятором с открытым исходным кодом, он является кросс-платформенным, с открытой спецификацией, и написан на TypeScript. Компилятор выполняет преобразование TypeScript-кода в JavaScript-код. Кроме того, если с программой что-то не так, он выдаёт сообщения об ошибках. Он позволяет объединять несколько TypeScript-файлов в один выходной JS-файл и умеет создавать карты кода.
- Вспомогательные инструменты. Вспомогательные инструменты TypeScript предназначены для облегчения процесса разработки с его использованием в различных IDE. Среди них — Visual Studio, VS Code, Sublime, различные средства для быстрого запуска TS-кода, и другие.
> Источник
Вопрос №10 (3). Есть ли в предоставленном вам TypeScript-коде ошибки? Объясните свой ответ.
Вот фрагмент кода:
class Point {
x: number;
y: number;
}
interface Point3d extends Point {
z: number;
}
let point3d: Point3d = {x: 1, y: 2, z: 3};
Ошибок в этом коде нет. Объявление класса создаёт две сущности: это тип данных, используемый для создания экземпляров класса, и функция-конструктор. Так как классы создают типы данных, использовать их можно там же, где можно использовать интерфейсы.
> Источник
Просто очень любим этот фильм )
Вопрос №11 (3). Расскажите об использовании декораторов свойств в TypeScript.
Декораторы можно использовать для изменения поведения классов, при этом ещё больше пользы от них можно получить при их использовании с каким-либо фреймворком. Например, если в вашем фреймворке есть методы, доступ к которым ограничен (скажем, они предназначены только для администратора), несложно будет написать декоратор метода
@admin
, который будет запрещать доступ к соответствующим методам пользователям, не являющимся администраторами. Можно создать декоратор @owner
, который позволяет модифицировать объект только его владельцу. Вот как может выглядеть использование декораторов:class CRUD {
get() { }
post() { }
@admin
delete() { }
@owner
put() { }
}
> Источник
Вопрос №12 (3). Можно ли в TypeScript использовать строго типизированные функции в качестве параметров?
Рассмотрим следующий пример:
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)
> Источник
Вопрос №13 (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");
> Источник
Вопрос №14 (3). Поддерживает ли TypeScript перегрузку функций?
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());
}
}
> Источник
Вопрос №15 (4). Что не так с предоставленным вам кодом?
Вот код, о котором идёт речь:
/* Неверно*/
interface Fetcher {
getObject(done: (data: any, elapsedTime?: number) => void): void;
}
Рекомендуется использовать необязательные параметры в коллбэках только в том случае, если вы абсолютно точно понимаете последствия такого шага. Этот код имеет весьма специфический смысл: коллбэк
done
может быть вызван или с 1 или 2 аргументами. Автор кода, вероятно, намеревался сообщить нам, что коллбэк может не обращать внимания на параметр elapsedTime
, но для того, чтобы этого достичь, всегда можно создать коллбэк, который принимает меньшее число аргументов.> Источник
Вопрос №16 (4). Как в TypeScript перегрузить конструктор класса?
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);
> Источник
Вопрос №17 (4). Чем различаются ключевые слова interface и type в TypeScript?
Вот примеры использования этих ключевых слов:
interface X {
a: number
b: string
}
type X = {
a: number
b: string
};
В отличие от объявления интерфейса, которое всегда представляет именованный тип объекта, применение ключевого слова
type
позволяет задать псевдоним для любой разновидности типа, включая примитивные типы, типы-объединения и типы-пересечения.При использовании ключевого слова
type
вместо ключевого слова interface
теряются следующие возможности:- Интерфейс может быть использован в выражении
extends
илиimplements
, а псевдоним для литерала объектного типа — нет. - Интерфейс может иметь несколько объединённых объявлений, а при использовании ключевого слова
type
эта возможность не доступна.
> Источник
Вопрос №18 (5). Расскажите о том, когда в TypeScript используют ключевое слово declare.
Ключевое слово
declare
используется в TypeScript для объявления переменных, источником которых может служить некий файл, не являющийся TypeScript-файлом.Например, представим, что у нас имеется библиотека, которая называется
myLibrary
. У неё нет файла с объявлениями типов TypeScript, у неё имеется лишь пространство имён myLibrary
в глобальном пространстве имён. Если вы хотите использовать эту библиотеку в своём TS-коде, вы можете использовать следующую конструкцию:declare var myLibrary;
TypeScript назначит переменной
myLibrary
тип any
. Проблема тут заключается в том, что у вас не будет, во время разработки, интеллектуальных подсказок по этой библиотеке, хотя использовать её в своём коде вы сможете. В этой ситуации можно воспользоваться и другим подходом, ведущим к тому же результату. Речь идёт об использовании переменной типа any
:var myLibrary: any;
И в том и в другом случае при компиляции TS-кода в JavaScript, получится одно и то же, но вариант с использованием ключевого слова
declare
отличается лучшей читабельностью. Применение этого ключевого слова приводит к созданию так называемого внешнего объявления переменной (ambient declaration).Вопрос №19 (5). Что такое внешние объявления переменных в TypeScript и когда их нужно использовать?
Внешнее объявление переменной (ambient declaration) — это механизм, который позволяет сообщать компилятору TypeScript о том, что некий исходный код существует где-то за пределами текущего файла. Внешние объявления помогают интегрировать в TS-программы сторонние JavaScript-библиотеки.
Эти объявления делают в файле объявления типов с расширением .d.ts. Внешние переменные или модули объявляют так:
declare module Module_Name {
}
Файлы, в которых находится внешний код, должны быть подключены в TS-файле, использующем их, так:
/// <reference path=" Sample.d.ts"></reference>
> Источник
Вопрос №20 (5). Можно ли автоматически генерировать файлы объявлений TypeScript из JS-библиотек?
JavaScript не всегда содержит достаточно информации, которая позволяет TypeScript автоматически выводить типы. Поэтому практически невозможно автоматически создавать объявления типов, основанные на JavaScript. Однако можно попытаться это сделать, воспользовавшись следующими инструментами:
- Microsoft/dts-gen — официальное средство, используемое Microsoft как отправная точка при создании объявлений типов.
- dtsmake — многообещающий инструмент для автоматического создания объявлений типов на основе JS-файлов, находящийся в процессе разработки. Он зависит от системы анализа кода Tern, которую используют некоторые редакторы для реализации механизма автозавершения при вводе JS-кода.
> Источник
Итоги
Надеемся, разбор приведённых в этом материале вопросов поможет вам лучше узнать TypeScript, возможно, обратить внимание на то, на что раньше вы внимания не обращали, и, если вы готовитесь к собеседованию, повысит ваши шансы на его успешное прохождение.
Уважаемые читатели! Какие вопросы вы задали бы тому, кто проходит собеседование, претендуя на должность, требующую знания TypeScript?
— И какая скидка по этому промо-коду?!
— Кажется, 7%. Проверю, если хотите…
— Да уж, вы проверьте. По-моему, скидка чуть завышена!
…
— Простите, я немного ошиблась насчет скидки. 10% на все виртуальные сервера.
Комментарии (55)
Chamie
13.08.2018 12:43Вас не смущает, что в разъяснении вашего ответа на 4-й вопрос вы, фактически, объясняете, что он неправильный?
Smokin
13.08.2018 12:47Имею малый опыт с TS, но неужели это и правда является ошибкой?
/* Неверно*/ interface Fetcher { getObject(done: (data: any, elapsedTime?: number) => void): void; }
k12th
13.08.2018 12:57Не является. Красивей было бы объявить несколько перегрузок, но на практике разницы нет, если имплементация это учитывает.
Smokin
13.08.2018 13:33Красивей, это так?
interface Fetcher { getObject(done: (data: any) => void): void; getObject(done: (data: any, elapsedTime: number) => void): void; }
k12th
13.08.2018 13:39+1Не, скорее так:
interface IGetObjectCallback { (data: any): void; (data: any, elapsedTime: number): void; } interface Fetcher { getObject(done: IGetObjectCallback): void; }
printercu
14.08.2018 15:46Что-то не работает.
class A implements Fetcher { getObject(done: IGetObjectCallback) {} } const a = new A a.getObject((x: any, y: number) => {}) // TS2345: Argument of type '(x: any, y: number) => void' is not assignable to parameter of type 'IGetObjectCallback'.
Официальные доки советуют использовать опциональные параметры вместо перегрузок: https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html#use-optional-parameters
Chamie
14.08.2018 15:51Там явное приведение типа не нужно?
a.getObject(<IGetObjectCallback>(x: any, y: number) => {})
printercu
14.08.2018 16:02-1Вы хотите, чтобы я за вас проверил?)
Chamie
14.08.2018 16:28+1Ну, если вам интересно, почему ошибка, то проверяйте. У вас под рукой, вроде бы, есть развёрнутое TS-окружение, откуда вы ошибку привели.
У меня нет задачи разобраться в этом примере, так что это вы не за меня, а за себя проверите.
printercu
14.08.2018 16:00Пример с Fetcher тоже из этой документации. В статью почему-то не добавили совет и пример:
Пишите параметры колбэков, как не-опциональные:
/* OK */ interface Fetcher { getObject(done: (data: any, elapsedTime: number) => void): void; }
"… всегда можно передать коллбэк, который принимает меньшее число аргументов" будет правильнее.
VolCh
13.08.2018 12:49Несколько для собеседования, сколько для использования, ничего внятного нагуглить не смог
1) Какие есть способы задать тип значения равным классу, внутри которого тип задаётся без использования его имени (по типу this.constructor в JS или self в PHP?
2) Какие есть способы задать тип значения, обозначающих конкретный декорируемый конкретным декоратор класс? Ну есть что-то вроде @loggable class Entity {}. просто где-то использовать let obj: Entity = new Entity() не рабоатет.arvitaly
14.08.2018 01:201) Можно с помощью this, хотя лучше писать с использованием имени явно.
class A { public b: this; public c: string; } new A().b.b.c.toLowerCase();
2) Нет таких способов. И в целом, я думаю, что использовать декораторы, как множественное наследование — bad practice. Если нужно добавить в класс функциональность с публичным интерфейсом, лучше сделать это явно, без магии. А декораторы как раз предназначены для того, чтобы изменить поведение класса, не меняя интерфейс.
ooki2day
13.08.2018 15:08я, конечно, очень далек от JS и TS, но неужели вопрос о ключевом слове является сложным на 5 баллов по пятибальной шкале?
Delagen
13.08.2018 15:08Половина вопросов вытекает из знания JS.
2. Русское наименование дженериков меня вообще в ступор ввело, хотя знаю их еще с C# когда писал в 2005 году
3. Это не реализация, а описание. В принципе таким же методом можно и геттер объявить.
6. Спрашивать про .map в TS? Реально? Если он о них не знает, значит и остальное просто 0.
13. В 2018 кто то вообще пользуется module?
15. Всё так. Никогда не думали что все мыслят по разному и то что принятно в одной команде, легко не принято в другой?
19. Если вы до сих пор используете reference path, я вам сочуствую.
20. Возможность может быть и есть, но нежизнеспособно.inoyakaigor
13.08.2018 15:38А объясните кто-нибудь ньюфагу от мира TS, что не так с module и reference path?
VolCh
13.08.2018 15:56Документация советует использовать namespace, а не module, чтобы избежать когнитивных коллизий с ES Modules.
VolCh
13.08.2018 15:59> Спрашивать про .map в TS? Реально? Если он о них не знает, значит и остальное просто 0.
Я вот только догадываюсь, что TS тоже может .map генерить как babel и, может быть, браузеры что-то покажут внятное. Но в обозримой перспективе даже уверенность в этом мне ничего мне не даст, весь маппинг в голове.Delagen
13.08.2018 17:02Ну тут тема вопросы к собеседованию, а не ответы начинающим ;)
VolCh
13.08.2018 17:19Я уже давно прошёл собеседование по TS и активно использую его и на фронте, и на бэке :) Может быть когда-то и читал про map в TS и по горячим следам ответил бы, но на практике не используется у нас на проекте. И обычно это значит, что такие чисто теоретические знания быстро улетучиваются, а значит на собеседовании вполне можно и не ответить даже имея кучу актуального опыта по стэку. Думаю, у почти любого спеца можно найти пробелы в оперативных знаниях.
Delagen
13.08.2018 18:06Возможно вы просто пишете на нем, но никогда не лезли глубже, вдобавок наверное никогда не настраивали какую то свою сборку на нем… Это не беда, в нормальных конторах разделение труда. У нас народу немного, поэтому приходится во все тонкости вникать самому. Может быть я просто параноик и хочу знать как что работает ;)
VolCh
13.08.2018 18:23И это не беда, по крайней мере если это не делается за счёт работодателя без его ведома ;)
А вообще я к тому, что заявлять «Если он о них не знает, значит и остальное просто 0.» в отношении какого-то малозначимого и не всеми используемого параметра трансляции, как-то очень близко к ложноотрицательному выводу. Тем более в наше время, когда правит, как вы заметили, разделение труда, и настройками сборок нередко занимаются специально обученные люди, которым этим мапы даром не сдались и сделают они их, в лучшем случае, если моё начальство обоснует их необходимость перед их начальством, плюс докажет, например, третьим людям, что создание этих мап в процессе сборки не являтся угрозой безопасности или является, но вторые люди исключат их утечку.Delagen
13.08.2018 18:42Ну тут сильно не согласен. Без карт отладка любого транспилированного модуля превращается в нечто нетривиальное. Да и зачем сидеть разбирать транспилированный код, если можно прекрасно дебажить исходный? Я как раз против того, чтобы этим занимались необученные люди. В нашей конторе несколько проектов пишущих фронт и я бы не сказал, что настройка сборки может производиться необученными людьми. Это создает кучу проблем и неудобств.
А насчет угроз безопасности, это смешно… Никто не заставляет эти мапы отдавать заказчику и т.п. Да и сами должны понимать, что JS код не защищен от слова НИКАКVolCh
13.08.2018 18:49Ну вот у меня три варианта: или отлаживать без карт, или пытаться пробивать (в том числе доказывая, что возможная утечка мап-файлов ничего опасного кроме того что и так есть в обфуцированном джс не даст, ну или хотя бы что вероятность такой утечки пренебрежимо мала) чтобы создали такую задачу и на кого-то назначили. Ну или лезть своими необученными руками в процесс сборки и предоставить готвое решение, но с теми ж доказываниями и убеждениями. Плюс доказывания и убеждения, что рабочего времени я на задачу практически не тратил, при этом рабочий код никуда не выносил, а, условно, в офисе ночевал и пилил сборку.
faiwer
13.08.2018 19:49+2Да и зачем сидеть разбирать транспилированный код, если можно прекрасно дебажить исходный?
Не могу говорить за TS, но в случае JS и babel-я я давно отказался от source-map-ов. Побудило меня к этому:
- я натыкался на баги транспайлера, когда оный совершенно по непонятным причинам срезал куски кода совсем
- различные
_this2
вместоthis
приводят к тому, что это невозможно дебажить в консоли в runtime - различные
(0, _flatten3.default)(...)
вместоflatten(...)
приводят к тому, что невозможно дебажить в консоли в runtime - многие другие неочевидные моменты, закрытые от глаз
- многочисленные баги уже самого отладчика chrome
Порой в сложных случаях приходится очень сильно углубляться в дебаг, довольно мутных вещей. И если я там буду видеть ещё и не тот код, который по факту исполняется, то я далеко не уеду.
Возможно в TS картина точно такая же.
Delagen
13.08.2018 20:28Ну картина везде одинаковая, но в случаях если все работает, то зачем лезть в эту муть? Понятно что, когда что-то перестает работать то надо. Сам находил пару ошибок в транспиляторе TS, но как говорится не обновляйся раньше времени и проблем не будет. Проблема в Babel это то что все размыто по куче плагинов, не всегда поддерживаемых самим сообществом. В TS хотя бы оно если заявлено, то в 99% работает.
faiwer
13.08.2018 20:33+1Я ведь не администратор, я ? разработчик. У меня перманентно что-нибудь не работает. Или новый функционал в процессе реализации, или сторонние библиотеки работают не так как ожидаешь, добавим различный отлов багов, и многое другое. Как тут без дебага? Можно даже пару дней в дебагере провести. По сути я что-нибудь отлаживаю практически каждый день. Ну может раз в два дня. Сам процесс отладки это… не одну книгу по трюкам и подходам можно написать.
Проблема в Babel я думаю не в плагинах и сообществе. С этим всё ок, баг в babel я пока встретил лишь единожды (кажется). Проблема скорее в том, что уж больно любит babel переименовывать сущности во всякие
(0, _name4)
и прочие трюки. Да, наверняка, у каждого такого трюка есть своя причина, но в отладке это сильно мешает.
F0iL
14.08.2018 12:12многочисленные баги уже самого отладчика chrome
А можете рассказать, с какими конкретно багами столкнулись?
Репортили их? Каков результат?faiwer
14.08.2018 12:25Самое простое — ломалась подсветка синтаксиса не транспилированного кода. Это ломало и просмотр значений при наведении. Из того, что посложнее, хм, был какой-то мутный баг с Object.entries. Правда это скорее к v8 баг, не к тулзам. Многократно наблюдал вылеты devtool-ов. Бывало по 30-40 раз в день умирали они. Тоже касается и браузерного таба (то самое "опаньки"). Многократно наблюдал недоступность каких-либо переменных, объявленных вот прямо под носом строкой выше (видимо какие-то внутренние оптимизации). Очень странное поведение трассировки, проскакивающее какие-нибудь куски (без blackbox). Да честно говоря всего не упомнишь. Обычно я или привыкал к какому-нибудь поведению, или оно "само" исправлялось с очередным релизом. Не репортил, каюсь, грешен. Репортил по v8, репортил по рендер-движку браузера, а вот по дев-тулзам ещё не репортил. Мне кажется это нетривиальным. Вот с полгода назад у меня гарантировано девтулзы мёрли в ряде обстоятельств. Но как это можно было воспроизвести без открытия кода — я не знал. А кому нужен мутный багрепорт без примера.
kaljan
13.08.2018 15:28Не советую пользоваться этим опросником HR-ам
Вопрос №1 (1) — Что такое TypeScript
Что? Какой смысл задавать вопрос и ожидать услышать ответ на 40 строк?
А если человек ответит «Не знаю» — тогда что?
Вопрос №6 (2). Что представляют собой .map-файлы в TypeScript?
Вопрос №9 (3). Расскажите об основных компонентах TypeScript.
Да кому это вообще нужно
Вопрос №16 (4). Как в TypeScript перегрузить конструктор класса?
ANY — Лучше не использовать any, тем самым вы полностью гасите смысл использования TypeScript
Вопрос №4 (2). Как в TypeScript проверять значения на равенство null и undefined?
if(value) — если в числе 0 — вернет false, хотя там число. Не пишите на Javascript, если пишете на Typescript
Вопрос №17 (4). Чем различаются ключевые слова interface и type в TypeScript?
в спеке все описано гораздо лучше — github.com/Microsoft/TypeScript/blob/master/doc/spec.md#3.10
Вопрос №18 (5). Расскажите о том, когда в TypeScript используют ключевое слово declare.
Копипаст детектед
Пример использования declare — когда у вас импортирован js-файл, и вы хотите работать с jquery (хаха)
Вопрос №19 (5). Что такое внешние объявления переменных в TypeScript и когда их нужно использовать?
///
Вот что говорит по этому поводу TsLint
reference is not allowed, use imports
mwizard
13.08.2018 18:54+5Какие вопросы вы задали бы тому, кто проходит собеседование, претендуя на должность, требующую знания TypeScript?
Прочитайте этот список из 20 вопросов и ответов и объясните, почему их ни в коем случае нельзя использовать при отборе кандидатов со знанием TypeScript.
arvitaly
14.08.2018 00:56if (value) {
}
const a = {}; if (a){ // Это ведь JavaScript! }
Такие проверки даже в JS чаще всего плохой тон, всегда нужно писать полную версию без приведения типа: a === null.TheShock
14.08.2018 09:38Лучше a == null, с двойным сравнением, а не тройным, тогда он проверит сразу на null и undefined, что в большинстве архитектур будет аналогичным значениями. Нету никакого смысла их разделять и потому двойное сравнение — самое правильное
arvitaly
14.08.2018 11:12Настаиваю на тождественном сравнении.
Значения null и undefined не аналогичны, null мы можем задать только сами, присвоив переменной. Для этого его и стоит использовать, когда нужно явным образом указать отсутствие значения.
function a(b?: null | number) { if (b === null) { // Точно знаем, что b - нулевое } else if (typeof b === "undefined") { // b не задали, возможно стоит задать значение по умолчанию } else { b.toFixed(); } } a(1); a(null); a();
Нет никакого смысла позволять переменной быть и null и undefined с одинаковой семантикой, это только вероятность ошибок увеличит.VolCh
14.08.2018 11:21Увеличит если только позволять при одинаковой семантике использовать тождественное сравнение.
TheShock
14.08.2018 12:29И зачем? Какая разница в реальном коде будет в первом и втором условии? Полагаться на разницу между null и undefined — признак попахивающего кода и никакое адекватное речью это не пропустит. Если всегда использовать двойное сравнение — количество ошибок сводится к минимуму, а если вы хотите дать возможность не передавать параметр, то хорошим тоном будет дать возможность пропустить его через нул
faiwer
14.08.2018 12:29Между
a == null
иa === null || a === undefined
я бы всегда выбирал второе. Оно очевидно до предела. В первом же случае приходится чесать репу и вспоминать неочевидные правила приведения типов, кому оно надо?
subzey
14.08.2018 01:25+1Интервью на TS с одним вопросом: Напишите
memoize
(даже без параметра-хэшера, чтобы не убивать мозг).
Если написанная функция работает правильно и возвращает не
any
, а дженерик, значит, кандидат умеет и привык пользоваться сильными сторонами TS. Остальное — мелочиamakhrov
14.08.2018 08:08А кстати, как написать memoize, принимающий функцию с любым количеством аргументов?
Ну, то есть я вполне представляю себе, как написать мемоизатор для функций одного аргумента, для функций двух аргументов и так далее. Но вот чтобы сразу — для произвольного количества аргументов — так можно?
subzey
14.08.2018 10:23Вообще любого количества любых аргументов?
Я бы, наверное, строил дерево из
interface HashNode<T> { map: Map<any, HashNode<T>>; weakMap: WeakMap<any, HashNode<T>>; value?: T; }
И перебирая аргументы слева направо, траверсил бы его от корня:
- Если последующий аргумент объект — следующая текущая нода становится тем, что вернёт
.weakMap.get(arg)
(WeakMap, чтобы утечек памяти не плодить) - Если примитив —
.map.get(arg)
- Если аргументы ещё не кончились, а текущая нода оказалась
null
, значит, промахнулись мимо кэша - Если аргументы кончились и в текущей ноде есть собственное свойство
value
, это вот оно.
Ну или как-то так. Только такая мемоизация может оказаться "дороже", чем просто обёртываемую функцию дёрнуть)
- Если последующий аргумент объект — следующая текущая нода становится тем, что вернёт
CepbluBoJlk
14.08.2018 11:32Примерно так:
function memoize<TS extends any[], R>( fn: (...args: TS) => R, keyFn?: (...args: TS) => string): (...args: TS) => R { const cache: Record<string, { value: R }> = {}; return (...args: TS) => { const key = (keyFn || (args => args.reduce((acc, arg) => (acc += String(arg)), "")))(args); return (cache[key] || (cache[key] = { value: fn(...args) })).value; }; } const fn1 = (a: string) => 1; const fn2 = (a: string, b: boolean) => true; const fn3 = (a: string, b: boolean, f: (x: number) => void) => 1; const fn4 = (a: string, b: boolean, o: object) => 1; // (a: string) => number const mfn1 = memoize(fn1); // (a: string, b: boolean) => boolean const mfn2 = memoize(fn2); // (a: string, b: boolean, f: (x: number) => void) => number const mfn3 = memoize(fn3, (a, b, fn) => `${a}, ${b}, ${fn(1)}`); // (a: string, b: boolean, o: object) => number const mfn4 = memoize(fn4);
Правда нужен typescript версии > 3, blogs.msdn.microsoft.com/typescript/2018/07/12/announcing-typescript-3-0-rcsubzey
15.08.2018 01:31const memoIdentity = memoize(v => v); console.log(memoIdentity('hasOwnProperty'));
;)
mSnus
14.08.2018 04:31Простите, но
Как в TypeScript проверять значения на равенство null и undefined?
if (value) {
}Вроде как это проверка на НЕравенство? Разные по смыслу вещи.
monah_tuk
14.08.2018 11:04Напомните название фильма, хочу пересмотреть, а вылетело из головы.
Boomburum
14.08.2018 12:43«1+1» (или «Неприкасаемые»), шикарный фильм :) Только аргентинскую версию не смотрите.
Valery4
14.08.2018 20:38А что за аргентинская версия?
Boomburum
15.08.2018 01:10+1В прошлом году аргентинцы сняли свою версию фильма, которая называется так же (1+1), в ней всё то же самое по смыслу и шуткам, но плохо всё остальное: игра актёров, сами актёры итд. Не знаю как так произошло :) видимо там нашли сценарий где-то на старом диске и решили снять киношку, не зная, что шедевр уже был снят.
k12th
...
Шел 2018 год...