Pull to refresh

Comments 30

Или просто flow прикрутить как постпроцесс на сохранение файла — получится то же самое с теми же сообщениями об ошибках.

Вряд ли это решение подойдёт для давно разрабатываемого проекта или для разработки в команде, где пишут только на чистом JS. А это не такой уж вырожденный случай, я вот так и работаю, например, как и многие фрондендеры в крупных компаниях.

Аннотации вам в любом случае писать придётся в документации. Так что лучше уж сразу писать формальные аннотации, по которым можно и документацию генерировать, чем лениться аннотировать код, а потом лениться обновлять документацию.

Какой-то ненадежный инструмент.

С одной стороны, несовпадение типов аргументов — это очень маленький процент от всех ошибок типизации. Например, если нужно отправить массив строк через POST и в него случайно попадет функция, мы об этом не узнаем.

С другой стороны, есть подозрение что он может сломать работающий код:

function hasDuplicates(arr) {
    for(var i = 0; var i < arr.length - 1; i++) {
        for(var j = i + 1; j < arr.length; j++) {
            if(arr[i] === arr[j]) return true;
        }
    }
    return false;
}

var result = hasDuplicates(['a', true]); // выкинет ошибку?

Сломать он ничего не сможет, потому что всего лишь выводит предупреждения в консоль, сохраняя результат операции.
Для вашего примера — да, будет ворнинг, т. к. в одном массиве хранятся данные разных типов (что не есть хорошо):


Оператор === специально сделан для того, чтобы безопасно сравнивать объекты потенциально разных типов. Если есть гарантия, что сравниваемые объекты всегда одного типа — можно и == использовать.

Если вы действительно проверяете с помощью простого typeof, как в примере, то у вас наверняка выдается ошибка при сравнении с null или undefined — хотя такое сравнение вполне корректно.

Кстати говоря, массив из элементов разных типов — это нормальная практика в JS-библиотеках. Например, в Angular так указываются аннотации для Dependency Injection.
Если есть гарантия, что сравниваемые объекты всегда одного типа — можно и == использовать.

С точки зрения синтаксиса да, но с точки зрение надежности, я бы не рекомендовал использовать "==".


Если вы действительно проверяете с помощью простого typeof, как в примере, то у вас наверняка выдается ошибка при сравнении с null или undefined — хотя такое сравнение вполне корректно.

Про явное сравнение x === null и x === undefined абсолютно согласен, в таких случаях разработчик явно показывает, что ожидает в переменной null|udnefined, поэтому предупреждений не будет.

Можно побыть немного занудой? Если в массиве будет NaN, ваш код сам сломается. Лучше так:


function hasDuplicates(arr) {
    for(var i = 0; i < arr.length - 1; i++) {
        if(arr.includes(arr[i], i + 1)) return true;
    }
    return false;
}

var result = hasDuplicates([NaN, 'a', true, NaN]); // ваша версия вернет false, моя - true
Это спорный момент. Я бы не ожидал, что hasDuplicates считает NaN равным самому себе, поскольку обычный оператор сравнения так не делает. Но всё зависит от контекста.

Есть еще подобный плагин для проверки в рантайме, но для Flow: babel-plugin-tcomb. Сам tcomb тоже стоит внимания.

Спасибо! Tcomb смотрел, а вот плагин не видел.

UFO landed and left these words here
это работает только с примитивными типами? Оно же даже массив с объектом отличить не сможет? И это же жесточайший удар по производительности. Нужна типизация? Смотрите на TypeScript или FlowType.
это работает только с примитивными типами?

пока да.


Оно же даже массив с объектом отличить не сможет?

на это есть issue


И это же жесточайший удар по производительности

это догадка или у вас есть пример с цифрами? На моих сборках разницы нет.

Бремя доказательства лежит на утверждающем.
Про производительность хотел бы посмотреть тесты и методику их постановки. Не то чтобы я не мог их поставить сам, но я не думаю что мне это нужно, всё и так понятно, не бывает бесплатного исполнения дополнительного кода.
Так для дева же. Запускаете отдельную таску на сборку с проверкой типов периодически — баги поискать. Всё остальное время без лишнего кода в обычном режиме.

Ну какой удар по производительности? Не будите же вы это в продакшене использовать. Это для этапа разработки.

Да, именно.


Кстати по сравнению с тем, что происходит например при транспайлинге es6 --> es5, то тут оверхед совсем небольшой: мы же и так в коде иногда пишем явную проверку через typeof в условиях.

что происходит например при транспайлинге es6 --> es5

а что там происходит? Можно конкретные примеры? Опять же с замерами если можно.

Пример можно взять прямо из REPL на сайте бабеля: https://babeljs.io/repl/
Было:


class A extends B {}

Стало:


"use strict";

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var A = function (_B) {
  _inherits(A, _B);

  function A() {
    _classCallCheck(this, A);

    return _possibleConstructorReturn(this, (A.__proto__ || Object.getPrototypeOf(A)).apply(this, arguments));
  }

  return A;
}(B);
это я видел. А тесты производительности. Вы их ставили?

Да: https://jsperf.com/runtyper-equal-perf


Сравним насколько медленнее становится === если заменить его на == и на самовызывающийся strictEqual(x, y) с проверкой типов:


Chrome 57:
== — 67% slower
strictEqual() — 94% slower


YaBrowser 17.3:
== — 84% slower
strictEqual() — 94% slower


Firefox 52:
== — 99% slower
strictEqual() — same time(!)

Да, полезный доклад.
Хотя в данном случае после заворачивания в функции получились ровно такие же результаты.

Такие мелкие штуки нельзя так тестить и в функцию заворачивая, там скорее всего вообще всё будет выброшено, нужно уже подробно смотреть что там наджитилось, а лучше бенчмаркать реальную задачу которая занимает какое-то ненулевое время, чтобы она долго выполнялась.
а лучше бенчмаркать реальную задачу которая занимает какое-то ненулевое время, чтобы она долго выполнялась.

Подскажешь, как правильно написать тест в данной ситуации?

Не обещаю на неделе, но может к выходным и напишу.
Иногда производительность важна и в NODE_ENV=development. У меня highload realtime webapp, в деве постоянно пухнет от утечек памяти и consol.log. А в NODE_ENV=production занимает максимум 32Mb в тестах на сутки и более.
Sign up to leave a comment.

Articles