TypeScript vs Flow (Part 3 of 3) – Syntax Difference

This is part three of three of TypeScript vs Flow. We previously saw the fundamental differences between TypeScript and Flow, then we saw some high-level differences in terms of features. Now, we will see at a much lower level the differences at the syntax.

Declaration

TypeScript and Flow are exactly the same.

Const 
let 
var

Primitive

Again, no difference.

Number 
Boolean 
String 
Null 
Undefined 
Void

Array

And again, no difference.

[] 
Array<T>

Enum

TypeScript is shorted:

// Language file:
export enum Language {
 English,
 French
}
// Use of Language file:
import { Language } from "../general/Language";
export class LocaleManager {
 public static GetLocale(language: Language): void {
 switch (language) {
 // ...
 }
 }
}

Flow requires the value in const, and special import. It’s more verbose.

// Language file:
// @flow
export const LANGUAGES_VALUE = {
 FRENCH: "French",
 ENGLISH: "English"
};

export type Language = $Values<typeof LANGUAGES_VALUE>;
// Use of Language file:
import type { Language } from "../general/Language";
import { LANGUAGES_VALUE } from "../general/Language";

export class LocaleManager {
 static GetLocale(language: Language): void {
    switch (language) {
    // ...
    }
 }
}

Maybe Argument

Watch out the question mark in the few next examples. Flow distinguishes null and undefined between optional and maybe.

TypeScript:

{ propertyName?: string } //Allow null & undefined

Flow:

{ propertyName: ?string } //Allow null & undefined 

Optional Property

TypeScript:

{ propertyName?: string } //Allow null & undefined 

Flow:

{ propertyName?: string } //Allow undefined 

Optional Argument

TypeScript:

 ( propertyName?: string ) //Allow null & undefined

Flow:

( propertyName?: string ) //Allow undefined 

Literal value as type

In both cases, same syntax. For example, the code below only accepts the value of two. The difference is that TypeScript allows us to pass null or undefined. Flow doesn’t. To have Flow accept null you need to use the maybe concept which is to put a question mark right before the two.

function funct(value: 2) {}
// Flow to accept 2 and null and undefined:
function funct(value: ?2) { }
// Flow to accept 2 and undefined by not null:
function funct(value?: 2) { }

Union type

Union type are supported by both and have the same syntax. Indeed, TypeScript allows to pass null and undefined while Flow doesn’t.

function funct(arg1: "a" | "b" | "c") { }
// Flow to have also null and undefined:
function funct(arg1?: "a" | "b" | "c" | null) { }

Union primitive type

Union with primitive work the same. TypeScript is consistent by letting null and undefined as well.

function funct(arg1: number | string) { }
// Flow to accept null and undefined:
function funct(arg1?: number | ?string) { }
function funct(arg1?: number | string | null) { }

Mixed keyword

Mixed doesn’t exist with TypeScript, so here is how it’s written in Flow. In TypeScript, you would use “any” or an empty definition with the curly brace: {}. The difference is that with “any” or curly brackets you can redefine the variable with any type once initialized. With Flow and the use of mixed, it’s any type until it’s defined. Once defined, the type is set for the life of the variable. Nice addition to the language, it’s a “dynamic any”.

function funct(arg1: mixed) { }

Any type

Same syntax.

function funct(arg1: any) { }

Define return type

Returning value is with the semi-colon followed by the type. If nothing, return void.

function funct(): string { }

Function type

The signature of a method is exactly the same. It uses the JavaScript keyword “function” with parentheses that contain the name followed by the type. After the semicolon, the type is returned.

function funct(p1: string, p2?: boolean): void { }

Function w/o type

Function returns void by default in both.

function funct(p1, p2) { } 

Function fat arrow

Fat arrow is a copy and paste between the two.

let funct = (p1, p2) => { }

Function with callback

Callback arguments are written the same way in TypeScript or Flow.

function funct(cb: (e: string | null, v: string | number) => void) { }

Funct with rest

Both support the long and short version.

function funct(...args: Array<number>) {}
function funct2(...args: number[]) {}

Type Alias

Aliases are written the same way in both case.

var obj1: { foo: boolean } = { foo: true };
// or
type MyType = { value: boolean };
var obj2: MyType;

Type Alias with Generic

Generic doesn’t change anything. TypeScript and Flow stays the same.

type MyObject<A, B, C> = {
 property: A,
 method(val: B): C,
};
var x: MyObject<number, string, boolean> = { property: 1, method: (string) => { return
true;}}

Subtype

Defining your own type is the same in Flow or TypeScript.

type TypeLetters = "A" | "B" | "C";

Object as map

The first part is the same. You can use a string between square bracket to access in read or write a member of an object.

var o: { foo?:number } = {};
o["foo"] = 0;

However, TypeScript won’t allow dynamic adding of a member. In TypeScript, once a type is set to a variable, this one cannot change. The exception is the “any” type.

var o: { foo?:number } = {};
o["foo"] = 0;
o[“bar”] = 2; //This will work in Flow, but not in TypeScript


This is interesting since Flow is looser in this regard, and TypeScript is looser in term of the null/undefined. The justification of TypeScript to be strict is its structural typing.

Array

Pretty similar except the case of allowing Null. Here are all the similar scenarios.

var x = [];
var y = [1, 2, 3];
var z = new Array();
var w: boolean[] = [true, false, true];
var v: Array<boolean> = [true, false, true];

Here is how TypeScript does with null (nothing to do) and how to add the possibility of null in Flow.

var s: number[] = [1, 2, null];
var s: (?number)[] = [1, 2, null];

Tuple

Same syntax for tuple.

var tuple: [number, boolean, string] = [1, true, "three"];

Key interpolation

var obj1: { foo: boolean } = { foo: true };
obj1["foo"] = false;

Opaque Type

With Flow you can define a type detail to be only available to a module. Here is an example. It can be used by an external module by importing it. However, the other file that imports won’t be able to assign it as Number, only as “MyType”. This feature can be interesting for people to enforce the use of their type. This is not available for TypeScript.

opaque type MyType = number;

Interface and Implementation

Implementing an interface is the same in Flow or TypeScript.

interface Serializable {
 serialize(): string;
}
class Foo implements Serializable {
 serialize() { return '[Foo]'; }
}

Interface as map

Both share the same syntax.

interface MyInterface {
 [key: string]: number;
}
var x: MyInterface;
x.key = 3;

Interface and object

Both are the same for the first part.

interface MyInterface{
  foo: string,
  bar: number
}
var x: MyInterface = {
  foo : "foo",
  bar : 1
};

However, TypeScript is more permissive since you do not have to define both members. You can just define the type, without defining any value at all, and later assign the value. By default, the value will be undefined.

var x: MyInterface;
x.foo = "foo";
x.bar = 1;

Covariance property (readonly)

The syntax is a little bit different. TypeScript is using a longer approach, similar to C# with the keyword “readonly”. Flow is using the plus symbol.

interface MyInterface{
 readonly foo: string
}
var x: MyInterface = { foo: "bar" };
x.foo = "123"; // Blocked!

Flow:

interface MyInterface{
 +foo: string
}
var x: MyInterface = { foo: "bar" };
x.foo = "123"; // Blocked!

Contravariance

TypeScript needs to have the type to be defined to all possible value. In the following example, the field is of type number. However, in the code, it can be a number or a string. TypeScript blocks the code to compile since there is a possibility of being a string, so it says that it must be a number or a string.

interface Contravariant { writeOnly: number; }
var numberOrString = Math.random() > 0.5 ? 42 : 'forty-two';
var value2: Contravariant = { writeOnly: numberOrString }; // Doesn't work. Need to
change the type number to be : number | string

With Flow, with the same syntax, you get the same result. However, with the sign minus, you can make the code to be contravariant.

interface Contravariant { -writeOnly: number; }
var numberOrString = Math.random() > 0.5 ? 42 : 'forty-two';
var value2: Contravariant = { writeOnly: numberOrString }; // Works!

Again, this is a small syntax difference. At the end, isn’t just simpler to just mark the type to “string | number” in both case?

Generic Class

Exact same syntax.

class Item<T> {
 prop: T;
 constructor(param: T) {
 this.prop = param;
 }
}
let item1: Item<number> = new Item(42);

Generic Interface

As we saw earlier, TypeScript allows to declare a type and not instantiated completely or completely. Flow must declare and instantiate.

interface MyInterface<A, B, C> {
 foo: A,
 bar: B,
 baz: C,
}

// Flow and TypeScript:
var x: MyInterface<string, number, boolean> = {foo:"1", bar:4, baz:true};

// Only TypeScript:
var x: MyInterface<string, number, boolean>; // Notice that we only declare.
x.foo = "123";

Generic Type

Both allows to have generic type in the same syntax.

type Item<T> = {
 prop: T,
};

Generic Function

Generic function share the same syntax between Flow and TypeScript.

function funct1<T>(p1: T, p2 = "Smith") { }

Default parameter value

Default parameter use the equal sign followed by the value in both cases.

function funct1(p1: string, p2 = "Smith") { }

Generic Type with default type and value

TypeScript uses the keyword extends to have a generic type from a particular type. Default value is the same.

Type Item<T extends number = 1> = {
 prop: T,
};

Flow uses the semicolon to enforce the generic type and equal sign for default.

