Hacker News new | past | comments | ask | show | jobs | submit login

I talked with Lee Byron about the differences and if there's hope for convergence at React Europe. He said:

- the biggest difference is nullability (you have to explicitly set TypeScript to treat all types as non-nullable by default to get behavior similar to Flow's default).

- Flow uses nominal typing (similar to functional languages); whereas, TypeScript uses structural typing (similar to Java). To be honest, I don't remember the ramifications of this, but I think one was it makes Flow easier to work with/require less boilerplate. If you set types on your exports, Flow can infer the stuff in the middle. Flow is also compatible with prototype chains; whereas, TypeScript only knows about ES2015 classes (unless you declare types separately in t.ds files).

- Because TypeScript is a compiler, they can define their own syntax. Flow, on the other hand, tries to be compatible with pure JavaScript. (You can define Flow annotations in comments to avoid needing a tool like Babel.) This means the syntax for certain operations is a bit more verbose in Flow: I think the nullable operator was one case, where the operator Microsoft chose could be ambiguous with JavaScript code in Flow, so Facebook chose a different one.

In short, there are inherent architectural differences that make the two incompatible - there can be edge cases that make a file that works in one not work in the other. The two teams share notes and try to avoid divergence when possible, but as the slideshow shows, the projects have different aims, which can yield conflicting decisions. If Microsoft adds support for the Flow nullability operator, there ought to be a large subset of shared syntax between the two, where files that work in one should work in the other, if you set TypeScript to use Flow's defaults and don't rely on nominal typing.

These are all notes off the top of my head from last week. I haven't used either tool yet. Please feel free to correct any mischaracterizations.




> Flow uses nominal typing (similar to functional languages); whereas, TypeScript uses structural typing (similar to Java).

Most statically typed languages have both nominal and structural types, and, if anything, functional programmers use structural types to a much greater extent than Java programmers:

(0) Haskell and ML: Algebraic data types and type classes (Haskell-only) are nominal. Function types, parametric polymorphism, module signatures (ML-only) and object types (OCaml-only) are structural. Type synonyms are of course structural. Type inference makes it practical to work with definitions whose types would be quite large if explicitly annotated, so programmers don't shy away from parameterizing types by four or more type parameters: http://hackage.haskell.org/package/lens-4.14/docs/Control-Le... , http://hackage.haskell.org/package/pipes-4.2.0/docs/Pipes.ht...

(1) Java and C#: Classes, interfaces and variances (C#-only) are nominal. Generics and wildcards (Java-only) are structural. No type synonyms and limited inference make working with syntactically large types very inconvenient. And guess which is the most vilified feature of Java's type system among Java programmers themselves...


>you have to explicitly set TypeScript to treat all types as non-nullable by default to get behavior similar to Flow's default

To be fair, it's one line in a config file / tsc commandline.

>Flow uses nominal typing (similar to functional languages); whereas, TypeScript uses structural typing (similar to Java)

Flow also uses structural typing, except for ES6 classes which it considers nominally typed.

>I don't remember the ramifications of this, but I think one was it makes Flow easier to work with/require less boilerplate

I can't imagine how that's related.

>I think the nullable operator was one case, where the operator Microsoft chose could be ambiguous with JavaScript code in Flow, so Facebook chose a different one.

I think you're talking about the type assertion operator which used to be angle brackets in TS. Yes it would cause syntax ambiguities with JSX. Since Flow had JSX support from the start for React, they chose a different operator (?:). When TS added support for JSX, they added another type assertion operator (as).


Java does nominal typing. That's actually a difference between Flow/TypeScript and Java/C#. The laters do nominal types (that is, if I have type Foo, that has a string property, and type bar, that also has a string property, they are NOT consider the same thing in Java/C#)

The difference is that TypeScript does structural typing exclusively, while Flow does structural for interfaces, and nominal for classes. So if you don't use classes, there's no difference (on that front), but if you use classes, there is.


I know I sound a little ignorant, but could you elaborate a little on nullability. I mean is it the same as checking whether an assignment is null or not?

P.S. I haven't used either typescript or flow.


The basic notion is that part of the meaning of a type is whether it's allowed to be null. As developers we have notions of whether some variable is supposed to ever be null; this is just asking the computer to make sure.

For example, suppose you're building a simple app to remind you to call your friends on their birthdays. Your fields are name (a string), birthday (a date), and phone number (a string). Since it doesn't make sense to put somebody in without a name and birthday, you say those aren't nullable. But say you want to be able to leave a phone number out, because it's easy enough to look up their phone number when you want to call. So phone would nullable.

Java, as an example, required everything variable to be typed, but all references could be null. This meant that far and away the most common error in Java logs was NullPointerException. It's great to see language features aimed at reducing that.


null and undefined are part of every type in TS, but you can tell it to exclude it from every type by default (with TS2.0). Then you are forced to check for it on every part of your code where it possibly could become null or undefined (like when data from external libs comes in etc.), so inside the TS code everything should be save to use. (no more: a && a.b && a.b.c = 123)

I have the feeling that even if you would just use "any" (with excluded null and undefined) everywhere 90% of JS problems would go away.


I have the opposite impression.

Structural type systems feel like dynamic typing most of the time, especially with JavaScript in mind (many {} and [] etc.)


I might have got the names backwards.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: