Comments 56
Пробежался по доке. Ключевые отличия от текущего тайпскрипта (в будущем обещают реализовать):
1. объединения типов
2. как следствие — наличие не nullable типов
3. ветвление по типам
В остальном разница лишь косметическая. Я думаю было бы куда больше пользы, если бы они реализовали какой-нибудь typescript2.0, чем делать несовместимый в мелочах язык.
И, кстати, на typescript код переводить тоже можно постепенно (пофайлово), а вот с typescript на flow — не получится.
1. объединения типов
2. как следствие — наличие не nullable типов
3. ветвление по типам
В остальном разница лишь косметическая. Я думаю было бы куда больше пользы, если бы они реализовали какой-нибудь typescript2.0, чем делать несовместимый в мелочах язык.
И, кстати, на typescript код переводить тоже можно постепенно (пофайлово), а вот с typescript на flow — не получится.
И это говорит профессиональный велосипедист? Чем Фейсбук хуже?
Я не говорил, что он хуже. Я говорю, что им с Microsoft стоило бы объединить усилия вместо того, чтобы конкурировать.
Именно. TypeScript от Microsoft, AtScript от Google, Flow от Facebook — все пилят свой собственный JavaScript, с типами и интерфейсами. С минимумом различий. Ну их всех к чёрту, если договориться не могут. С таким подходом буду ждать аннотации типов в самом ECMAScript, тем более с этим, вроде, есть подвижки.
> пофайлово
Я бы сказал, что нет ограничений и typescript также можно переводить постепенно. Файлы TS могут содержать как TS так и JS код, иногда для этого нужно написать интерфейсы к JS части кода, но это вполне логично и нужно.
Но я не против, пусть будет, может что интересное получится)
Я бы сказал, что нет ограничений и typescript также можно переводить постепенно. Файлы TS могут содержать как TS так и JS код, иногда для этого нужно написать интерфейсы к JS части кода, но это вполне логично и нужно.
Но я не против, пусть будет, может что интересное получится)
В typescript нельзя переводить постепенно. Вы не можете взять js файл и просто изменить расширение. Вам либо прийдется для всех остальных классов проставить динамические типы в и не получать никакого анализа, либо переводить полностью.
В flow же есть вывод типа, что позволяет действительно ничего не делая получить информацию о потенциальных ошибках.
В flow же есть вывод типа, что позволяет действительно ничего не делая получить информацию о потенциальных ошибках.
Значит я делаю невозможное :-)
Например, при переводе какого-то модуля на TS обнаружилась зависимость от модуля $jin.asyn2sync. Чтобы не переводить его сейчас же на TS, я добавил файл с декларацией его апи. В результате при компиляции TS будет проведена проверка типов в соответствии с декларацией. Когда дойдут руки до перевода и этого модуля на TS — декларации и JS будут удалены и заменены на нормальную TS-реализацию.
А Flow вообще ничего не поймет, потому, что функция в том модуле создаётся через указание полного пути литералом.
Например, при переводе какого-то модуля на TS обнаружилась зависимость от модуля $jin.asyn2sync. Чтобы не переводить его сейчас же на TS, я добавил файл с декларацией его апи. В результате при компиляции TS будет проведена проверка типов в соответствии с декларацией. Когда дойдут руки до перевода и этого модуля на TS — декларации и JS будут удалены и заменены на нормальную TS-реализацию.
А Flow вообще ничего не поймет, потому, что функция в том модуле создаётся через указание полного пути литералом.
А вы пробовали Flow, или просто так говорите? Мой поинт в том, что Flow позволяет делать то, что вы описали без .d.ts как раз.
Я пролистнул документацию и не нашёл там даже поддержки jsdoc, а значит вытащить такие идиомы как «класс» или даже «примесь» из js кода он не сможет, потому, что в js есть тысяча и один способ реализовать наследование.
Все это пустые слова. Покажите код, посмотрим как отреагирует Flow.
Вместо тупой проверки типа переменной, Flow учитывает природу динамической типизации.
Вот вам пример, ошибка где надо — последняя строка
PS у меня есть предположение, что ядром flow является VM, а значит анализируется рантайм, а значит вы любым способом можете определить/унаследовать класс, а Flow все отследит. Только вот не могу ничем подтвердить догадки
Вместо тупой проверки типа переменной, Flow учитывает природу динамической типизации.
/* @flow */
function Foo (a) {
this.a = a;
}
Foo.prototype.bar = function(foo) {
console.log(foo.a);
}
var foo = new Foo(1);
foo.bar(foo);
foo.bar(123);
Вот вам пример, ошибка где надо — последняя строка
PS у меня есть предположение, что ядром flow является VM, а значит анализируется рантайм, а значит вы любым способом можете определить/унаследовать класс, а Flow все отследит. Только вот не могу ничем подтвердить догадки
function define( config ){
for( var path in config ) {
var current = this
var names = path.split( '.' )
for( var i = 0 ; i < names.length - 1 ; ++i ) {
var name = names[ i ] || 'prototype'
var next = current[ name ]
if( !next ) next = current[ name ] = {}
current = next
}
current[ names[ i ] || 'prototype' ] = config[ path ]
}
}
define({
'Foo' : function Foo (a) {
this.a = a;
},
'Foo..bar' : function(foo) {
console.log(foo.a);
}
})
var foo = new Foo(1);
foo.bar(foo);
foo.bar(123);
/Users/nkt/Desktop/flow.js:9:24,38: access of computed property/element
Computed property/element cannot be accessed on global object
/Users/nkt/Desktop/flow.js:10:32,51: assignment of computed property/element
Computed property/element cannot be assigned on global object
/Users/nkt/Desktop/flow.js:13:9,61: assignment of computed property/element
Computed property/element cannot be assigned on global object
/Users/nkt/Desktop/flow.js:26:15,17: identifier Foo
Unknown global name
Found 4 errors
Если this в define заменить на window — останется неизвестный Foo.
Будем ждать, что уж. Тут наверное тот случай, когда можно подсказать компилятору.
Плюс, на сколько я понимаю, Flow заточен под использование с ES6 и наверное не будет развивать es5, что в принципе логично.
Сравнение с typescript немного некорректно. Его придется компилировать, а парни из Flow утверждают, что все пашет само прямо на живую. Что несомненно лучше. Единственное, на мой взгляд, лучше бы они JSDoc начали парсить, чем вводить какие-то навороты по синтаксису, а то и правда TS получается.
ИМХО, с внедрением статической типизацией сейчас такой же дикий запад, как был в свое время с модульными системами. Когда каждый писал свой велосипед и было неизвестно доживет ли система модулей хотя бы до следующего года. Сейчас все более-менее устаканилось: browserify, webpack, requirejs. Еще одна реализация системы типов, это ок. Посмотрим какая из них реально выживет и в итоге станет стандартом. Пока что Flow это очень умный препроцессор, который почти не меняет исходный js-код. Посмотрим, что будет по мере добавления фич.
В отличии от TypeScript, есть возможность делать код типизированным постепенно.
Что вы имели в виду под этой фразой? В Typescript можно просто поменять расширение с
js
на ts
и всё будет компилироваться, поскольку Typescript — надмножество Javascript. А потом постепенно заменять типы — например, начиная с локальных переменных.Судя по каментам автор имел ввиду что typescript, при простом изменении расширения будет воспринимать код как обычный js, при этом будет игнорировать опасные моменты (например var q = 5; w = «5»; e = q + w;), flow же в такой ситуации выдаст предупреждение что проходит не математическая операция а конкатенация (типы не совместимы). Как-то так. Естественно оба языка будут работать с чистым js без проблем, они оба полностью совместимы с js.
Вы, мягко выражаясь, не правы
function foo( a ){
alert( a || 'hello world' )
}
foo() // error TS2081: Supplied parameters do not match any signature of call target.
Да, прошу прощения — вы правы, количество аргументов проверяется жестко. Но какой вариант логичнее с точки зрения статической проверки — показывать ошибку или нет — однозначно сказать нельзя. Всё зависит от того, как используется
В Typescript есть еще одна запрещенная конструкция, которая является допустимой в JS:
Было бы интересно узнать, что Flow говорит в обоих этих случаях.
a
внутри функции.В Typescript есть еще одна запрещенная конструкция, которая является допустимой в JS:
var x = "test";
x = 123;
Было бы интересно узнать, что Flow говорит в обоих этих случаях.
Для вызова функции без аргумента — Too few arguments (expected default/rest parameters in function)
Если изменить сигнатуру на function foo(a = undefined) — нет ошибок, es6 такое позволяет
Для второго примера все ок.
Более того
Ошибка на последней строке. Вот этим Flow и лучше TypeScript.
Если изменить сигнатуру на function foo(a = undefined) — нет ошибок, es6 такое позволяет
Для второго примера все ок.
Более того
/* @flow */
var x = "test";
x.indexOf('t');
x = 123;
x.indexOf('t');
Ошибка на последней строке. Вот этим Flow и лучше TypeScript.
Не сказал бы, что лучше. Обычно типы переменных не должны меняться. К тому же, что он выдаст на такое?
/* @flow */
var x = "test";
x.indexOf('t');
while( o > 1 ) {
o--;
x = Math.random();
}
x.toFixed( 2 );
/Users/nkt/Desktop/flow.js:5:8,8: identifier o
Unknown global name
/Users/nkt/Desktop/flow.js:9:1,14: call of method toFixed
Property not found in
А вот так ошибок нет:
/* @flow */
var x = "test";
x.indexOf('t');
var o = 0;
do {
o--;
x = Math.random();
}while( o > 1 );
x.toFixed( 2 );
Лучше? Я бы наоборот назвал это фундаментальным недостатком :)
Использование одной и той же переменной для поочередного хранения несовместимых данных и вызов методов на них — большой шаг на пути к неподдерживаемому коду, и куда менее вероятно, чем случайное переопределение значения переменной неправильными данными.
Кстати, а если переопределять значение переменной в цикле, что оно будет делать?
UPD: Товарищ vintage меня опередил, даже пример практически такой же.
Использование одной и той же переменной для поочередного хранения несовместимых данных и вызов методов на них — большой шаг на пути к неподдерживаемому коду, и куда менее вероятно, чем случайное переопределение значения переменной неправильными данными.
Кстати, а если переопределять значение переменной в цикле, что оно будет делать?
var data = ["123", 123];
var elem;
for(var i =0; i < data.length; i++)
{
elem = data[i];
elem.indexOf('1'); // что-то будет?
}
UPD: Товарищ vintage меня опередил, даже пример практически такой же.
На самом деле лучше бы в typescript добавил то что им не хватает. Выведение типов без аннотаций умеет google closure компилятор.
Я так понял, парням из фейсбука в typescript не понравилось то, что там нету ихнего безумного JSX. А гуглю с аналогичной поделкой — видимо что-то не хватает для из ангуляра. Может тоже строго-типизированного HTML, лол. Обоим двум пока не хватает мозга понять что JSX и Angular нужно просто выкинуть в помойку как побочные эффекты эволюции.
Но нет — будет у нас ещё два тайпскрипта. Привычно, в очередной раз, вздыхаем, берем попкорн и смотрим шоу. Которое, разумеется, закончится тем, что JSX и ангуляр выкинут в помойку.
Но нет — будет у нас ещё два тайпскрипта. Привычно, в очередной раз, вздыхаем, берем попкорн и смотрим шоу. Которое, разумеется, закончится тем, что JSX и ангуляр выкинут в помойку.
JSX и ангуляр выкинут в помойку
Это вы как себе представляете? А на чем приложения писать на чистом js?
На реакте и его потомках. Если ничего лучше не придумают.
На то что подход ангуляра не взлетел и больше никогда не взлетит — коственно указывает практически полное отсутствие под него компонентов и остальной инфраструктуры, то что гугль сам его толком не использует, ну и просто здравый смысл.
На то что подход ангуляра не взлетел и больше никогда не взлетит — коственно указывает практически полное отсутствие под него компонентов и остальной инфраструктуры, то что гугль сам его толком не использует, ну и просто здравый смысл.
AngularJS отлично дружит с Typescript. Единственное, чего пока не видел — качественного автодополнения кода в выражениях типа
ng-repeat
.До реорганизации хабра, я имел возможность к статьям ни о чем оставлять камменты, и из разговоров иной раз выносить какие-то мысли. Иногда набрасывал, иногда — давал какие-то советы, иногда — помогали мне. Было в целом прикольно, и у меня был даже какой-то положительный бюджет в карме, который я воспринимал чисто как автомагическое определение моего поведение как нормального человека — не тролля и не спаммера.
Сейчас, за два минуса, мне выдали бедж «отхабренный», и ограничили возможность комментировать одним камментов в пять минут.
Учитывая такое тупорылое поведение робота, настроенного тупорылыми хозяевами ресурса (которые сворее всего — тупорылые PHP-шники), пожалуй, это будет мой последний сюда визит. Искренне желаю тупорылой команде хабра придти к своей исконной цели — стать местячковой тусовкой тупорылых PHP-шников. С перепостами новостей месячной давности, и физической невозможностью высказывать по этому поводу любые мысли, перпендикулярные общепринятым в тупорылом PHP-сообществе тупорылым мейнстримным понятиям.
За сим — откланиваюсь.
Сейчас, за два минуса, мне выдали бедж «отхабренный», и ограничили возможность комментировать одним камментов в пять минут.
Учитывая такое тупорылое поведение робота, настроенного тупорылыми хозяевами ресурса (которые сворее всего — тупорылые PHP-шники), пожалуй, это будет мой последний сюда визит. Искренне желаю тупорылой команде хабра придти к своей исконной цели — стать местячковой тусовкой тупорылых PHP-шников. С перепостами новостей месячной давности, и физической невозможностью высказывать по этому поводу любые мысли, перпендикулярные общепринятым в тупорылом PHP-сообществе тупорылым мейнстримным понятиям.
За сим — откланиваюсь.
Как по мне, так google closure compiler с его прекрасной системой аннотирования. Которые совместно не только позволяют искать ошибки на ранних стадиях, но и ужимать скрипты, повышать производительность и даже использовать информацию о типах при оптимизации — вещь на много более полезная. К сожалению стилистические требования для продвинутой оптимизации немного высоковаты, что не позволяет его широко использовать.
Но мне нравится направление движения сообщества, которому не хватает типов в таком типо-разгильдяйском языке как JS.
Но мне нравится направление движения сообщества, которому не хватает типов в таком типо-разгильдяйском языке как JS.
Я имею большой опыт разработки на closure compiler и могу сказать что писать для closure компилятора довольно утомительно, код получается зашумлённый и нужнопостоянно проверять что написанный код в Release режиме работает так же как в debug`е. Есть загнувшийся проект который модифицировал typescript компилятор таким образом что он при компиляции выдавал js код с аннотациями для closure компилятора, я считаю была очень здравая мысль, жалко не развилась.
По поводу утомительно и зашумлено — не согласен. То же самое, что и на других языках типа java. Иногда бывают танци-с-бубном для избавления от варнингов, но при некотором опыте — это не напрягает.
По поводу проверки работает ли оптимизированный код — так я последний раз сталкивался год назад с тем, что компилятор не то «нагеморировал». И то в не совсем красивом инжекшине.
По поводу тайпскрипта — это да, это очень приятно. Но у меня опустились руки, как только подумал сколько времени нужно потратить, дабы преобразовать саурсмап от откомпилированного google closure compiler результата через саурсмапы тайпскрипта к исходникам…
По поводу проверки работает ли оптимизированный код — так я последний раз сталкивался год назад с тем, что компилятор не то «нагеморировал». И то в не совсем красивом инжекшине.
По поводу тайпскрипта — это да, это очень приятно. Но у меня опустились руки, как только подумал сколько времени нужно потратить, дабы преобразовать саурсмап от откомпилированного google closure compiler результата через саурсмапы тайпскрипта к исходникам…
Я не знаю как в сравнении с Java, но в сравнении с C# анотации closure это очень утомительно и не читабельно.
По поводу нагеморировал, вот такой код
/** param {Object} a */
function(a){
var x = a.someField;
}
closure в advanced режиме преобразует в такой
function(a){
var x = a.mangledField;
}
Спрашивает, какого он переименовал поле, если не имеет о нём никакой информации?
По поводу нагеморировал, вот такой код
/** param {Object} a */
function(a){
var x = a.someField;
}
closure в advanced режиме преобразует в такой
function(a){
var x = a.mangledField;
}
Спрашивает, какого он переименовал поле, если не имеет о нём никакой информации?
«Спрашивает» -> «Спрашивается»
>… но в сравнении с C# аннотации closure это очень утомительно и не читабельно.
Возможно XML Comments чем-то лучше чем javaDoc формат, но как по мне это не принципиально. (Только не скажите, что доки писать вредно!)
Прошу прощения за оффтопик
Не стоит жаловаться на переименование свойств, если используете адвансед оптимизацию — пишите просто верно. Ко всему прочему есть различные externs, publish итп. В привате отвечу на вопросы, а тут не стоит засорять.
Возможно XML Comments чем-то лучше чем javaDoc формат, но как по мне это не принципиально. (Только не скажите, что доки писать вредно!)
Прошу прощения за оффтопик
/** @param {Object} a */
function(a){
var x = a['someField'];
}
//Преобразует к
function(a){
var x = a.someField;
}
Не стоит жаловаться на переименование свойств, если используете адвансед оптимизацию — пишите просто верно. Ко всему прочему есть различные externs, publish итп. В привате отвечу на вопросы, а тут не стоит засорять.
Я лично именно за такой вариант, когда при применении RequireJS (ну или Cajon, если CommonJS синтаксис ближе) есть и модульность и нет необходимости что-то компилировать перед запуском, а парсинг JSDoc обеспечивает более-менее вменяемое автодополнение при написании и подсветку потенциально опасных мест. На мой взгляд, компилировать язык, который без этого прекрасно обходится — есть безусловное зло. Только при создании билда на продакшен, там это оправдано.
Сейчас IntelliJ продукты (WebStorm, IDEA и т.д.) прекрасно справляются с большинством ситуаций при наличии хорошо написанного JSDoc.
Надеюсь это направление со временем не отомрет и JS не придет к тому, что любой чих надо будет перекомпилировать…
Сейчас IntelliJ продукты (WebStorm, IDEA и т.д.) прекрасно справляются с большинством ситуаций при наличии хорошо написанного JSDoc.
Надеюсь это направление со временем не отомрет и JS не придет к тому, что любой чих надо будет перекомпилировать…
Это конечно очень приятно, и в целом я с Вами согласен.
А в дебаг режиме не нужно ничего компилировать, оно и так работает как RequireJS.
Но иногда бывают проекты с многими мегабайтами исходников, которые должны быть загружены за 6 секунд максимум по вайфай, и работать на андроиде с 512 памяти. Тогда различие в десятки раз по времени загрузки, в разы по трафику и в существенные проценты по потреблению памяти играют огромную роль. Но на много важнее то, что есть список варнингов, который учитывает и приведения типов, и вычисляемые выражения и много чего еще.
Анализаторы InteliJ подсвечивают лишь малую часть возможных варнингов.
> Надеюсь это направление со временем не отомрет и JS не придет к тому, что любой чих надо будет перекомпилировать…
Не отомрет! ;)
(Только привычка разработки методом, близким к «научному тыку», как правило менее качественна, чем у людей, которые не могут себе позволить, даже в голове, писать маленькими не полными кусочками. Парадокс, но я к примеру делаю больше ошибок в примитивных для-себя страничках на jQuery, чем на ассемблере 20 лет назад.)
А в дебаг режиме не нужно ничего компилировать, оно и так работает как RequireJS.
Но иногда бывают проекты с многими мегабайтами исходников, которые должны быть загружены за 6 секунд максимум по вайфай, и работать на андроиде с 512 памяти. Тогда различие в десятки раз по времени загрузки, в разы по трафику и в существенные проценты по потреблению памяти играют огромную роль. Но на много важнее то, что есть список варнингов, который учитывает и приведения типов, и вычисляемые выражения и много чего еще.
Анализаторы InteliJ подсвечивают лишь малую часть возможных варнингов.
> Надеюсь это направление со временем не отомрет и JS не придет к тому, что любой чих надо будет перекомпилировать…
Не отомрет! ;)
(Только привычка разработки методом, близким к «научному тыку», как правило менее качественна, чем у людей, которые не могут себе позволить, даже в голове, писать маленькими не полными кусочками. Парадокс, но я к примеру делаю больше ошибок в примитивных для-себя страничках на jQuery, чем на ассемблере 20 лет назад.)
А в дебаг режиме не нужно ничего компилировать, оно и так работает как RequireJS.
Если Вы про google closure compiler, то да, а вот фишки Flow, в которых задействовано в т.ч. расширение синтаксиса, без пре-компиляции не взлетят. Так что я сугубо за подход через аннотации в комментариях.
Что касается проектов с мегабайтами исходников — для таких только бандлы функциональности, загружаемые по мере надобности, и, безусловно, прекомпиляция, но так то ж для продакшена. Там можно многое, чего не желательно иметь в дев режиме. И наоборот…
А как код потом выполняется?
Насколько я знаю JS (а я знаю я его по Qt Quick только), там нельзя указывать типы подобным образом…
Насколько я знаю JS (а я знаю я его по Qt Quick только), там нельзя указывать типы подобным образом…
Пишите в начале файлик с типами через function (a: number, b: string), а дальше препроцессор прогоняет ваш файлик и вырезает все ваши указания типов, оставляя function(a, b)
Это грустно как-то, по сути в системе контроля версий имеешь неработоспособный код, который перед использованием еще нужно чем-то прогонять =\
Для js — это вполне нормальная ситуация. Клиентские приложения часто пишутся с использованием например commonjs, сборка в этом случае все равно требуется, несмотря на то что сам код написан на чистом js.
а в c++ не так? Перед использованием, код нужно прогнать компилятором)
Вместо того, чтобы изменить сам язык, лучше сделать невозможное и написать для него статический анализатор :)
Sign up to leave a comment.
Flow — статический анализ типов в JS от Facebook