type Item<T: number = 1> = {
 prop: T,
};

Cast

Cast is different. Require having parentheses and a semi colon in Flow. TypeScript uses “as” like in C#. Flow is a little bit more verbose and can become harder to see in a situation within the inner function with many parentheses and curly braces.

var x: number = otherVariable as number;
var x: number = (othervariable: number);

While I was investigating Flow, I was getting more and more surprised by the similitude with TypeScript. In this third article, we can see that the syntax is so common with TypeScript that it’s hard to be very polarized about which one is really the best. There are few fundamental differences that we saw in terms of concept, but even there it’s not very deeply different. Indeed, Flow is checking more scenarios, and TypeScript is letting some scenarios be more “JavaScript-ish”, but still, in other scenarios allows a strong rigidity and better encapsulation.

Every team is different. Every person has a different past. Flow and TypeScript should cover the need of having your code more strongly typed, less prone to error, and easier to understand by everyone who reads it. The choice of Flow or TypeScript is a matter of little details. At the end of my investigation, I was all open to going with Flow for our new project at Netflix. However, the last meeting tipped the decision to go with TypeScript. In our case, the number of supported third-party libraries was something that changed our mind.

Parts of the serie:

TypeScript vs Flow (Part 2 of 3) – High Level Coding

This is the second article of three about differences between TypeScript and Flow. You can read the first part about high level of TypeScript vs Flow in this article. The investigation I conducted was done on August 9 and August 10, 2017. It’s a domain where it evolves a lot and my conclusion could change in few months or years. The first article goal was to bring fundamentals around what are TypeScript and Flow.

This article will focus on high-level coding feature that differentiates TypeScript and Flow. The get differences, I had to sample a subset of all the feature and the reason is that both support a lot of them and I have limited time. How I decided these features was to go with Flow first by using their documentation. My plan was to convert one TypeScript project already written to Flow and while doing so, I added features that were used which resulted to the features comparison matrix of this article. The result is of the 40 features tested is:

  • 11 features lean on TypeScript
  • 4 features lean on Flow
  • 18 features that are neutrally equal
  • 1 feature that is subjective who is better

Let’s spread the 40 features in a table to illustrate these details and then talk about them.

Feature TypeScript Flow Winner?
Interface Yes Yes Both
Type (Alias) Yes Yes Both
Subtype Yes Yes Both
Implementation Yes Yes Both
Encapsulation (private, protected, public) Yes No TypeScript
Enum Yes No TypeScript
$key (utility type) No Yes Flow
$diff (utility type) No Yes Flow
* (utility type) No Yes Flow
Type Casting Yes Yes Both
DefinitionFile or Librairie Definition Yes Yes Both
Non standard JS Yes Yes Both
Get definition file NPM cli TypeScript
Readonly Yes No (see covariance) TypeScript
React props/states Yes Yes Both
maybe/optional parameter Yes Yes (separate null/undefined) Both
Optional properties Yes (same syntax) Yes (diff syntax) Both
Infer type Yes Yes Both
Contravariant Yes Yes Both
Covariance No (see readonly) Yes Flow
Abstract Yes No TypeScript
Decorator Yes No TypeScript
Quick initialization (by ctor params) Yes No TypeScript
Static Yes Not all scenarios TypeScript
Sealed Yes by default Yes by default Both
Unsealed Must cast Object defined by {} Both
Tuple Yes Yes Both
Soundness Not completely Yes ???
Type of typing Structural typing Nominally typing TS is following JS
Generic Class Yes Yes Both
Generic Interface Yes Yes Both
Generic Function Yes Yes Both
Generic Type Yes Yes Both

That’s a lot of information and at the same time, just a sample of what Flow and TypeScript can offer. I’ll try to cover the difference without focusing on the resemblances and more about what makes them apart.

Encapsulation

Encapsulation or “modifier” is the first difference. I’ll talk about the lack of private, public, protected keyword all at once. This level of protection doesn’t exist in JavaScript, but TypeScript allows it if interested, otherwise, it’s all open (public). TypeScript enforces it at the syntax level put the transpiled JavaScript doesn’t have any trace of the encapsulation notion. For example:

class MyClass {
    private privateMember: string;
    public publicMember: string;
    protected protectedMember: string;
    constructor(message: string) {
        this.privateMember = message;
        this.publicMember = "public";
        this.protectedMember = "protected";
    }
}


Transpile to:

var MyClass = (function () {
    function MyClass(message) {
        this.privateMember = message;
        this.publicMember = "public";
        this.protectedMember = "protected";
    }
    return MyClass;
}());

The encapsulation is not propagated in JavaScript, but could have been there with some closure. In all circumstances, Flow decided to not enforce the encapsulation at all. The repercussion is interesting. First, the code becomes harder to maintain because it allows people to access members directly. A common scenario is to inject by constructor some specific class that represent services. You want to control the integrity when the class is instantiated, but if the injected objects are public, they could be modified by anyone in the lifetime of the object. There is much other justification why having a stronger encapsulation is good which will be the subject of future articles.

Enum

Enum is a convenient way to organize potential value for a type. For example, with TypeScript you can write an enum that will hold a specific group of language the following way:

enum Language {
    English,
    French
}

This syntax allows to assign easily with a good Intellisense support, but also enforce passing only the value from the enum by parameter.

var myLanguage = Language.English;
functTakeOnlyLanguage(myLanguage);
function functTakeOnlyLanguage(param: Language){
    // ...
}

The notion of Enum doesn’t exist in Flow [2]. They have a workaround which more verbose [3] than the TypeScript keyword. Here is the same representation with Flow.

export const LANGUAGES_VALUE = {
    French: "French",
    English: "English"
};
export type Language = $Values&lt;typeof LANGUAGES_VALUE&gt;;

var myLanguage = LANGUAGES_VALUE.English;
functTakeOnlyLanguage(myLanguage);
function functTakeOnlyLanguage(param: Language){
    // ...
}

Using this type and constant with Flow require to have a special import when using.

import { LANGUAGES_VALUE } from "../general/Language";
import type { Language } from "../general/Language";

The Flow version requires a little more work since you need to define the const and then use a “magic utility type” to create a type, and after you need two imports which one is non-standard. The use of “magic” seems pejorative, but it’s how it is called. Also, it might be the configuration issue between my VsCode and Flow during my investigation, but the type of Language was “any”, hence the Intellisense wasn’t great. Overall, TypeScript have an edge here on a simple thing that makes developer life just a little easier.

Utility Type

Flow is having something TypeScript does not literally have called utility type [3] or magic utility type. We already saw the potential with Enum with the $keys one. TypeScript lets you do something similar with keyof.

Flow has also $Diff<a,b> which returns a type that is the difference between two types. There is also few others which are not all implemented. </a,b>

So, at first glance, it’s a pro and I marked it as well. However, the more I was thinking about it and the more I was wondering why Flow has these utility method. It should belong somewhere else than inside a type checker tool. These utility methods would dwell well in a Babel plugin, or in a library like lodash, or directly in TypeScript. I do not have the full context, but it seems that it was added to fulfill a need with React which is a close team Flow is working with.

Getting Definition Files

Getting definition files is different between TypeScript and Flow. The reason is that Flow doesn’t use the same definition file than TypeScript. There is no way to translate one to the other, and both persist their definition files in an independent repository. This creates fragmentation in the community that needs to create two kinds of definition file. As mentioned in the first part, TypeScript has above three thousand definition files while Flow has reached few week ago three hundred. Besides the number of libraries, the major difference is how to get the definition files. TypeScript has a long history of ways to do it. At the time I am writing this article, we are at the third iteration which seem to be stable and better in many ways. It’s now using NPM, a tool that every JavaScript developers have familiarity since it is the most common way to get library. It makes sense to have the definition file by the same way. Using NPM allows using the same syntax and configuration file (package.json). This is convenient to store data, but also convenient to get the definition file from a repository that you do not own. By installing with “npm install” you are getting all the libraries as well as all the definition files.

npm install --save-dev @types/redux

With Flow, getting library definition is not hard, but it’s not a paved way what we are used to ride on. It requires using a cli (command line)[4]. This cli is available from npm (npm install -g flow-typed) and from there, you can use flow-typed to get a library that will be installed into a flow-typed folder at the root of your project. One requirement is that you must specify a version.

flow-typed install redux@2.3.x

If you get a project and needs to get the library, you will need to use npm install but also flow-typed install. Since we need to handle the second tool, Flow doesn’t gain a point in that comparison. TypeScript matured into using NPM and that choice simplify the access to third party definition file.

Readonly

TypeScript has the keyword readonly. Flow does not. However, Flow has something similar which is the “+” sign for covariance. The goal is to do like in C# or another language which is to set a value directly in the class where we the field is declared or when in the constructor when the class is instantiated. At the end, the value cannot change. This allows having values that are set dynamically and only once.

Flow doesn’t have the keyword read only. It has the concept of covariance that TypeScript doesn’t have. To mimic this behavior, in Flow it requires having a “+” sign in front of the variable. The difference is small for a field but subtle. For example, it works well if you know the value and assigns it directly to the field of the class. However, if you want to assign it in the constructor, it won’t work in Flow. Let’s see some code:

class Person {
  +name: string;
  constructor(name: string) {
    this.name = name; // This doesn't work in Flow
  }
}

