Pull to refresh

Comments 42

Сходства? Есть только различия:
TypeKit — язык
Flow — статический анализотор JavaScript
Брр, бес попутал — конечно TypeScript.
Использую пару лет в продакшене, пишу на TS с самого зачатия.

Чтобы использовать какой-то внешний инструмент (читай «библиотеку» или «фреймворк»), тогда сигнатуру каждого из методов каждого модуля этого инструмента необходимо описать
Не обязательно, можно «заткнуть» какую-то библиотеку через any. Например, допустим нет определений для jQuery, но её можно использовать просто описав так: var $: any;

а разработку тратится больше времени, в сравнении с JavaScript. Это вызвано тем, что помимо реализации класса необходимо описать все задействованные интерфейсы, сигнатуры методов.
Это достаточно распространенное заблуждение. На самом деле, типы можно определять «на ходу», т.е. inline. Например: f(arg: { p: number; }): void; — это функция, которая принимает такой объект, у которого есть свойство p типа number. Или так: f() { return { p: 10; }; } — возвращает автоматически выведенный тип { p: number; }.

Код такого вида невалиден:
var foo: { [key: string]: number; }
foo = {};
foo.foobar = 10; // error
Потому что вы не определили свойство foobar. Но можно так:
var foo: { [key: string]: number; }
foo = {};
foo['foobar'] = 10; // OK


Реальная проблема TS: достаточно сложно отучиться писать его как JavaScript, не писать на нём как на C#, а найти что-то среднее.
И ещё: не понял, чем вам не нравятся определения конструктора.
interface SomeType {
    new (value: string): Instance;
    new (value: number, value2: {}): Instance;
}
Очевидно, это был мой пробел.
Спасибо, не знал про new в интерфейсе.

Попробовал использовать то, что вы написали, и получил ошибку.
Буду очень вам признателен, если вы сможете объяснить в чем ошибка: ссылка на Playground
Этот случай описан здесь: www.typescriptlang.org/Handbook#interfaces-class-types (пункт Difference between static/instance side of class)

На мой взгляд решение предложено довольно странное.
some_x, спасибо за ссылку.

Я думаю что написанному на странице по ссылке есть объяснение, но для меня оно пока не очевидно.

Исходя из прочитанного, я склонен думать что решение предложенное по ссылке является костылем:
This is because when a class implements an interface, only the instance side of the class is checked. Since the constructor sits in the static side, it is not included in this check.


Получается, вместо того чтобы описать сигнатуру конструктора в интерфейсе и просто написать класс реализующий интерфейс, мы должны делать такой, назовем это, «крюк».

Лично у меня создалось ощущение что авторы языка столкнулись с каким-то блокером при реализации описания сигнатуры конструктора, и чтобы не решать проблему просто решили ее «обойти».

Возможно, я не прав, но впечатление создалось именно такое.
Да, такая проблема есть — язык пока недостаточно выразительный. Из-за этого же нельзя нормально сделать расширемые встроенные классы: github.com/Microsoft/TypeScript/issues/1168

Но код не компилируется по абсолютно правильной причине, у вас интерфейс SomeType реализует тип typeof SomeClass (т.е. глобальная джаваскрипт переменная SomeClass), а не инстанс SomeClass, как вы описали.
Вообще, с точки зрения классического ООП, конструктор — это часть реализации, а не интерфейса.
Думаю, авторами языка этот костыль был внедрен для того, чтобы можно было писать дефиниции на уже существующие библиотеки (в которых вполне может быть полиморфизм в конструкторе, а в TS полиморфизма в таком понимании нет)
Это нужно хотя бы чтобы описать стандартную библиотеку.
var foo: { [key: string]: number; }
foo = {};
foo['foobar'] = 10; // OK


Возможно, я ошибаюсь, но я склонен считать что это костыль.
Фактически, сделав так — мы обманули компилятор чтобы решить свою собственную задачу.

a553,
Это нормальная практика?
Много бывает ли кейсов, когда приходится прибегать к решениям такого типа?
Ошибаетесь. В интерфейсе мы объявили foo как словарь. Так что логично, что обращаться к нему надо как ко словарю, а не как к объекту. То, что в JS все объекты — словари и можно использовать обе формы записи — особенность объектной модели JS.

Костыль — это когда приходится писать что-то типа:
var foo = { bar : 10 };
foo['__cache__'] = {}; // OK
Это не совсем костыль, а скорее «переработка» языка в попытках сделать код типобезопаснее. foo['foobar'] вполне понятно почему разрешен — вы объявили индексатор, и компилятор подчиняется. Вопрос в том, почему нельзя написать foo.foobar — возможно, это сделали так, чтобы не давать разработчику иллюзию типобезопасности. Код вида foo.barbar от foo.baibar на глаз отличается плохо, а в ts привыкаешь, что наличие свойства проверяет компилятор, и ошибка неочевидно. Другое дело — индексатор, в котором достаточно очевидна необходимость удостовериться в идентичности ключей.

Настоящий костыль — это включаемый в настройках компилятора строковый индексатор у Object, созданный для ленивых людей. :)
Скажите, как писать на нём модули Angular 1.x. Так и не осилил внедрение зависимостей.
Вы бы не могли подробнее описать, с чем именно у вас затруднения? Возможно я смогу вам помочь.
Делаю фабрику, которая использует $resource и $sce. На JS пишу так:

