Комментарии 69
module Vehicle {
...
/// <reference path=" Sample.d.ts"></reference>
Шел 2018 год...
/* Неверно*/
interface Fetcher {
getObject(done: (data: any, elapsedTime?: number) => void): void;
}
Не является. Красивей было бы объявить несколько перегрузок, но на практике разницы нет, если имплементация это учитывает.
interface Fetcher {
getObject(done: (data: any) => void): void;
getObject(done: (data: any, elapsedTime: number) => void): void;
}
Не, скорее так:
interface IGetObjectCallback {
(data: any): void;
(data: any, elapsedTime: number): void;
}
interface Fetcher {
getObject(done: IGetObjectCallback): void;
}
Что-то не работает.
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
a.getObject(<IGetObjectCallback>(x: any, y: number) => {})
Пример с Fetcher тоже из этой документации. В статью почему-то не добавили совет и пример:
Пишите параметры колбэков, как не-опциональные:
/* OK */ interface Fetcher { getObject(done: (data: any, elapsedTime: number) => void): void; }
"… всегда можно передать коллбэк, который принимает меньшее число аргументов" будет правильнее.
Поправка: красивее по мнению автора оригинала.
1) Какие есть способы задать тип значения равным классу, внутри которого тип задаётся без использования его имени (по типу this.constructor в JS или self в PHP?
2) Какие есть способы задать тип значения, обозначающих конкретный декорируемый конкретным декоратор класс? Ну есть что-то вроде @loggable class Entity {}. просто где-то использовать let obj: Entity = new Entity() не рабоатет.
class A {
public b: this;
public c: string;
}
new A().b.b.c.toLowerCase();
2) Нет таких способов. И в целом, я думаю, что использовать декораторы, как множественное наследование — bad practice. Если нужно добавить в класс функциональность с публичным интерфейсом, лучше сделать это явно, без магии. А декораторы как раз предназначены для того, чтобы изменить поведение класса, не меняя интерфейс.
2. Русское наименование дженериков меня вообще в ступор ввело, хотя знаю их еще с C# когда писал в 2005 году
3. Это не реализация, а описание. В принципе таким же методом можно и геттер объявить.
6. Спрашивать про .map в TS? Реально? Если он о них не знает, значит и остальное просто 0.
13. В 2018 кто то вообще пользуется module?
15. Всё так. Никогда не думали что все мыслят по разному и то что принятно в одной команде, легко не принято в другой?
19. Если вы до сих пор используете reference path, я вам сочуствую.
20. Возможность может быть и есть, но нежизнеспособно.
Я вот только догадываюсь, что TS тоже может .map генерить как babel и, может быть, браузеры что-то покажут внятное. Но в обозримой перспективе даже уверенность в этом мне ничего мне не даст, весь маппинг в голове.
А вообще я к тому, что заявлять «Если он о них не знает, значит и остальное просто 0.» в отношении какого-то малозначимого и не всеми используемого параметра трансляции, как-то очень близко к ложноотрицательному выводу. Тем более в наше время, когда правит, как вы заметили, разделение труда, и настройками сборок нередко занимаются специально обученные люди, которым этим мапы даром не сдались и сделают они их, в лучшем случае, если моё начальство обоснует их необходимость перед их начальством, плюс докажет, например, третьим людям, что создание этих мап в процессе сборки не являтся угрозой безопасности или является, но вторые люди исключат их утечку.
А насчет угроз безопасности, это смешно… Никто не заставляет эти мапы отдавать заказчику и т.п. Да и сами должны понимать, что JS код не защищен от слова НИКАК
Да и зачем сидеть разбирать транспилированный код, если можно прекрасно дебажить исходный?
Не могу говорить за TS, но в случае JS и babel-я я давно отказался от source-map-ов. Побудило меня к этому:
- я натыкался на баги транспайлера, когда оный совершенно по непонятным причинам срезал куски кода совсем
- различные
_this2
вместоthis
приводят к тому, что это невозможно дебажить в консоли в runtime - различные
(0, _flatten3.default)(...)
вместоflatten(...)
приводят к тому, что невозможно дебажить в консоли в runtime - многие другие неочевидные моменты, закрытые от глаз
- многочисленные баги уже самого отладчика chrome
Порой в сложных случаях приходится очень сильно углубляться в дебаг, довольно мутных вещей. И если я там буду видеть ещё и не тот код, который по факту исполняется, то я далеко не уеду.
Возможно в TS картина точно такая же.
Я ведь не администратор, я ― разработчик. У меня перманентно что-нибудь не работает. Или новый функционал в процессе реализации, или сторонние библиотеки работают не так как ожидаешь, добавим различный отлов багов, и многое другое. Как тут без дебага? Можно даже пару дней в дебагере провести. По сути я что-нибудь отлаживаю практически каждый день. Ну может раз в два дня. Сам процесс отладки это… не одну книгу по трюкам и подходам можно написать.
Проблема в Babel я думаю не в плагинах и сообществе. С этим всё ок, баг в babel я пока встретил лишь единожды (кажется). Проблема скорее в том, что уж больно любит babel переименовывать сущности во всякие (0, _name4)
и прочие трюки. Да, наверняка, у каждого такого трюка есть своя причина, но в отладке это сильно мешает.
Самое простое — ломалась подсветка синтаксиса не транспилированного кода. Это ломало и просмотр значений при наведении. Из того, что посложнее, хм, был какой-то мутный баг с Object.entries. Правда это скорее к v8 баг, не к тулзам. Многократно наблюдал вылеты devtool-ов. Бывало по 30-40 раз в день умирали они. Тоже касается и браузерного таба (то самое "опаньки"). Многократно наблюдал недоступность каких-либо переменных, объявленных вот прямо под носом строкой выше (видимо какие-то внутренние оптимизации). Очень странное поведение трассировки, проскакивающее какие-нибудь куски (без blackbox). Да честно говоря всего не упомнишь. Обычно я или привыкал к какому-нибудь поведению, или оно "само" исправлялось с очередным релизом. Не репортил, каюсь, грешен. Репортил по v8, репортил по рендер-движку браузера, а вот по дев-тулзам ещё не репортил. Мне кажется это нетривиальным. Вот с полгода назад у меня гарантировано девтулзы мёрли в ряде обстоятельств. Но как это можно было воспроизвести без открытия кода — я не знал. А кому нужен мутный багрепорт без примера.
Какие вопросы вы задали бы тому, кто проходит собеседование, претендуя на должность, требующую знания TypeScript?Прочитайте этот список из 20 вопросов и ответов и объясните, почему их ни в коем случае нельзя использовать при отборе кандидатов со знанием TypeScript.
if (value) {
}
const a = {};
if (a){
// Это ведь JavaScript!
}
Такие проверки даже в JS чаще всего плохой тон, всегда нужно писать полную версию без приведения типа: a === null.
Лучше a == null, с двойным сравнением, а не тройным, тогда он проверит сразу на null и undefined, что в большинстве архитектур будет аналогичным значениями. Нету никакого смысла их разделять и потому двойное сравнение — самое правильное
Значения 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 с одинаковой семантикой, это только вероятность ошибок увеличит.
И зачем? Какая разница в реальном коде будет в первом и втором условии? Полагаться на разницу между null и undefined — признак попахивающего кода и никакое адекватное речью это не пропустит. Если всегда использовать двойное сравнение — количество ошибок сводится к минимуму, а если вы хотите дать возможность не передавать параметр, то хорошим тоном будет дать возможность пропустить его через нул
Между a == null
и a === null || a === undefined
я бы всегда выбирал второе. Оно очевидно до предела. В первом же случае приходится чесать репу и вспоминать неочевидные правила приведения типов, кому оно надо?
i = i + 1
// вместо
i++
// или
object.prototype.method.call(object, param1, param2)
// вместо
object.method(param1, param2)
и другие усложняющие чтение кода глупости на случай, если ваш код будет читать мимо пробегающий доставщик пиццы, который прочитал только первые две главы книги о JavaScript?
Никакого привидения типов при сравнении null и undefined не происходит, они просто нестрого равны:
If x is null and y is undefined, return true.
If x is undefined and y is null, return true.
Умные люди, которые улучшали этот стандарт понимают, что в любом нормальном коде эти два значения тождественны и необходим простой и читабельный паттерн для сравнения, потому и ввели его явно. Используется он давно — я видел его активное применение еще в старом коде Mootools — все интересующиеся языком его давно знают
object.constructor.prototype
, конечноTypeError: object.prototype.method is undefined
[].constructor.prototype.push
— так есть все методы, если всё корректно с constructorЯ ведь исправил ошибку свою)Это которую?
let object = { method: (p1, p2) => console.log(p1,p2) };
object.constructor.prototype.method.call(object, param1, param2);
TypeError: object.constructor.prototype.method is undefined
let obj2 = new function(){ this.method = (p1, p2) => console.log(p1,p2); }
obj2.constructor.prototype.method.call(object, param1, param2);
TypeError: obj2.constructor.prototype.method is undefined
var undefined = true
можно сломать, написав var undefined = trueНаписать можно, только он не сломается ;)
window.undefined
— read-only свойство.Ну значит я тот самый мимо-пробегающий доставщик пиццы. У меня код с ==
не пройдёт code review. К +=
, apply
, call
претензий не имею.
А кстати, как написать memoize, принимающий функцию с любым количеством аргументов?
Ну, то есть я вполне представляю себе, как написать мемоизатор для функций одного аргумента, для функций двух аргументов и так далее. Но вот чтобы сразу — для произвольного количества аргументов — так можно?
Вообще любого количества любых аргументов?
Я бы, наверное, строил дерево из
interface HashNode<T> {
map: Map<any, HashNode<T>>;
weakMap: WeakMap<any, HashNode<T>>;
value?: T;
}
И перебирая аргументы слева направо, траверсил бы его от корня:
- Если последующий аргумент объект — следующая текущая нода становится тем, что вернёт
.weakMap.get(arg)
(WeakMap, чтобы утечек памяти не плодить) - Если примитив —
.map.get(arg)
- Если аргументы ещё не кончились, а текущая нода оказалась
null
, значит, промахнулись мимо кэша - Если аргументы кончились и в текущей ноде есть собственное свойство
value
, это вот оно.
Ну или как-то так. Только такая мемоизация может оказаться "дороже", чем просто обёртываемую функцию дёрнуть)
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-rc
Спасибо! Это реально классно!
const memoIdentity = memoize(v => v);
console.log(memoIdentity('hasOwnProperty'));
;)
Простите, но
Как в TypeScript проверять значения на равенство null и undefined?
if (value) {
}
Вроде как это проверка на НЕравенство? Разные по смыслу вещи.
Напомните название фильма, хочу пересмотреть, а вылетело из головы.
Собеседование по TypeScript: 20 вопросов и ответов