But the equivalence work in TypeScript:

class Person {
  readonly name: string;
  constructor(name: string) {
    this.name = name
  }
}

The case of read only is simpler with TypeScript and work like many other languages, hence seem to be slightly favorable for TypeScript.

Optional Parameter and Optional Field

Both have a different way to achieve optional value to be provided for parameter of a function or to have a field defined (in an interface for example). TypeScript use the question mark in both cases.

// Optional Field
interface IInterface{ propertyName?: string } //Allow null &amp;amp;amp;amp;amp; undefined

// Optional Parameter
function myFunc( param?: string ) //Allow null &amp;amp;amp;amp;amp; undefined

This is different from Flow which will not be that loose. With Flow, you can pass nothing (which is undefined) but cannot explicitly pass null for something optional.

// Optional Field
interface IInterface{ propertyName?: string } //Allow undefined

// Optional Parameter
function myFunc( param?: string ) //Allow undefined

If you want to pass null, you need to use the concept of “maybe” which is unique to Flow. The syntax is also with the question mark, but this time before the type.

// Optional Parameter
function myFunc( param: ?string ) //Allow null &amp;amp;amp;amp;amp; undefined

This goes in the sense that Flow is more “sound” than TypeScript. Flow has more control about what you want to pass. TypeScript is following JavaScript and is less strict in that matter. At the end, both sides can be pros or cons. TypeScript shines by having a single place to put the question mark and it’s always the same logic which is that it allows value, null and undefined. On the other hand, Flow has more option by being able to allow value an undefined as well as null if using the maybe type. However, the syntax is very similar to the other type of optional which can cause confusion. At the end, they have different pros and cons and I consider no winner.

Abstract

Abstract is available in TypeScript; it’s not in Flow. Abstract is an object oriented concept, and it wasn’t available 3 years and half ago when I started using TypeScript and it was a tool that I missed. Since about 2 years, it’s available and I used it few times. I do not want to explain why it can be useful or not in this comparison article, but it’s a concept that some kind of developers like while other doesn’t. TypeScript doesn’t force you to use it, and give you the ability to if you want. By giving the developer the choice instead of not providing it, TypeScript wins.

Decorator

TypeScript requires having a configuration flag to true in the tsconfig.json. Flow requires having a babel plugin. It needs a little more work, like getting the right package, but nothing significant. I started using the babel decorator, but was getting a warning message that conducted me to using the decorator-legacy.

From there, Flow was giving an error saying that this feature was experimental. Flow, at this time, doesn’t support decorator [5]. I ended up by having to ignore the EcmaScript proposal in the .flowconfig file. TypeScript won. However, if you are not using Angular2+ or MobX than you might do not mind. However, more and more libraries and frameworks use decorator which is nice to have some type checking as well.

Quick Initialization

I’ll be brief. Since Flow doesn’t have encapsulation than it’s obvious that quick initialization doesn’t exist in Flow. This feature allows to not declare inside a class the field and avoid having line of code to set the constructor’s argument to the field manually. This is handy and a recent addition to TypeScript. It’s clean up the code by still having a great encapsulation. TypeScript wins by default.

Statics

On this one, I wasn’t very thorough. I had code that was defining readonly static field in TypeScript and couldn’t have them static (without readonly) in Flow. So, I had to choose about having the value defined once or the field to be static. TypeScript acted more like I was used to see in Java or C#. Because of that, I’m giving a weak win to TypeScript.

Type of Typing

TypeScript is using a structural typing [6]. Flow is following nominally typing[7]. It means that for TypeScript, if you have two interfaces or classes with the same members but with a different name, hence are a different type, they are assignable. This is to mimic how JavaScript works. However, Flow is nominally typed which means that every class or interface defined is unique and cannot be assigned to another one even if they have the same members. I could elaborate more, but I suggest you read the TypeScript documentation about type compatibility. So who is winning? It’s a hard one. Flow wins if we want something more strict. TypeScript wins if we want not to invent a new language on top of JavaScript. To be noted is that, even if JavaScript doesn’t have keywords for encapsulation and abstraction, the language allow it with closures and other JavaScript tricks. So at the end, TypeScript seems to be the winner since it doesn’t try to change the nature of JavaScript, which Flow is doing…and maybe for the best? I guess that is debatable.

Conclusion

This part is getting long. I’ll end it here. In the first part, we saw some fundamental differences between TypeScript and Flow. In this second part, we saw that the two type checkers are pretty close in features. Even if I write about the differences, there were so many similarities that I got impressed and surprised. In the last and third part, I’ll take the time to show in terms of code the similarities and differences. Before closing this part two, if you are still hesitating on which one to use, you won’t find more answers in the third part. The next article will confirm the idea that both of them are pretty similar. I suggest that you read again the first part and this one to make your decision and read the third one only for your curiosity.

Parts of the serie:

References

[1] –
[2] https://github.com/facebook/flow/issues/627
[3] https://flow.org/en/docs/types/utilities/
[4] https://github.com/flowtype/flow-typed/blob/master/README.md
[5] https://github.com/facebook/flow/issues/3405
[6] https://www.typescriptlang.org/docs/handbook/type-compatibility.html
[7] https://flow.org/en/docs/types/classes/

TypeScript vs Flow (Part 1 of 3) – Who are they?

Most of the time, usually at the beginning of a project, some hard decisions need to be made. In the web development world, where JavaScript has the monopoly as a client-side language, the decision is less about the language, but more about the tooling and the libraries to use. However, in recent years JavaScript developers got the option to use language based on JavaScript to increase their productivity. TypeScript was born around 2010 and Microsoft initially released it to the public in October 2012. Facebook alternative named Flow was born two years after TypeScript, almost month to month. Both of them give some rigidity to JavaScript that can be loose in terms of how to write code. Indeed, JavaScript is getting better and better with new features and more support from browsers. That being said, the need to have type or not is a question that could raise lots of discussions. In this article, I will take for granted that the decision about using a typed language has been accepted and that the next step is to figure out which language/static type checker to use, between TypeScript or Flow.

First of all, like any person, I have some bias. I’ve been working in TypeScript since 2014, I never worked with Flow. This is why I did an investigation for two full days and took 30 pages of notes to see deeply the differences I’ll mention during this post, as well as the two upcoming ones when I add opinions instead of facts. Second, what I’m writing here is subject to change over time. The investigation I conducted was done on August 9 and August 10, 2017. It’s a domain where it evolves a lot and my conclusions could change in a few months or years. Third, I could have done an even more thorough investigation with more time. I limited myself to two days.

Concerning my conclusions, here they are; they are both very similar. TypeScript is a transpiler, hence does more. Flow needs Babel to be able to accomplish what TypeScript is Patrick Desjardins 132 doing. Concerning the type checking, they have different mentalities, but are still very similar except for the encapsulation and for the null/undefined validation. TypeScript has 10x the support for third parties, with a vast definition files ecosystem that is not the case for Flow. Now that you have my elevator speech conclusion of TypeScript vs Flow, here are the details.

Historical Background

Flow exists since 18 November 2014. TypeScript exists in public since 1 October 2012, but its inception started 2 years before as an internal product (2010). This information doesn’t give us much other than TypeScript went through more active days of finding bugs, and that Flow may have leverage on the pros and cons of the former. The amount of time between the two is still relatively small, which makes both of them still young.

Flow started at Facebook, TypeScript started at Microsoft. The motivation of Facebook was to create a system that is “sound”[1] while TypeScript is not totally as sound in respect to how JavaScript behaves[2]. Here is a quote from Microsoft TypeScript documentation:

In practice, this sort of error is rare, and allowing this enables many common JavaScript patterns

Microsoft goals and non-goals [17] are well defined. We can read:

Non-goal: Apply a sound or “provably correct” type system. Instead, strike a balance between correctness and productivity.

I’ll provide more examples of what it really means in the next two articles. For this overview, let’s just conclude that TypeScript is closer to JavaScript in some behavior, while Flow is closer to Java or C# by being more strict.

The idea of which one is better is subjective and I won’t go a lot deeper. As a former C# developer, I like the idea of a sound language. As a long-time JavaScript developer and previous PHP developer, I like to have more freedom and can get around how JavaScript handles some behaviors. TypeScript is in the middle, Flow is more on one side. At the end, both help developers in some way to be more protected than vanilla JavaScript. To me, they both win in that category and it wasn’t a criterion that had a significant enough impact to lean me one way or the other.

Definition Files

TypeScript, being the precursor of a superset of JavaScript, brought the notion of the definition file. Definition file allows having typed libraries written in JavaScript. Flow has the same concept, but in a different format, which makes them incompatible, and they never did a conversion to leverage the TypeScript collection. TypeScript started using 2 different ways to store the definition file and ended up storing them with NPM instead of relying on a custom tool. Facebook decided to go with a custom tool.

TypeScript has 3,429 [3] definition files and this doesn’t count a definition file bundled directly in an official JavaScript package. Flow has 302 [4]. Today, getting a definition file for JQuery-UI (250k downloads per month) or Redux-Thunk (1.7 million downloads per month) is not a problem with TypeScript, but it is unavailable with Flow. This is not a big problem if you are using libraries that Flow supports and is not a big deal if you do not need to have types for third parties. Flow could be used to check your own code without having Intellisense for code outside your project. Nevertheless, it is worth mentioning that TypeScript offers more in that aspect and may be more appealing for someone who enjoys having code completion and IntelliSense when coding for custom code as well as code written by someone else.