(function (A){
    "use strict";
    A.module('app').factory('FactoryName', [ '$resource', '$sce', function($resource, $sce){
        var r = $resource('/api/url/:id/', {
            id: '@id'
        }, {
            update: {
                method: 'PATCH'
            }
        });

        function Factory(){
            // Код инициализации
        }

        // Расширение прототипа свойствами и методами
        Factory.prototype.someMethod = function(){
            return $sce.trustAsHtml(this.someProperty);
        };

        return Factory;
    }]);
}(this.angular));


Как написать то же самое на TS? Видел где-то, как внедряются зависимости через $inject, но не понял до конца суть этого метода, да и выглядело в той статье всё это ужасно.
Разделите внедрение зависимостей + конфигурация и класс фабрики, а зависимости передавайте через конструктор.

angular.module('app').factory('FactoryName', ['$resource', '$sce', function ($resource, $sce) {
    var apiObjectResource = $resource('/api/url/:id/', {
        id: '@id'
    }, {
        update: {
            method: 'PATCH'
        }
    });
    return new Factory($sce, apiObjectResource);
}]); 

class Factory {
    $sce: ng.ISCEService;
    apiObjectResource: angular.resource.IResource<APIObject>;
    someProperty;
    constructor($sce, apiObjectResource) {
        this.$sce = $sce;
        this.apiObjectResource = apiObjectResource;
    }
    someMethod() {
        return this.$sce.trustAsHtml(this.someProperty);
    };
}
class APIObject {
    id: number;
}
sferrka верно написала. Через $inject удобно внедрять зависимость например в класс контроллера

class SwiperController { public static thumbnailsMaxWidth = 55; public static thumbnailsMaxHeight = 33; public static $inject = ["$element", "$scope"]; constructor(private swiperRootElement: ng.IAugmentedJQuery, private _scope: ng.IScope) { ... } }

(Не могу понять почему не работает)
Коментарий выше оказался испорчен потому что не уложился в ограничение в 3 минуты :(
Вместо (Не могу понять почему не работает) читать (Извиняюсь за форматирование, почему-то не могу заставить работать тэг )
Насколько быстро компилируется крупный проект?
TypeScript компилирует каждый файл, отдельно, без зависимостей. Можно выбрать для какой системы модулей компилировать — CommonJS, AMD, ES6. Т.е. зависит напрямую от количества файлов и кода в них.
Это всего-лишь трансляция в JS. После неё идёт проверка типов, для которой, по понятным причинам, нужен код всего проекта.
Не совсем правда: MSBuild умеет запускать билд всех файлов в проекте одним процессом, а после одного билда не запускать перекомпиляцию, если ts файлы не менялись. У меня проект из 500 ts файлов с 70 000 строк кода компилируется около 3 секунд.
Разве не правду сказал? Ну ок, значит это я слишком быстро думаю, раз успеваю хабр почитать, пока проект компилируется.
После того как они оони повысили скорость компилятора в 4-5 раз я лично проблем не испытваю. Не могли бы вы описать более конкретно: сколько у вас файлов, сколько строк кода в них, как долго идёт компиляция, какая версия компилятора, как компилируете (vs/grunt/gulp ?)
Ну, у некоторых и IDEA «не тормозит» :-)
Порядка сотни относительно небольших файлов, сборка каждого пакета — 2-3 секунды.
Компилирую через Compiler API.
Полная сборка проекта ~350К строк занимает 10 секунд.
Инкрементальная пересборка webpack'oм(https://github.com/s-panferov/awesome-typescript-loader) в зависимости от фундаментальности изменений занимает 1-3 секунды
Дебажить TS-код под node.js с бряками и вотчами уже можно?
В IDEA, как минимум, да. Единственный нюанс — стектрейсы ничего не знают про сорсмапы.
А есть issue в трекере? Я из JetBrains, могу починить.
Не знаю. Речь идёт о стектрейсах, что пишутся в логи. Тут разве что можно при переходе из консоли к файлу понимать, что для него есть сорсмап и открывать исходник. Ещё, к слову, дебаггер в IDEA не очень дружит с node-fibers — после возобновления волокна дебаггер не может получить доступ к содержимому переменных.
Спасибо большое. То, что надо :-)
Visual Studio Professional 2013 + nodejstools.codeplex.com + typescript на backend и frontend — полёт нормальный. Раньше не всегда срабатывал маппинг и брейкпойнт останавливался в нужном месте, но в файле *.js. С апдейтами NTVS, это проблема встречается все реже.
Кстати, на edx.org 2 июня начинается курс по typescript
Генерируемый JS очень похож на исходный код на TS и дебажить его довольно просто, это не создаёт никаких проблем, по крайней мере мне.
Не понял проблему с typeof. Конструктор и экземпляр разные же вещи.
Так и есть. В примере в статье функция ожидает получить конструктор, а не экземпляр. Поэтому в качестве типа указывается конструкция typeof , которая указывает на потребность получения конструктора класса, а не его экземпляра. Подробнее можно почитать об этом здесь
Sign up to leave a comment.

Articles