http://tryflow.org/#2944d91c10fc5d76faeebbb20cac466a Try this snippet in TS.
http://tryflow.org/#2944d91c10fc5d76faeebbb20cac466a Try this snippet in TS.
var x: any = {}; x.foo();
Here's the typesafe way: http://tryflow.org/#b5f826e03045f64084cfc74398270e85
Try adding the types to the function in your Flow example. The error will finally move to the last line i.e. Flow will actually become useful in tracing down the error.
http://tryflow.org/#e6512d9c847d504bba8be8b90427ffc3
I think Microsoft made the right call to demand function argument types. It doesn't cost very much at all, but it improves error messages tremendously. It might not matter in a tiny example, but I'd bet that Flow's behaviour can be frustrating in a large project.
Showing no errors is a separate argument entirely, and was addressed by the parent poster (noImplicitAny). I will add that I always use TypeScript with --noImplicitAny which indeed does result with TypeScript DEMANDING type annotations for arguments. Of which you complained:
> Having to declare types on everything even if it's just generics beats the productivity argument.
and to which I respond that
1. its not everything, just function arguments
2. its better to demand function argument types than to show unhelpful error locations.
Implicit any is (was) useful for the early migration phase of the project. At that point you (had to) rename everything from JS to TS to use the compiler, and would get a type error for every unannotated function (which might not be a type error at all). The TS team had to choose between:
1. spending a lot of time and effort to get proper deep unification like Flow's working at acceptable performance in a single-threaded process, even without incremental recompilation, or
2. default to a loose "type checker" and provide a gradual tightening valve for users - at the cost of demanding a bit more annotations: for function arguments (and only if the function is not a part of a single expression or statement where the type can be inferred - e.g. types will be inferred for lambdas passed as function arguments)
(1) may have been worth it if it actually resulted with useful error messages, however as demonstrated above, it often doesn't. So they went with (2), and I'm glad they did - otherwise I'd have to deal with mostly-unannotated TypeScript codebases that produce useless error messages every time you do some sort of refactoring, or enforce type annotations via conventions / code reviews / linters.
Flow's inference is a beautiful marvel of engineering, really, and the type system avoided some legacy TS pitfalls (has safer treatment of nulls, proper union and intersection types from the start) but I'm afraid its not that big of a marvel of practicality.
> var cats : Cat[] = [ new Cat() ]