A small detail about definition files is that Microsoft offers a “pull request mechanism” [5] for a missing definition file as well as accepts a pull request on GitHub. Flow is also accepting a pull request from contributors outside Facebook, but I haven’t found a mechanism to request a library file to Facebook.

At the end, if you are choosing TypeScript you will have all your definition files under the common NPM directory node_module. With Flow, it will be under a folder named flowtyped. It is not a big difference and on balance doesn’t change anything. If I can bring up my personal point of view, I would say that I like that Microsoft went in the existing and wellknown tool NPM and went away from their initial design. Even if it took them three iterations to achieve that goal, it’s now in a place that JavaScript developers know, using a tool that is known and doesn’t depend on a homemade solution.

This had a big impact for me and the team. Being able to use a well-known tool like NPM to reach thousands of types gives us an edge to jump on third parties where we do not know by heart all signatures or potential members. It is something that we thought was a significant decider in our final decision. Again, all depends on your needs.

Open Source

Both projects are open source and hosted on Github. They differ in terms of the license, which is in Flow BSD-3, and in TypeScript is Apache2. I am not a license expert, but from what I know, both are fine. Patrick Desjardins 134 The main difference is the language used. While being open source is great, being able to understand the code is what makes open source greater.

The main point of being open source is to have access to the source code in case something is required to change. The point of being open source is also to get contributions outside the main organization, as well as having a transparent channel to bring in ideas and issues. TypeScript is ahead of Flow about all these particular points. TypeScript source code is easier to read by TypeScript developers because it’s written 100% in TypeScript. Flow is written in OCaml. We do not know exactly the lifespan of each of these products; technologies are changing fast, and both of them may stop being developed at some point. For huge software, this might be an argument in favor of TypeScript, since if in many years they need to do a fix in

TypeScript source code they will be able to do it more easily than having to go in OCaml code. However, this is a borderline case and most of the people won’t mind and that is fair. Still, I think it’s more a positive aspect than a negative one for TypeScript.

Let’s bring some metrics around both open source project.

  • Flow has 17 branches, TS has 317
  • Flow has 336 contributors, TS has 228 contributors
  • Flow has 74 release, TS has 48 release (2 months)
  • Flow last month active pull request: 13. TS last month pull request: 188 (July 2017)
  • Flow has 1 057 fork, TS has 3 600 fork
  • Flow has 12 925 stars, TS has 24 738 stars

That’s great, but what can we get from these numbers? I am not an expert on open source projects, but I can only see that there is more activity around TypeScript. The number of contributors and releases are in favor of Flow. That said, the number of contributors is significant only if they are all active. The number of releases is also subjective since TypeScript cadence is every two months, Flow looks to be faster. Does that mean it’s better or not?This is subjective since the balance between stability and new features is always at play. TypeScript has more forks and more starts than Flow. Again, what it really means is that people are more interested, hence follow the project more and maybe get the code. Does it mean TypeScript is better? I don’t think so. The metric that I was the most interested in is the number of pull requests. It’s a good indicator that features and bug fixes are coming in. Both Facebook and Microsoft have employees contributing to the code, but it’s still relevant. TypeScript has more than 10 times the number of features/fixes coming in than Flow.  So, on the open source aspect, TypeScript is one step ahead because of the language used to build it.

What about the future?

The future is hard to know. Microsoft is investing in TypeScript, Facebook is investing in Flow. What I like about TypeScript is that they have an open roadmap [6] available to consult. You can see what they have done and what they are planning to work on. Microsoft also has milestones [7] available in their GitHub account. Flow’s roadmap was not found at the time of this investigation, and no official delivery milestones [8] are available on GitHub. Microsoft has been developing languages since the beginning of the company with a good track record of having long support (10 years after active development). Even Silverlight got a life support by Microsoft up to 2021 [18]!

TypeScript is used by huge projects, and not only from Microsoft. Here is a quick list of companies using TypeScript.

  • Google
  • Slack
  • Asana
  • Ebay
  • Ubisoft
  • Ericsson
  • UpWork (a.k.a Elance)
  • Bloomberg
  • Lyft [19]

And it’s used by many projects too.

  • Angular
  • Slack
  • VsCode
  • Teams
  • VSTS
  • Office Web
  • Ionic
  • Blueprint
  • RxJs
  • ReDoc
  • Google TensorBoard
  • Tensorflow Playground
  • NativeScript

Finally, it’s praised by tools and frameworks as well.

  • Aurelia framework
  • Ember
  • Babylon.js
  • Laravel
  • MobX
  • ReSharper

But what does that mean and where is the information about Flow? I have to say that I had an easier time finding that list directly from the TypeScript website as well as some blog posts, which are easier to look up. Flow has the disadvantage of having a name that brings lots of noise in search engines. I did some searches but couldn’t find much and their website doesn’t have a list of partners or use cases. But, does having big names in terms of businesses and projects really matter? It does. First, as you can see, Microsoft has quite a few projects written in TypeScript (or that have been converted from JavaScript to TypeScript). You can see that Microsoft Office (Web), Microsoft Teams and VSTS are using TypeScript. These are applications developed by thousands of developers and used by millions of users. Microsoft won’t switch off easily — it would kill the productivity of many projects and won’t be helping Microsoft. For companies and projects outside Microsoft it means that other people had to make the same decision that you may have to make and they analyzed that TypeScript was the right choice. These projects are used also by a lot of people and the decision to go that way was well evaluated. When Google Angular team decided to go with TypeScript instead of Flow or plain JavaScript, they did their homework. It also means that one of these big companies could fork TypeScript and continue its support or development in the eventuality that Microsoft would change its mind.

The future cannot be guaranteed, but TypeScript is written in TypeScript. Visual Studio Code is written in TypeScript. Office (web) is using TypeScript. Microsoft’s new projects, like Microsoft Teams, are written in TypeScript, as well as are their direct competitor’s,who moved to TypeScript. Depending on your project, this should soothe some fears. It’s there in 2017, it will be there in a few years as well. I would like to add more in this section about Flow, but I have limited visibility about Facebook and their plan. It might be as good, but I cannot get anything. Feel free to contact me.

For the moment, concerning the future of TypeScript or Flow, it seems to me that Microsoft has a clearer vision and background of being enterprise solid with their languages.

Developers

In the same way as about language, here is a slight note about who is leading TypeScript. It’s managed by Anders Hejlsberg[9], creator of Turbo Pascal, Delphi, C# and now TypeScript. He graduated in the 80s, received many awards in his career and he is the person who committed the most on Github.

Flow commits are led by Marshall Roch [11] by twice the next biggest contributor, who was the second developer on Flow. I assume that he is in charge of Flow (I might be wrong). He has been for seven years at Facebook and graduated in 2009 from Carnegie Mellon University.

While this might not be a game changer, it’s also a point for TypeScript. The experience behind the lead of this project is a positive for TypeScript. Flow has the advantage to have fresh eyes on new technologies, hence still not bad. At the end, both projects are not driven by a single man, but by a group of people, and are simply influenced by the spirit that leaders project.

Integrations

Visual Studio Code is the prefered language for TypeScript, but they offer a variety of plugin for many IDE. TypeScript and Flow has the same kind of architecture that let external program to communicate with the “local server” to get analyzed for type check. Here is the list of supported IDE for TypeScript [11]:

  • alm.tools
  • Atom
  • CATS
  • Eclipse
  • Emacs
  • NeoVim
  • NetBeans
  • Notepad++
  • Sublime Text
  • Vim
  • Visual Studio
  • Visual Studio Code (VSCode)
  • WebStorm

Here is the list of supported IDE for Flow [12]:

  • Visual Studio Code (VSCode)
  • Atom
  • Nuclide
  • Sublime Text
  • Vim
  • Emacs
  • WebStorm

Beyond the support of IDE, there is the experience of the type checker within the IDE. During this comparison, I used the editor that I use to work on a variety of languages, which is Visual Studio Code (VsCode). The integration with TypeScript is seamless. The integration with Flow requires an extension. This is how VSCode works (1 plugin per language) and it installed flawlessly as well. When starting to convert, I added a comment at the top of each JavaScript file to have Flow catching up on verification. I noticed that when fixing issues, it could take from two to five seconds to have the error getting away from the editor. Flow confirms [13] that VsCode lacks the on-the-fly linting and validates only on save, which is also a limitation on the Nuclide [14] editor that Facebook built.

Both languages have a suggestion when importing custom type which simplifies the writing of the import. However, Visual Studio Code allows with TypeScript to write the code and detect the missing type and auto-suggests which import to bring at the top of the file for you. This is a neat feature that wasn’t triggering while writing with Flow. This might be a limitation of the VsCode plugin.

Again, this might not be a big deal, but if you love one IDE that is not on the list of either Flow or TypeScript, it can become one. Being used to having TypeScript jumping to help me right when I type is also something I was missing with Flow in VsCode. TypeScript covers more IDE, but both are pretty similar in terms of the most popular ones in web development these days. If I had to declare a winner, I would say TypeScript, but with a marginal gain since it supports more IDE. It wasn’t a decisive point for me or the team since the IDE we use were covered.

Support

What about when you have a problem and you need an answer? This will happen and it’s interesting to see what both are offering. Most of the developers will use StackOverflow to write a question to get an answer or will search the Internet and stumble at StackOverflow. If we look at StackOverflow we can see that Flow has 783 questions and TypeScript has 34,613 questions. TypeScript is more active, but we have to put in perspective that people are asking questions about TypeScript the type checker, as well as TypeScript the transpiler. It would be fairer to say that Babel + Flow count would be more comparable. I’ll come back about TypeScript being more than just a type checker in an instant.

About the potential code on the Internet, there are fewer examples in Flow. For example, the well-known TodoMvc has an example with TypeScript and React, TypeScript and Angular, TypeScript and Backbone, but none with Flow.

The official documentation is detailed in both official websites. Very clear, with examples, and both offer an interactive online console where you can drop code and test it.

At the end, TypeScript has a slight advantage. It might be because I was hitting lots of garbage while trying to search “flow” + my keywords but even with “Facebook flow” or “flow js” it wasn’t getting better. I barely found any small projects or websites with good examples with Flow. I found more with TypeScript. However, in both cases, JavaScript’s examples are way higher than the two type checkers we are evaluating.

Beyond Type Checking

During my evaluation of TypeScript vs Flow, rapidly I had to admit that a major difference between the two is that one is doing more than the other. TypeScript is not just a type checker, it’s a transpiler. Flow is a type checker, that’s it.

What is the advantage of Flow? The advantage is that you can use whatever you want for transpiling. To be honest, it means that you will need BabelJs. BabelJs has the advantage against TypeScript that you can cherry-pick plugins and presets you want. TypeScript allows you to enable and disable features, but you are limited to the features they release. At the end, BabelJs is very popular and gives more flexibility. TypeScript is simpler to install and compatibility (or configuration) is a breeze.

I migrated one of my small projects, which is a React project. Here is the TypeScript configuration followed by the BabelJs and Flow configuration.

// tsconfig.json
{
"compilerOptions": {
"target": "es6",
"module": "amd",
"outDir": "./deploy/output",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"jsx": "react"
},
"include": [
"app/scripts/**/*"
]
}

// NPM packages required
"typescript": "^2.3.2"
[/javascript]
Flow and BabelJs:


//.flowconfig
[ignore]
.*/node_moduless/*.*
.*/deploy/*.*
.*/lib/*.*

[include]
.*/app/scripts

[libs]

[lints]

[options]
esproposal.decorators=ignore
esproposal.class_static_fields=ignore
esproposal.class_instance_fields=ignore

//.babelrc
{
"presets": [
"env",
"stage-0",
"react",
"es2015",
"flow"
],
"plugins": [
[
"flow-runtime",
{
"assert": true,
"annotate": true
}
],
"transform-flow-strip-types",
"transform-es2015-arrow-functions",
"Transform-decorators-legacy",
"transform-class-properties"
]
}

// NPM packages required
"flow-bin": "^0.52.0",
"flow-runtime": "^0.14.0",
"babel-cli": "^6.24.1",
"babel-core": "^6.25.0",
"babel-plugin-flow-runtime": "^0.11.1",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-decorators": "^6.24.1",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-es2015-arrow-functions": "^6.22.0",
"babel-plugin-transform-flow-strip-types": "^6.22.0",
"babel-preset-env": "^1.6.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.24.1"

It has more boilerplate. TypeScript offers stage 2 and up feature from EcmaScript because their philosophy is to have all released feature backward compatible (which is true since version 1.0). Earlier stage EcmaScript features are more prone to die or change signatures. With Babel, you can decide which stage you want to subscribe. This freedom has a cost. TypeScript brings simplicity at the cost of a being a less cutting edge. But what does it really mean at the end? If we look at all EcmaScript 2016 features, Babel is supporting 40% of them, TypeScript 36%. At the end, it’s only 2 features different.

It’s also interesting to note that BabelJs may support features that Flow doesn’t. This doesn’t occur with TypeScript since they are in symbios. For example, Flow doesn’t support decorator [16], but BabelJs and TypeScript does.

Conclusion

This is part one of three where we put on the table some differences between TypeScript and Flow. If you are reading this article because you are hesitating between the two, stay tuned for the remaining which will be a high and low-level comparison of each of the type checkers. If you are here because you are looking to know if you want typed language vs non-typed language for web development, I would suggest that you consult other sources of data. If you are in some discussions at work about JavaScript vs TypeScript or Flow, I would suggest first deciding between typed or not before jumping on the subject of TypeScript vs Flow. At the end, the goal is not to be a fanboy (fangirl) but to have the best tool that will help you and your team to be productive.

In this article, I illustrated the main difference of TypeScript being more than just a type checker which is a big difference compared to Flow. We also highlighted that the ecosystem around TypeScript is richer with more definition files for third parties. I illustrated that Patrick Desjardins 142 configuring TypeScript is simpler, but that Flow is more configurable. I also briefly mentioned that both solutions have many solutions in terms of IDE. Indeed, after reading only one article of many, it seems that I am leaning more on TypeScript. I would say that the major arguments in the decision about TypeScript or Flow are in fact in that article. The next two articles will bring detail about comparing how both achieve almost the same thing with a very minor difference in terms of features or syntax. At the end, what will matter the most in the choice is the point I brought up here

Parts of the serie:

References

[1] https://discuss.reactjs.org/t/if-typescript-is-so-great-how-come-all-notable-reactjs-projects-use-babel/4887
[2] https://www.typescriptlang.org/docs/handbook/type-compatibility.html
[3] https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types
[4] https://github.com/flowtype/flow-typed/tree/master/definitions/npm
[5] https://github.com/DefinitelyTyped/DefinitelyTyped/labels/Definition%3ARequest
[6] https://github.com/Microsoft/TypeScript/wiki/Roadmap
[7] https://github.com/Microsoft/TypeScript/milestones
[8] https://github.com/facebook/flow/milestones
[9] https://en.wikipedia.org/wiki/Anders_Hejlsberg
[10] https://www.linkedin.com/in/mroch/
[11] https://github.com/Microsoft/TypeScript/wiki/TypeScript-Editor-Support
[12] https://flow.org/en/docs/editors/
[13] https://flow.org/en/docs/editors/vscode/
[14] https://nuclid1e.io/
[15] http://kangax.github.io/compat-table/es2016plus/
[16] https://github.com/facebook/flow/issues/3405
[17] https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals
[18] https://support.microsoft.com/en-us/lifecycle/search?alpha=silver
[19] https://eng.lyft.com/typescript-at-lyft-64f0702346ea

Pros and Cons of Using TypeScript

It’s been 3 years that I’ve been using TypeScript daily. From what I recall, it wasn’t yet in version 1, abstract classes were not supported and tsconfig.json file was not there as well. A lot has changed in these 3 years and every two months new features make the language better and better. I recently took some personal time to write two video courses on the subject to demonstrate how great is TypeScript.

However, from someone new to TypeScript and used to JavaScript, it might not sound that great. This is why I compiled a list of pros and cons of TypeScript to help you decide if you should or not use TypeScript.

If you need to debate about TypeScript or JavaScript, you should tackle the problem by first attacking the idea of typed language versus dynamic. This is the biggest battle. Typed language helps on a bigger scale or in a situation where people jump from one project to another. It also helps if you have new people coming in a project to understand faster what needs to be what. It also brings a potential error to the developer by having the code editor raising an error while developing which means less error at run-time. There are countless arguments in favor of strongly typed code. While losing the possibility to dynamically add properties on the fly, you win on having a well-established contract that can be extended if required. Dynamic type brings more drawback in the long term where people can add a property that could change the whole workflow without knowing it while writing type. Strongly typed code auto-document your code by mentioning what is expecting. It also reduces your number of unit tests by not having to check type for each parameter for example.

Here is a list of pros and cons.

Pros

This is a list of pros with some descriptions about why it’s a pro.

Combine Three Tools

If you are using plain JavaScript, you are mostly also using Babel. The main goal of babel is to transpile an advanced version of ECMAScript into a version that is well supported by browsers. TypeScript is also doing it while transpiling TypeScript into JavaScript. You need to specify which version of ECMAScript you want the outputted JavaScript to be and it will be done.

If you are using Flow to have typing capability, then you do not need it anymore with TypeScript. It has a strong preference for types. The newest version allows to slack on the strongly typed feature and bring inference as well. Hence, TypeScript can be configured the way your team wants and get the benefit of using the right type of data at the right place.

If you are using React and PropTypes than Flow or TypeScript do the job of enforcing the property types, hence no need to have this other library.

Here is a trend graph of the last year of TypeScript vs Babel under the category programming:

Used by Big Companies

This might not be the strongest argument, but it shows that companies trust the product enough to invest millions of dollars into building with TypeScript.

  • Microsoft
  • Google
  • Slack
  • Asana
  • Ebay
  • Ubisoft
  • Ericsson
  • UpWork (a.k.a Elance)
  • Bloomberg

There is also a list of product that you may know that are made or partially made with TypeScript:

  • Angular
  • Slack
  • VsCode
  • Teams
  • VSTS
  • Office Web
  • Ionic
  • Blueprint
  • RxJs
  • ReDoc
  • Google TensorBoard
  • Tensorflow Playground
  • NativeScript

And here are few frameworks/tools that praise about how great it TypeScript.

  • Aurelia framework
  • Ember Babylon.js
  • Laravel
  • MobX
  • ReSharper

Again, this is more a pro than a con, while not being the ultimate argument. It’s just reinforcing that big project benefit of strongly typed system.

Future Features Now

Polyfill is the capability to bring future features in the syntax that developers can use today even if not implemented by the browser or yet implemented by ECMAScript. It creates a workaround with the existing code. This is not unique to TypeScript and BabelJs is a very popular alternative. TypeScript shines by the fact that it does more than BabelJs. However, you will see that is also a cons since TypeScript have polyfill for stage 3 features of ECMAScript specification while BabelJs implement them earlier.

Work with Older Browser

TypeScript allows you to target a specific version of ECMAScript. It means you can target a version that will produce compatible JavaScript for Internet Explorer 11 if you need. If you don’t need, you can produce ECMAScript for the latest version of Chrome and be more efficient in performance.

Static Typing

This is the most important and strong argument to go with TypeScript — it allows to have types. Types can be optional and can be inferred if not explicitly defined.

TypeScript verifies your code on the fly while typing if you are using an IDE that supports TypeScript. This brings a very quick feedback loop to fix errors. Instead of waiting to go in the browser and hit the specific line of code that might be problematic, TypeScript while typing the code let you know that there is an issue.

Static types self-documents the code. Have you ever see a variable “options” as a parameter? What option is available is often obfuscated deep in the code and could be also just used once somewhere no obvious. With typing, the variable “options” will be of a specific type or defined with an interface, hence having a set of possible properties.

Static types reduce the number of errors. If you are using a function that expects a variable, and you send a callback function with 2 parameters in JavaScript, it will just run and maybe or not crash if you passed the wrong callback parameter or even if you thought it was a callback while it was just a value. With TypeScript, while typing the name of the function you would have seen the possible arguments as well as what parameters the callback needs. It won’t have let you try something else without warning you.

Having a contract defined remove some hacks in the code. The code is enforced to be in a predicted state which is the one defined by the definition type.

Finally, having type helps new people coming into a project. They do not need to know the whole system to understand a piece of it. Types help them dig into the specific class or interface they need to be aware of, while they can ignore the rest. It also helps people switching from a project. If you are working for 3 months on something, move to something else for few weeks and come back, it’s way easier to remember that in that project this class is having these properties and this interfaces than having nothing at all.

Type Inference

This is a relatively new feature that was a big plus of Flow compared to TypeScript. In Flow, the philosophy is that you do not have to define all your types. In TypeScript, you had to do it otherwise it was “any” which is anything. However, since TypeScript 2.1, TypeScript will infer the right type. It means that if you assign a variable a number that this variable will be a number.

let x = 1; // x is a number, not var

This is an advantage for people who do not like the heaviness of typing the type every time and still give good support and validation. It means that it’s impossible to assign x to a string from that point of time.

let x = 1; x = "string here"; // Won't compile since x is inferred as a number

It brings more security and less problematic in code that can be trickier. For example, if you take numbers and return the sum of them. Do you expect to return a number of a string (concatenated value of the number). Well, if your method returns a number (explicitly) it won’t compile if one of the parameters passed is a string and that we implicitly wanted a number. Indeed, we could have defined numbers everywhere and remove all the confusion, to begin with.

Inference work as well with a literal object. If you defined an object and assign a value of an integer, the type will be inferred as a number. It means that if you assign to that object’s property a string that it will be caught up by Typescript.

let myObject = { a : 1 }; myObject.a = "string"; // TypeScript will catch the inferred type that the property is of type number

TypeScript spreads inference to arrays as well.

IntelliSense

Many editors support TypeScript and provide code completion. IntelliSense increases developers discoverability, bring the JSDoc if defined when typing, inform which parameters can be used as well as overloaded possibility. It reduces potential typos, removes the need to go on the Internet to figure out what properties and functions are available on an object. It increases every developer by enhancing their typing experience which is what a developer does most days.

Avoid Common Errors

JavaScript has common pitfalls that are still very frequent amongst web developer. One of this one is what “this” refers to. With TypeScript, you do not have an issue with “this” since TypeScript figure out for you what it means. If it’s “window” than when typing “this.” you will see only “window” stuff. If it is referencing the class, you would see the class members. Same thing with variable scopes. With TypeScript, you know exactly if the variable was defined if you are reaching the one you expect hence remove scoping issues.

Real-Time Feedback

All problems with JavaScript are discovered at runtime. The problem with runtime discovery is that you must hit the line of code which may be in a web page very deep under a specific button that is rarely pressed. Still, there is an error hiding there. Going to that page might require several clicks and at the end, you may do a quick modification and not be aware of a change. With TypeScript, while you are typing you are getting feedback. When you are transpiling you are getting feedback and finally, when executing your JavaScript in the browser you can see the error. With TypeScript, you are getting way more feedback from real-time to compilation time to execution time!

Low Entry Barriers

Coming from JavaScript to TypeScript is a matter of hours. I did the jump after many years of being a JavaScript developer and within a full week of work I was already embracing the change. It will be annoying for few hours to have to type more to specify the type, but after few functions, classes, sharing code with teammates you will soon realize that it is worth the few more keystroke required.

It’s a low barrier because it’s not a new language. TypeScript is a superset of JavaScript. It means that it uses the official EcmaScript syntax, functionalities, primitive types, documentation style, and same libraries. You are used to use “MomentJs” you can. You know by heart all array functions, well it’s the same in TypeScript. You do not like the class, but rather to function only, you can!

IDE Integration

There is more and more integration. One of the most popular choices is Microsoft Visual Studio Code, but the list is way bigger than this tool. Take a look and there is probably your tool of choice. If not, you can still use anything else, it’s just that TypeScript won’t be active while typing, only while transpiling. That said, it’s possible to create your own plugin for the editor you use.

  • VsCode
  • Sublime
  • Atom
  • Eclipse
  • VIM
  • Netbeans
  • Visual Studio 2013+
  • WebStorm
  • Emac
  • IntelliJ

Third Most Loved Language in 2017

This one is as well not a very strong argument but put in perspective how TypeScript is perceived. The result is from Stack Overflow 2017 survey. Position 1 was Rust and position 2 was Smalltalk. JavaScript was 11. This is a survey and like all of them not perfect. But it shows that it is not hated, hence give some idea that if you go that way that it might be easier to recruit people to work on your application.

TypeScript vs Dart vs CoffeeScript

Again, this is just to give a perspective against some other alternative. Dart and CoffeeScript tried to help developers by compensating the lack of JavaScript. However, these two requires learning a new language while TypeScript is a superset of JavaScript (extend JavaScript).

On the last 5 years graph, you can see the blue line is TypeScript, the red one is CoffeeScript and the yellow one is Dart.

Compatible with all JavaScript libraries

TypeScript doesn’t have a Microsoft repository of libraries for JavaScript like Nuget. While you can find some JavaScript library in that system, the main source is NPM. TypeScript has two way to support JavaScript libraries. The best option which is often (if not always) available is to use definition file (d.ts) which bring only the signature of the public interface of a library. It is integrated into NPM and let you have all the consumption benefit of TypeScript code from JavaScript. In the situation that you are using a JavaScript that doesn’t have a definition file, which occurs for less popular libraries, you can still use them but won’t get the typing information. Hence, you will be at the same level that if you were not using TypeScript.

Hybrid Mode with JavaScript and Portability

This is mostly new for TypeScript. It can now analyze JavaScript file since 1.8 by looking up .js file instead of just .ts file. In version 2.3, TypeScript can run on JavaScript file and get IntelliSense and some basic inferred type support. This allows converting a JavaScript project easily since you can bring TypeScript without having to rename all the files and without having to bring any TypeScript types, interfaces or other concepts. Once you migrate everything to TypeScript, you can swap the extension file and convert all “any” to a strong type. I’ll write a more thorough guide about migrating in a near future.

Remove some JSDoc

I like writing JSDoc, but some people don’t. TypeScript allows you to not put as much comment since your parameters are already more documented by the type. For example, if you have a create(user) you may want to explain what is a user in JavaScript. In contrast, in TypeScript you would have create(user:Person):boolean, which is self-explanatory that we need a user of type Person and if successfully created that “true” is expected.

But, in the case you like to comment, you still can and it doesn’t need a custom TypeScript comment way to do it. It just uses the popular JSDoc convention. Nothing new and TypeScript leverage your code comment by bringing it with IntelliSense.

Open Source

It’s written by Microsoft, but the main repository is open source. You have the best of both worlds. A project backed by people working full time that takes contribution over the world. In the worse scenario that Microsoft pull the plug, the community (which is active) can take over. At the moment, there is release every month and more than 25 people outside Microsoft contribute in average on each release.

Living Project

Not only it is open source, it is very active. A new version every month. More than 18 000 commits, with 47 official released version.

Refactoring Tools

This depend on the IDE you are using, but since TypeScript brings types, it’s easier to find refactoring tool. Renaming a class or function is a breath since it will affect only the right one.

Reduce the Amount of Unit Tests

Without TypeScript, more unit tests are required to be sure that we check for a specific type. For example, you are writing a function that takes an array. In TypeScript, you do not need to check if it’s an array of integer because TypeScript enforces it for you. However, in JavaScript, you will need to do a check to see if it’s an array, and then to check if the array contains all numbers. These checks will need to be unit tested.

Future Proof

If TypeScript die, you can always use the generated JavaScript. At this time, generating in EcmaScript 6 produce a very understandable JavaScript. Also, TypeScript has been built in a Microsoft’s fashion in term of compatibility. They have in mind to always (finger crossed) be backward compatible which is true since version 1.0.

Nothing Proprietary

Microsoft didn’t reinvent the wheel. As mentioned earlier, it uses NPM and follows EcmaScript. It doesn’t use any proprietary tool, technology or language. This is not Silverlight, Nuget or XAML.

Leaded by Experimented Engineer

TypeScript is lead by Anders Hejlsberg. He is the creator of Turbo Pascal, Delphi, C# and now TypeScript. Lots of experience behind creating language. This might not be a very appealing argument, but it’s still more appealing to know it is lead by someone who has experience about what is good and wrong in language.

Linter Compatible

TypeScript as a TsLint plugin for many IDE and can run normal linter with the normal JavaScript rules. No need to learn something new. It’s using what everybody know.

Debugging Capability and Options

You can debug your Typescript directly. Or, you can debug the generated JavaScript. You can do it directly in your browser, or you can do it in your IDE. As you can see, TypeScript doesn’t limit you and you can embrace the way you prefer to debug the code.

Easier with Merge Conflict

You are merging and getting conflict, you fix them all and that’s it. What happens if you had bad merge? Hard to know until execution. With TypeScript, you open the IDE and see right away what went wrong. A missing variable, a duplicated line, a missing brace, a function that returns something wrong, etc. You can fix them all before compiling, Lintin or executing the code in the browser. Again, smaller loop to feedback which makes big merges way easier to fix with confidence that nothing is breaking.

React Compatible

The extension won’t be JSX, but TSX. Other than that, TypeScript will build like Babe would do JavaScript. Definition files for React are up-to-date and Microsoft is using TypeScript and React internally so they have the interest to have the definition files always at the latest version.

Create-React Option for TypeScript

There are two versions at this moment. One maintained by Microsoft and one by an independant person. This is great since it is often used to bootstrap project. You are not left alone with TypeScript and have all the advantage the main project is having since the TypeScript version use the main create-react underneath.

Merge Conflicts

Merge conflict are simplified. Once you are done merging, you can see right away if something won’t compile in TypeScript. You have the IDE highlighting all potential errors and the TypeScript transpiler not letting you generate the JavaScript. Surprisingly, this happens quite often while merging and missing a curly brace.

Cons

TypeScript is not perfect and has also some cons. In my perspective, the pros overweight the cons and feel free to comment if I am missing any cons that I do not see.

Compilation Time

This is a con since you must transpile your TypeScript into JavaScript. It takes some time. However, most JavaScript project use Babel to transpile from one version of EcmaScript to another. It means that that the cons is only one if you are using vanilla JavaScript without any transformation. There is some way to improve the transpilation time by just compiling specific folders or by just compiling specific files. Also, it’s possible to divide a huge application into several pieces where one piece can rely on the definition file generated by the other area. This latest suggestion allows compiling a big chunk of code that doesn’t change often and have the other piece of code to use the generated JavaScript with the definition file. Only the piece that the developers are working on can be compiled. It’s a little bit messier to setup, but still a viable approach.

Babel as more Feature than TypeScript

TypeScript will be behind Babel as far as feature completeness goes because features need to be built by Microsoft. This is almost not a cons because Babel must also implement the polyfill too.

How cutting edge we need to be is also questionable here. Babel is having 40% of ES2016, TypeScript 36%, not a huge difference since it’s only 2 features. TypeScript rule is to only have polyfill for stage 3 and above, Babel brings earlier stage. The justification of Microsoft is that they want to always be compatible from version to version and some early stage feature could be dropped or changed.

Less flexible and Less Dynamic

Less flexible than JavaScript. Type for example constraint what can be passed by argument. This is seen as a con by many hardcore JavaScript developers, however, we saw with PHP that being too flexible leads to some disaster. While some dynamic type can have in specific scenario some great strength, in most cases it causes chaos and maintainability. Still worth mentioning that TypeScript can be less flexible if “no any” is enforced.

Definition Files Required and not Up-to-date

Some libraries may not have up-to-date definition files or not a definition at all. This can be annoying, but it doesn’t block you to use those libraries. It will just not have great IntelliSense or you may have to use “any” which would be the case without TypeScript.

Less Examples of Code

For me, this is the biggest drawback of TypeScript. There are obviously fewer examples written in TypeScript than in JavaScript. It’s not that hard to create a mental mapping between the two since they look alike, but sometimes a simple copy-and-paste is just not possible. It can be annoying. With experience, you can copy-and-paste the JavaScript and convert it to TypeScript rapidly, but still annoying.

Less Support

If you have an issue in JavaScript you will get way more people jumping in to help you. TypeScript is a subset of JavaScript in term of developer that use it. It means that most TypeScript developers would be able to answer questions about JavaScript, but the other way around might not be true. It’s becoming more and more popular, so it’s not impossible to get support, but JavaScript beats TypeScript.

I realize that the list is getting quite big. I encourage anyone to start a small project in TypeScript and see the benefits by themselves.

NodeJs and MongoDb on Windows : Connecting and Inserting

MongoDb is an interesting choice of permanent persistence when using NodeJs since it stores document which is ideal of JSON document to get stored.

You can download a free version directly on MongoD : https://www.mongodb.com/download-center#community
Once it’s downloaded, it’s best to be sure that the system environment variable is set to have an entry in the path to point to the bin folder of the installation path of MongoDb.

Before working out MongoDb with NodeJs, I recommend to download RoboMongo for free: https://robomongo.org/download. This tool allows to query MongoDb and explore the data. Before using RoboMongo or to use the MongoDb library, we need to run the MongoDb server. To do so, go in the development folder you are working and execute the mongod command with the dbpath. For example, the following command will store the MongoDb in the “data” folder in the development folder.

mongod --dbpath=.\data

Inside your NodeJs project, you needs sto have the mongodb library. If you are using TypeScript, you can get the type definition too.

npm install mongodb --save
npm install @types/mongodb --save-dev

At this point, you can start using the library to access the information. First step, connecting to the server. Second step, connecting to the collection. The first step is the same as any other database, the second one is just that every documents are stored into a collection. Think about it as a table.

From here, we need to import some classes.

import { MongoClient, MongoError, Db, InsertOneWriteOpResult } from "mongodb";

MongoClient is the main class to connect to Mongo. MongoError is the class that wrap the error which we will use to get information about the connection’s error. Db is the class that hold information about MongoDb once connected. We need it to properly close the connection, but also to select the collection in which we want to invoke the action (find, insert, delete). The InsertOneWriteOpResult is the result on an insert.

Here is the connection code:

MongoClient.connect(url, (errMongo: MongoError, db: Db) => {
    if (errMongo) {
        console.log(errMongo);
    } else {
        console.log("Connected successfully to server");
    }
});

To insert something in you need to get the collection name and use the insert method. Something I haven’t yet figure out perfectly is how to handle Date from a .json file. In my case, I was opening file (.json) and inserting them into MongoDb. The Json parse method was returning the date as string, hence I needed to assign the value back with an instance of date


// To have a real date format in MongoDb
objToInsert.fullDate = new Date(objToInsert.fullDate);

// Access the collection we want to insert
const collection = db.collection("documents"); // "documents" can be anything you want your collection to be named

// Insert with a callback that has an error or the result data
collection.insert(objToInsert, (err: MongoError, result: InsertOneWriteOpResult) => {

});

The code above will add a new entry and alter the object to add an “_id” with a GUID for the object. This way, every entry has a unique identifier automatically.

TypeScript Boolean Function can Return Undefined

As much as I like TypeScript, it sometime inherits of the bad side of JavaScript. In this article, I’ll demonstrate a common example that cause problem. It goes in the line of what I wrote a year ago about the difference between NULL or undefined. While it’s always better to check for === undefined, lot of people keep having the habit of just checking the value with &&.

Before getting into the core of the issue. Let’s be on the same page. The following code compiles.

function test1(): boolean{
    return undefined;
}
alert(test1());

It doesn’t look like it compiles, but it does. Which mean that the following code also compile and return undefined as well.

function test2(): boolean{
    return true && undefined;
}
alert(test2());

But you will say that you will never explicitly write “undefined” in an && condition. However, people write:

function test3(myObject:any): boolean { 
    return myObject && myObject.prop && myObject.prop.isOkay;
}
alert(test3());

The alert in that case will be undefined if the “prop” is not defined or if the “myObject” is not defined. It won’t be false.

There is two ways to solve that issue. The first one is the proper way, but longer way to write which is to check against what we are really evaluating — undefined.

function test4(myObject:any): boolean { 
    return myObject !== undefined && myObject.prop !== undefined && myObject.prop.isOkay;
}
alert(test4());

This is the most explicit and clear way to have exactly the result expected. It returns true or it returns false; it cannot return undefined.

A more succinct way to write this validation is to use the double bang (!!).

function test5(myObject:any): boolean { 
    return !!myObject && !!myObject.prop && myObject.prop.isOkay;
}
alert(test5());

This latest will also evaluate for null as well as undefined and also true/false.

At the end, you should always avoid to simply rely that an undefined value will return false in a chain of condition. JavaScript return the last value that is not true in the chain, which we saw that can be undefined. TypeScript is not smart enough to catch this possibility and will let the function returning undefined instead of a boolean.

Resizing an Image with NodeJs

This is the second post about project of creating a search tool for local pictures. As mentioned in the first post, this tool needs to use a web service to get information about the picture. This mean we need to upload the image that Microsoft Cognitive Vision/Face service will analyze and return a JSON object with information about the picture. Like most service, there is some constraints in term of the minimum and maximum of the size of what you can upload. Also, even for us, we do not want to send a 25 megs picture when it is not necessary. This article discuss about how to resize picture before sending a request to the web service. This will not only allow to be withing the range of the acceptable values, but also speed up the upload.

I decide to take the arbitrary value of sending picture with the widest side of 640px. This produce in average a file 30kb which is tiny but still enough for the cognitive service to give very good result. This value may not be good if you are building something similar where people are far or if you are not using portrait pictures. In my case, the main subjects are always close range, hence very easy to get detail at that small resolution.

Resizing a file requires to use a third-party library. This is something easy to find with JavaScript and NPM has a library named “Sharp” that do it perfectly. The TypeScript definition file is also available, so we are in business!

npm install --save sharp
npm install --save-dev @types/sharp

Before anything, even if this project is for myself, I defined some configuration variables. Some rigor is required when it’s cheap to do! The three first constant is the maximum size we want to output the image. I choose 640 pixel. The directory name is the constant of the folder where we will save the image we will send and where we will late save the JSON file with the analysed data. We save the resized image because on the website later, we will use this small image instead of the full resolution image. The website will be snappy and since we have the file, why not using this optimization for free. At 30kb for 2000 images, we only use 58 megs. The last constant is the glob pattern to get all underscore JPEG pictures. We will talk about glob very soon.

const maxSize = 640;
const directoryName = "metainfo";
const pathImagesDirectory = path.join(imagesDirectory, "**/_*.+(jpg|JPG)");

The second pre-task is to find the images to resize. Again, this will require a third-party library to simplify our life. We could recursively navigate folders, but it would be nicer to have a singe glob pattern that handle it.

npm install --save glob
npm install --save-dev @types/glob

From there, we need to import the module. We will bring the path and fs module of NodeJs to be able to create proper path syntax and to save file on disk.

import * as g from "glob";
import * as path from "path";
import * as sharp from "sharp";
import * as fs from "fs";

The first function that we need to create is the one that return a list of string that represent the file to resize. This will be all our underscore aka best pictures. We want to be sure that we can re-run this function multiple times, thus we need to ignore the output folder where we will save resized images. This function returns the list in a promise fashion because the glob library is asynchronous. Here is the first version which call the module function “Glob” and add everything into an array while sending in the console the file for debugging purpose.

function getImageToAnalyze(): Promise<string[]> {
    const fullPathFiles: string[] = [];
    const promise = new Promise<string[]>((resolve, reject) => {
        const glob = new g.Glob(pathImagesDirectory, { ignore: "**/" + directoryName + "/**" } as g.IOptions, (err: Error, matches: string[]) => {
            matches.forEach((file: string) => {
                console.log(file);
                fullPathFiles.push(file);
            });
            resolve(fullPathFiles);
        });
    });
    return promise;
}

This can be simplified by just returning the matches string array and returning the promise instead of using a variable. At the end, if you are not debugging you can use :

function getImageToAnalyze(): Promise<string[]> {
    return new Promise<string[]>((resolve, reject) => {
        const glob = new g.Glob(pathImagesDirectory, { ignore: "**/" + directoryName + "/**" } as g.IOptions, (err: Error, matches: string[]) => {
            resolve(matches);
        });
    });
}

As mentioned, the quality of this code is average. In reality, some loves are missing around the error scenario. Right now, if something is wrong, the rejection promise bubble up.

At this point, we can call the method with :

console.log("Step 1 : Getting images to analyze " + pathImagesDirectory);
getImageToAnalyze()
    .then((fullPathFiles: string[]) => {
        console.log("Step 2 : Resize " + fullPathFiles.length + " files");
        return resize(fullPathFiles);
    })

The code inside the “then” is the one executed if the promise is resolved successfully. It will start resizing the list of pictures and pass this list into the function that we will create in an instant.

The resize function is not the one that will do the resize. It will call the function that does the resize only if the picture has not been yet resized. This is great if something happen to fail and you need to re-run. The resize function will check in the “metainfo” folder, where we output the resized picture and only resize this one if not present. In both case, this function return a promise. The type of the promise is a list of IImage.

export interface IImage {
    thumbnailPath: string;
    originalFullPathImage: string;
}

This type allows to have the detail about the full path of the thumbnail “resized” picture and the original picture. When we have already resized, we just create an instance, when we do not have an image we create this one and then return a new instance. This method waits all resize to occur before resolving. This is the reason of the .all. We are doing so just to have a clear cut before moving to the next step and since we are launching multiple resizes in parallel, we are waiting to have them all done before analyzing.

function resize(fullPathFiles: string[]): Promise<IImage[]> {
    const listPromises: Array<Promise<IImage>> = [];
    const promise = new Promise<IImage[]>((resolve, reject) => {
        for (const imagePathFile of fullPathFiles) {
            const thumb = getThumbnailPathAndFileName(imagePathFile);
            if (fs.existsSync(thumb)) {
                listPromises.push(Promise.resolve({ thumbnailPath: thumb, originalFullPathImage: imagePathFile } as IImage));
            } else {
                listPromises.push(resizeImage(imagePathFile));
            }
        }
        Promise.all(listPromises)
            .then((value: IImage[]) => resolve(value));
    });
    return promise;
}

This function use a function to get the thumbnail path to lookup if it’s been already created or not. This function call another one too, and both of these methods are having the same goal of providing a path. The first one, the getThumbnailPathAndFileName get the original full quality picture path and return the full image path of where the resized thumbnail is stored. The second one is a function that will be resused in some occasion and it gives the metainfo directory. This is where the resized picture are stored, but also the JSON file with the analytic data are saved.

function getThumbnailPathAndFileName(imageFullPath: string): string {
    const dir = getMetainfoDirectoryPath(imageFullPath);
    const imageFilename = path.parse(imageFullPath);
    const thumbnail = path.join(dir, imageFilename.base);
    return thumbnail;
}

function getMetainfoDirectoryPath(imageFullPath: string): string {
    const onlyPath = path.dirname(imageFullPath);
    const imageFilename = path.parse(imageFullPath);
    const thumbnail = path.join(onlyPath, "/" + directoryName + "/");
    return thumbnail;
}

The last method is the actual resize logic. The first line of the method create a “sharp” object for the desired picture. Then we invoke the “metadata” method that will give us access to the image information. We need this to get the actual width and height and do some computation to get the wider side and find the ratio of resizing. Once we know the height and the width of the thumbnail we need to create the destination folder before saving. Finally, we need to call the “resize” method with the height and width calculated. The “webp” method is the one that generate the image. From there, we could generate a buffered image and use a stream to handle it in memory or to store it on disk like we will do with the method “toFile”. This return a promise that we use to generate and return the IImage.

function resizeImage(imageToProceed: string): Promise<IImage> {
    const sharpFile = sharp(imageToProceed);
    return sharpFile.metadata()
        .then((metadata: sharp.Metadata) => {
            const actualWidth = metadata.width;
            const actualHeight = metadata.height;
            let ratio = 1;
            if (actualWidth > actualHeight) {
                ratio = actualWidth / maxSize;
            } else {
                ratio = actualHeight / maxSize;
            }
            const newHeight = Math.round(actualHeight / ratio);
            const newWidth = Math.round(actualWidth / ratio);
            const thumbnailPath = getThumbnailPathAndFileName(imageToProceed);
            // Create directory thumbnail first
            const dir = getMetainfoDirectoryPath(imageToProceed);
            if (!fs.existsSync(dir)) {
                fs.mkdirSync(dir);
            }

            return sharpFile
                .resize(newWidth, newHeight)
                .webp()
                .toFile(thumbnailPath)
                .then((image: sharp.OutputInfo, ) => {
                    return { thumbnailPath: thumbnailPath, originalFullPathImage: imageToProceed } as IImage;
                });
        }, (reason: any) => {
            console.error(reason);
        });
}

This conclude the resize part of the project. It’s not as straight forward as it may seem, but noting is space rocket science either. This code can be optimized to start resizing without having analyzed if all the image are present or not. Some refactoring could be done around the ratio logic within the promise callback of sharp’s metadata method. We could also optimize the write to remain in memory and hence having not to reload the thumbnail from the disk but working the on the memory buffer. The last optimization wasn’t done because I wanted every step to be re-executed what ever the state in which they were stopped. I didn’t wanted to bring more logic to reload in memory if already generated. That said, it could be done. The full project is available on GitHub : https://github.com/MrDesjardins/CognitiveImagesCollection