Hacker News new | past | comments | ask | show | jobs | submit login
Announcing TypeScript 2.0 (microsoft.com)
553 points by DanRosenwasser on Sept 22, 2016 | hide | past | favorite | 310 comments



TL;DR

- Simplified Declaration File (.d.ts) Acquisition (via npm)

- Non-nullable Types

- Control Flow Analyzed Types

- The readonly Modifier

Finally, I was wating for months :)


And a whole lot more. https://github.com/Microsoft/TypeScript/wiki/Roadmap has a summary of the most important changes.


I'll add the ability to use globs in tsconfig is a big win too.

http://www.typescriptlang.org/docs/handbook/tsconfig-json.ht...


Simplified Declaration File (.d.ts) Acquisition (via npm)

This is huge from a usability perspective.


It doesn't seem to be ready. Random thing are broken that weren't in Typings.


There's a couple different things we're talking about here. The ability to install typings via npm, which is good because it gets rid of another tool (typings) and everything is in package.json. But the other thing is the ability to consume declaration files in node_module packages themselves, which I consider a bigger win.


Why couldn't you do that before? Definition files are just ts files, wouldn't tsc be able to find them in node_modules?


i hope they will add details on creating new d.ts files for the new @types scope.


We've got some of the documentation out now. You can see more at https://www.typescriptlang.org/docs/handbook/declaration-fil.... When submitting PRs, new files will need to be written for the `types-2.0` branch on DefinitelyTyped.


So now

    tsd install angular
is replaced by this?

    npm install -s @types/angular


If the library has it's own .d.ts file in the repo, it will just work.

Otherwise, the @types packages on npm are the way to go.

Please note that most of the @types/XXX packages are just automatically extracted from the DefinitelyTyped repo. Big packages with lot's of updates can use their own repo.

But this is a huge, huge usability win. No more haggling with additional tools to get your typings.


From a usability point of view is it really such a huge huge win that instead of using `typings install foo` you can now use `npm install @types/foo`?

I can see it's better (not sure why a single repository(!) was ever considered a good idea), but in the end both methods work if all you need is to obtain the latest version of a .d.ts file.


As far as I know, some libraries bring their own typings, especially when they're written in TypeScript.


Right, Angular 2 could build typings directly from their Typescript sources into their npm packages (there's a "typings" field to add to package.json being the only other step). If they did that all you need is npm install -s angular and typings just fall out of the sky for you.

Aside, my biggest concern with the new @types scope is that it is still tightly coupled with the DefinitelyTyped megarepo. DT has been a great help over the years, but it's so huge and increasingly hard to contribute to as DT has increased its quality bar and its size makes it a stress test on git tools and IDEs, too.


I can't wait to use some of the new features in our production apps. Typescript is/was my bridge into javascript development, because IMHO javascript was a broken language for a long time, and I am not sure if I could have ever done as much as I have without its existence.

Non-nullable types, tagged union types, and easy declaration file acquisition are definitely the biggest wins for me with this release.


Well, to make JavaScript tolerable, you need to use Babel with tons of plugins and presets. Instead, you can just use TypeScript.


Still no async/await though, right?


No the spec is finished and Babel supports it. Browsers already have started implementing it.

Edit: I realize you mean Typescript, my apologies


Javascript isn't as broken as you might think.

Non-nullable types, OTOH, might just be the thing that makes me start using TS, despite my love of dynamic typing.


Yeah, I'm sick of the "static types and classes!!!" crowd, too.

I've come to the conclusion that "mandatory and immutable" should be the default, but there are precious few languages in which that is the case, rather than some noise words that have to be plastered all over. (the noise words should be something like "dont_know_when_or_if" and "whacked_whenever_i_feel" for optional and mutable to make you cringe when you use such a local/parameter/return-value.

It's always funny (funny-sad) to read a project or a research paper that discovered "static types turned out not to catch as many errors as we thought it would".

We've made our turing tar pit, now we have to live in it :-(

... at least until we push the whole C-and-its-spawn edifice over the cliff.


Well, if you assume Static Types, or anything else, is the be-all-end-all. If you use a bit of common sense, you should be fine.


I hear you. Compile time types can be useful, but again, I'm just weary of hearing from the people who want to make them mandatory, and seem unwilling to consider the tradeoffs.

Enter the XML config file... :-(

I ranted quite a bit lately about partial function application as well, but it's not appropriate for everything. But when when you're dealing with a crowd that has no idea that there are other ways of doing some things...


I mean, yeah. Mandatory typing isn't always The Right Thing, and XML config <english:word:grammar:adjective:insult value="sucks"/>. And it is a tradeoff.

And partial application is never necessary. It's elegant and useful, and can save you a bit of typing, yes, but it's never needed. It's nice to be able to type:

  map (+ 3) a-list
but I don't mind:

  (map (lambda (x) (+ x 3)) a-list)
and in most Schemes, there's a macro called cut, which means you can do this:

  (map (cut + <> 3) a-list)
Which is almost as nice as the first one, and works regardless of the position of the arg you want to apply.

And it's no so much that the crowd doesn't know that there are other ways of doing things, it's that they reject them out of hand, because they're different.


Rather than strict, one at a time down to arity-1, currying, I wrote a utility to wrap up functions so "bare parens" simply called the function, or one of its partially applied "derivatives", with however many arguments you passed, and an explicit "method" on the function had to be called (I think I called it "apply", but ended up using the alias "inject" so my Java coworkers understood the purpose).

Can you attach a property list to a function in Scheme? If so, maybe you could make a way for properly prepared functions to have an "apply" property. (like I said, it's been a LONG time since I did Lisp)


My favorite Scheme has the ability, but like so much in schemeland, it's not formally specified. But cut effectively does the same thing, so what's the point?

Then again, I don't totally understand your system, so I might just have gotten it wrong...


Argh. I've never done Scheme. In fact, it's been since the mid 80s when we dabbled in Common Lisp at school. Most of this stuff I had to be re-introduced to again looking at Ruby and doing some reading about 10 years ago.

The first line looks odd to me, since there are just 3 expressions sitting there - no parens around map and the rest of the stuff. My ignorance is showing :-(

... but I don't want to write Java <= 7 style inner classes, either. I'll likely get a bad case of COBOL-fingers.


That's because Scheme doesn't support partial applications (I mean, you can return lambdas, but your functions aren't curried by default). That's why we have to cut macro from the third line to fake it.

Instead, the first line is Haskell, the best-known language to support that particular feature. I personally dislike it, but if you're demonstrating partial application, it's the language to do so.

And in case you haven't realized it yet, Java is actually the new COBOL: Verbose, ugly, and very popular in industry.


Oh, I very much realize that about Java. I was so excited about Java, 20 years ago. (of course the industry alternative was C++, so I'd rather be shot in the foot than the head).

I never saw any Simula 67 until VERY recently. Hmm. So its what Borland patterned Turbo Pascal 5.5 (and beyond) after, more or less. And Eiffel, as well. But the MIS industry keeps trying to rehabilitate a portable assembler for general application programming (C, C++, Java, ???)


...With the logic that it's performant, and it worked for Ken Thompson, not realizing that Unix is an order of magnitude less complex than the systems they're building, yes.

Don't get me wrong, as a language I will defend C to the very end (C++ and Java, not so much), but it has a specific usecase: Low-level code, or code where you absolutely need the performance. If you're not in either area, stop. You shouldn't be using C. And, of course, Rust has been eating some of C's lunch of late...


I did a lot of C in the 90s. Appropriately, in the first half to do "systems" type programming (we made development tools to emulate IBM mini computer facilities on PCs and unix , etc), less appropriately in the second half (bulk document formatting for one of the biggest print and mail houses)

One good thing about Unix is, the creators intended for things to be stitched together as insulated building blocks, NOT to be built as monolithic C programs (at least as far as I can tell). OK, I'm really off on a tangent now. Have a nice day :-)


Save the kernel, which is pretty small, yes. Essentially, they realized C wasn't up to the task of writing monoliths, and so they didn't, to keep global complexity low. Richard Gabriel argued that this was part of C's success over Lisp in "Lisp: The Good News, The Bad News, And How To Win Big," informally known as the Worse is Better paper.


Said elsewhere, but I've not done Haskell or F#, either, but I understand they are both similar, at least in regard to currying.


Yeah, I kinda assumed you had, as that's how most people get introduced to partial application.


One other thing: more important than the typing, is having to read excess logorrhea for the life of the project. (IDEs are good at generating filler, but I don't want to read it)


Qwerty's law: If your IDE can generate most of your program for you, than your programming language is badly designed.


non-nullable types are excellent. It basically gives you implicit Maybe/Option.


For explicit Maybe/Option try Monapt[1]. Disclaimer: I might know the author =)

[1] https://github.com/jiaweihli/monapt


Please tell the author Either is where it's at these days. Even F# is doing it! :)


Try adding 1.3 + 1.1 and tell me JavaScript isn't broken. Hint: The result is isn't 2.4, it's 2.4000000000000004.

Unfortunately that's something TypeScript doesn't tackle, but you can use external libraries for floats, where you work on floats as... strings.


That's arguably a problem in almost every language that follows the IEEE 754 standard. It doesn't make much sense to pin that problem solely on Javascript.


when you work with floats, never expect anything to exactly equal a value, ie, it should be banned to use <float> === <constant> . That is universal across languages, for exact representations often languages provide another type. But floating point is popular because CPUs can natively work with them.


For financial work, you want to use a fixed precision or binary coded decimal library, such as java's BigDecimal.

You knew that, but I'm just spelling it out for others.


...Or you could use Scheme, where we have precise numbers (fractions)


JS does that... And so does C, and just about every other language out there.


Well, here's one way around that, at least on the server:

https://github.com/roboprog/nashorn_play/blob/master/script/...


Is that your only complaint about JS?


This isn't really the place for it but I really wish that both Webstorm and Resharper used the actual typescript compiler for its tooling (like vscode) vs handrolling their own. Now I have to wait until Webstorm 2016.3 to see the full benefit of 2.0, rather than getting it for free by just updating typescript. Not to mention the obscene number of typescript edge case inconsistencies in the warnings, errors, and refactorings.


You've been able to configure your own tsc for a while, at least in IDEA anyway.


Webstorm does as well. It's in the settings, under Languages > Typescript. You have set "TypeScript version" to "Custom" and give it the path to your "node_modules/typescript/lib", and then also check the box to "Use Typescript Service (Experimental)".

It's marked as experimental, but has worked flawlessly for me on a moderately sized project using typescript 2.0.0@beta


I more meant in the form of tooling, not compiling. The intellisense that it provides is often incorrect vs VSCode which asks tsc what the intellisense is, making it always correct.


This is possible if you look closely at the settings for TypeScript in IDEA/WebStorm:

> Select the Use TypeScript Service check box to get native support from the TypeScript Language Service according to the up-to-date specifications. In this case syntax and error highlighting is performed based on the annotations retrieved from the TypeScript Language Service while code completion lists contain both suggestions from the TypeScript Language Service and suggestions calculated by IntelliJ IDEA itself.

https://www.jetbrains.com/help/idea/2016.2/typescript-suppor...


Wow, you're right. This is new by the way, wasn't like this at least in the 1.0 typesript days.


Wow! Great catch! I hope resharper gets this soon


Typescript is such a neat project. The js ecosystem is vast and diverse and the typescript team has the unique job of figuring out how to make common dynamic patterns type-safe and convenient. Like... that's so cool. Every little pattern like its own type system puzzle, and there's no _avoiding_ the issue like a ground-up language can do, because their job is literally to type the JavaScript we write today.

Also, how much money is MS pumping into TS? A lot of OSS has one or two super-contributors that carry the project on their backs, but typescript has a small army of smart people with significant contributions.


I'm still trying to figure out Microsoft's new end game. Major inroads into OSS, more linux support, VSCode, etc.


End game is be relevant to developers. There's an entire org called DevDiv whose primary job is to win developer market share. If developers love your platform and tools, then they won't hesitate to use Azure and the other money making beasts.


Control-flow analysis? I think that was Flow's differentiating feature.

Obviously, there are still differentiators between the projects (like TypeScript including a known set of transpilers vs. Flow delegating to Babel), but I'm curious to know if they are converging on their core feature (e.g. how to do type-checking/static analysis).


they are. Flow is still quite ahead in term of control flow analysis and "soundness" features, and the type system in general is much richer, but TypeScript is catching up. Flow's tooling is getting better (though it still has ways to go).

It's pretty easy to see where things are going. Advanced type systems (Elm, Scala, ML, Haskell, whatever) have the features we really need, and tooling (IDE support, etc) can use that info to provide crazy good tooling, so any type system developed in 2016 and beyond must have all of these things to be of mass appeal.


Hey, I don't see TypeScript as being behind on control flow analysis or anything like that.

If you're referring to differences in the way TypeScript narrow types based on control flow analysis, we don't see one as being "better" than the other, but TypeScript takes a more optimistic approach to avoid putting users in frustrating scenarios where the analysis is too limited. Most users tend to prefer this to the slightly more rigid approach used in Flow, so we felt we made an ideal choice there.

If you have any specific thoughts or ideas, feel free to leave us feedback on our issue tracker.


To be fair, it is very, very unlikely that I am better at type systems than someone working on TypeScript, so anything I'd suggest, you probably heard about, and is either already on your roadmap, or was a conscious design decision that we just happen to disagree about :)

I think the javascript type system world is still evolving, and the only "wrong" thing to do is to say "Ok, its a solved problem, let's run away with THIS ONE and kill the others".

As long as we still have at least 2 reasonably well known ones, I'm happy.


One of the things I've been really needing is buried in the wiki:

> Previously flagged as an invalid flag combination, target: es5 and 'module: es6' is now supported. This should facilitate using ES2015-based tree shakers like rollup.

So now I can add rollup to my production build pipeline to remove dead code. Nice!


Wow TIL, I had no idea this was a thing! It looks amazing!


TypeScript is so strange for me. Each time I read something about it, I want to give it another try... then I read some codes and I just can't go further. I like JavaScript as it is, without types on every line of code.

Unlike most people on HN, I like JavaScript. I build web app since 2011. I liked working with jQuery, then Backbone and Grunt, then Angular and Gulp. Now I'm working with React, Webpack and Babel (ES6/ES7) and writing web apps has never been so much pleasure. JavaScript in 2016 is really fine for me. And the common point in my JS experience from 2011 to 2016 is that dynamic typing has never been a problem. I also worked with strongly typed languages for years like Java or C# and I still prefer the flexibility of JavaScript.

So it's strange because I admire TypeScript. The work accomplished by its team is really amazing. And it's so nice to see a single library reconcile developers with JavaScript. But in the other hand, I prefer keeping my JS without types because it just works fine for me and the teams with who I worked.


Have you tried starting a fresh project with just TypeScript?

I have no idea how your brain works, but for me working with a non-trivial JavaScript codebase is a nightmare.

TypeScript makes web development fun again.


Yeah.

Every making even a small change to a JS codebase you haven't touched in a while that isn't VERY thoroughly tested? (Doesn't even need to be a big code base).

Thinks will break. And you will lose hours of time.

Static typing doesn't eliminate all bugs, of course. But it can catch many common mistakes made in JS.


If you don't have tests, why do you think your code works?


I never said write no tests.

But static typing catches a lot of things otherwise only caught by tests.

Also, try Haskell. Haskell code that compiles works correctly sursprisingly often. ^^


> I like JavaScript as it is, without types on every line of code.

Types are inferred for the most part. Typically, you have to annotate less than a quarter to make your project fully typed. I have about 7-10 types per 100 lines in my current project and I do use "noImplicitAny" and "strictNullChecks".

Most of those types are for fields and function/method signatures. You probably might want to document those types either way. Type annotations are a lot nicer for this than JSDoc comments.


Man, I feel like the only one here who doesn't really like static types. I like dynamic typing just fine (it's crazy, I know: it must be the lisp influence). And if I want static typing, TS feels a bit intrusive. Flow is much better in this respect.

I also don't think JS is the root of all evil, and I use Emacs rather than an IDE (although we do have really good integration with regular JS, in the form of the famous js2-mode, and flycheck's linter integration). I, mean, do you really need your IDE checking your types as you type? It's not that slow, and us Emacs users have M-x compile, so we can run our code, and than jump back to the problematic line when an error occurs, and I know IDEs have similar functionality.

Don't get me wrong: static typing can be good at times, and option static typing and compile-time type analysis are useful tools, and I'm glad TS, Flow, and the like exist. But I always see a flock of comments saying that they couldn't possible live without static types, and thanking TS for taking them out of the hell of dynamism, and wishing there was something similar in Ruby/Python/whatever.

I don't really get that.


On the other hand I don't understand how anyone can work with a code base that is dynamically typed. I'm looking at a function parameter in a random file. How do I even begin to work with it?

Unless you wrote the code yourself you pretty much have to run the program first and then REPL to see what the type actually is and the properties it exposes Slow, arduous, unnecessary.

Also especially in the early stages of any development project I am refactoring like crazy as things come together. Static typing enables refactoring operations that are lightning fast with almost zero chance of error. Refactoring in any dynamic language is super error prone and leaves open the possibility for bugs that often show up unexpectedly at runtime.

Do people who prefer dynamic languages actually use the benefits of dynamic typing in the first place? Changing variables from one type to another mid-stream. Dynamically adding properties to objects, using == instead of === etc.. Those things are a recipe for bugs, inconsistency, and unmaintainability right from the get go.

Static typing doesn't feel intrusive, it feels like a flashlight. I don't like coding in the dark, feeling around for what everything is or is not.


> Do people who prefer dynamic languages actually use the benefits of dynamic typing in the first place? Changing variables from one type to another mid-stream. Dynamically adding properties to objects, using == instead of === etc.. Those things are a recipe for bugs, inconsistency, and unmaintainability right from the get go.

I think you are mixing some things there. The biggest advantage of dynamic typing is that it has no restrictions to how you are allowed to program. There are many cool language features that you can only use in a static language if its type system was designed to support it while in a dynamic language you can just implement it yourself (just hope it doesn't crash at runtime). For example, datatype-generic functions, object orientation (in all different variations), encoding JSON, etc.

Changing variables from one type to the other mid stream is usually a bad programming practice, so don't do that. Same thing for "==", although sometimes coercions really are convenient (for example wen you read data from an input field its often in string format).

Dynamically adding properties to objects is very useful if you are doing some "metaprogramming" stuff. For example, its trivial to write a "clone" method in Javascript because you can dynamically set properties. In a static language you would need language support for this.

> Static typing doesn't feel intrusive, it feels like a flashlight.

Which is why the Typescript project exists! When your programs are super small (for example, an inline onclick event handler) then dynamic typing wins because its concise (no type annotations), conceptually simple (no type system, type inference, etc) and doesn't get in the way. However, if you have a large program that can't fit all in your head at once then the types help a lot.


Dynamic property addition is super useful.

With the == vs === thing, I think you're confusing dynamic typing with weak typing. Weak typing is why == and === exist, and it totally sucks.

>I'm looking at a function parameter in a random file. How do I even begin to work with it?

First off, Duck Typing: The type of the parameter is the intersection of the types the functions it is called with contain.

Secondly, this is why you document your code and choose prescriptive variable names. Honestly, this is pretty bad even with types (the first question I had when I looked at my first chunk of real world C was, "what the hell is the variable 'int rv;', and what's it being used for?).

Even I'll admit that type annotations can be useful sometimes, but I don't need them.


Having a parameter 'user' doesn't infer what properties are on it. If you're going to document what properties it has you might as well create a type definition for it.

Duck typing (or checking types at runtime) is verbose and forces you to handle type mismatches at runtime. Which means you will probably end up throwing an error anyways when types end up missing the properties you expected.

If your code relies on properties added dynamically that might be useful for you, but god help anyone working with your code.


Well, obviously, I wouldn't document everything, but if the argument name is "user" and it's an object, as opposed to a string, than it's probably a user object. Not exactly rocket science.

That's not exactly what Duck Typing is, but that is possibly true. However, in an OO system, Duck Typing has massive benefits, as you don't have to depend on inheritance to see if an object can be passed to a function: polymorphism. This is the sort of thing Java's interfaces do, albeit clumsily.

>If your code relies on properties added dynamically that might be useful for you, but god help anyone working with your code.

Obviously, you have to be careful about it. But if you're marking nodes on a graph, or attaching metadata to a function, especially if it's temporary, it comes in handy.


You can totally simulate duck typing with Typescript, since it (only) supports structural typing. If your method only expects an object with an asString() method, you can do something like:

    function useAsString(foo: {asString: () => string}) {
        ...
    }
Note that the type we give for foo here is an anonymous type (though this would also work with an explicitly named type).

And now you can do this:

    interface SomeInterface {
       name: string;
       asString: () => string;
    }

    let bob: SomeInterface = { name: "Bob", asString: () => "Bob" };

    useAsString(bob);
And this works, because the interface SomeInterface has an asString() method. No inheritance in sight.


Huh. Pretty cool. Are the interfaces Go-style (must you declare a class/object as that interface, or is it just detected)?

Because if it's not, than it's not duck typing, is it?


Interfaces in typescript are implicit, or auto detected. You dont have to say that a class implements an interface, if it has the correct properties it automatically fulfills the interface. It's like type safe ducktyping and it's super awesome.


Sounds like it works just like Go-lang, then.

Is there a way to cast something anonymous, just a value read in from JSON, to such an interface? This would allow you to specify an important subset of things that an object needs to do, verify it in one place, then pass around the interface handle to anything that needed the underlying object in that role. Presumably, if the incoming object lacked the desired attributes, the "cast" would blow up sooner, during the assignment, rather than later, when the interface alias was used.


That's just compile-time verified duck typing.

Not bad.


Static weak types


No, because you're not doing implicit type conversion, which is what weak typing implies.


Unless you wrote the code yourself you pretty much have to run the program first and then REPL to see what the type actually is and the properties it exposes Slow, arduous, unnecessary.

If the code is well written, then no, to seeing what the type actually is. In a good environment like you have in many Smalltalks, you should be able to compose some implementors searches, then quickly know what you're dealing with. Then you quickly and easily debug the system just to be rigorous. In environments set up by smart people, these actions can be surprisingly quick and easy. (In the same way that git allows for using certain information much more quickly, quantity can become a different quality.)

Do people who prefer dynamic languages actually use the benefits of dynamic typing in the first place? Changing variables from one type to another mid-stream. Dynamically adding properties to objects, using == instead of === etc.. Those things are a recipe for bugs, inconsistency, and unmaintainability right from the get go.

None of those things are the benefits of a dynamic language, except maybe as super debugging tricks. No one who really knows how to write in a dynamic language puts stuff like that in typical code! That you say this makes me think you don't know what you're talking about, or your main exposure to dynamic langs has been through the code of yahoos.


If the code is well written...

In a good environment like you have in many Smalltalks...

No one who really knows how to write in a dynamic language puts stuff like that in typical code

That's the problem. You're talking about some hypothetical, Smalltalk environment, where some expert dynamic language programmers always do "the right thing".


Okay then, but if you're not documenting your functions, which is the most important thing, you shouldn't be working on a large project with other people in any case.


Documentation will not save you the day you decide to rename a function or change its signature. Static typing will.


It depends on your tools. I refactor JS stuff in intelliJ from time to time, no big deal, at least for rename. (1)

OTOH, if you don't have plugins for things like Struts or Spring (faking the desperately needed dynamicism in config files), good luck safely refactoring your "static" typed Java (2). But once have "trained" your IDE where to look, you are back in business again.

1: it's easier to refactor JS if you restrict the scope of identifiers, of course. For starters, this means NOT naively making every function and variable in the global namespace and/or scattered in inline <script> fragments.

2: many other languages dragged into these discussions since there is some general philosophy of compile time vs runtime types discussed on this page.


...No, it won't. It might make the refactoring a little easier, but with various tools, you can check all the call sites and see if you fixed it. Sure, your compiler won't tell you what's wrong, but your REPL and your tests will.


Yes, given enough time for enough manual work, and enough tests, and enough code review....

The whole point is not to have to do this stuff manually, which is very error prone. Ad-hoc REPL work, and tests are very likely to have missed something.


Precisely.


It will absolutely save you, because it will complain loudly about every broken call site and prevent the broken code from making it to production (assuming you didn't use any tricks with any). Tests may or may not help (I have yet to see a codebase with perfect test coverage).


Sure, your compiler won't tell you what's wrong, but your REPL and your tests will.

If a REPL and tests make you powerful, then a type system that doesn't drag you down and good tooling around that will only make you more powerful.


That's the problem. You're talking about some hypothetical, Smalltalk environment, where some expert dynamic language programmers always do "the right thing".

No, I'm talking about a place I've worked, certain subsets of code in other places I've worked, code at customer's shops, and most of the standard library of Smalltalk.

True, I've also seen what can go wrong in Smalltalk. But in my experience, this isn't worse than what can go wrong in other languages, dynamic and static.


I think the argument is not "You can't write something maintainable in a dynamic language" - it's more like "Given the majority of projects, static typing would have helped readability".

Since in SDLC maintenance is like 80%, and most of the time code isn't written amazingly, it seems pragmatic to have static typing.

I love Dynamic languages as much as the next guy (Ruby and clojure are pretty great in my book) but in my career, I get my guys to write in statically typed languages.


it's more like "Given the majority of projects, static typing would have helped readability".

Not so much readability. That comes mostly from good naming in Smalltalk, and thinking about, "What if I had to understand this through senders/implementors searches?" However, in my experience, it helps maintainability. In general, I didn't need type annotations to help me understand the system. Good Smalltalk is about message passing, so you understood the system through who sends what to whom. What I did experience a lack of, were 100% ironclad guarantees in a couple of instances where we needed to be 100% sure about something.

And yes, it is pragmatic to have static typing for the long term!


Some of those aren't even dynamic language things. And most of them are bad form.

But yeah, shoving a flag onto an object where there was no such flag can come in handy at times, if you're treating your objects as dicts or whatever (in JS). If you're doing Real OO, you'd want to put the flag into the class/prototype declaration, so that it's documented, but if you're not, or just need to attach some extra data to, say, a function, it's handy.

Also, in a well documented system, functions should note what types they except, even if it is just "any types that respond to these messages" in smalltalk, or your local equivalent.


> But yeah, shoving a flag onto an object where there was no such flag can come in handy at times, if you're treating your objects as dicts or whatever (in JS).

Ugh, no. I really don't want to be looking at code where properties appear after initialization and you have reason about when the damn thing is actually available, thank you.

> Also, in a well documented system, functions should note what types they except, even if it is just "any types that respond to these messages" in smalltalk, or your local equivalent

So, like specifying type signatures in Typescript, except probably out of sync because it's not automatically enforced?


Well, sometimes, which is why optional type signatures, like those in TS, can be useful. But even if you're not telling all the typing details, at least tell the world that your function works with strings, or whatever.

And if you're using the properties everywhere, yeah, define them, but if you need to extend an object, and the extension will only be used locally, than it's useful.


What infitessimally small numbers of us actually get to use a dynamic language that is on the Smalltalk end of the scale, vs the overgrown scripting languages like python, lua, ruby or javascript?


Many of those "overgrown scripting languages" owe a pretty big debt to Smalltalk. Ruby and JS, particularly, borrow heavily from Smalltalk and Self. Lua is very Schemey, and while many talk about JS's Scheme influences, Lua really does feel like Scheme sometimes, and reflects Scheme's values far more than JS (small number of primitives, TCO, emphasis on minimalism and flexability, etc.).

Yes, they don't have the refactoring toolkit Smalltalk does, and they can be slow, but don't discount them off the bat. The two ends of the scale are closer together than you think.


Sure, but to be kind, the tooling mostly sucks bogwater. Trying to detect usages of symbols or perform simple refactorings is considerably harder than even in languages with less than stellar static typing, like the C++/Java/C# enterprise workhorses, much less anything more powerful. Maybe I'm spoiled, but using find&replace and runtime errors feels as primitive as banging two rocks together.


Well, maybe I'm spoiled, but waiting forever for your code to recompile, just to discover that you misplaced a semicolon, as opposed to running it through a REPL as you develop feels a primitive as banging rocks together.

It's a tradeoff, and I didn't choose the refactoring side. Although refactoring did originate in Smalltalk...


It's funny that the guy that wrote the definitive catalog of refactoring techniques prefers to work in a dynamic language.

http://www.martinfowler.com/articles/rubyAtThoughtWorks.html


> Do people who prefer dynamic languages actually use the benefits of dynamic typing in the first place? Changing variables from one type to another mid-stream.

I don't think people use dynamic languages for that ability. It's more for the ability to not have to explicitly think about types -- it's more natural that way.


When you start typing user.. your brain is thinking about what type user is and the properties on it. How about not just keeping that knowledge in your brain, but write it down as a type definition so others can work with your code without having to become Sherlock Holmes.


First they tell you the types are optional.

Then one day the type declarations are not, and you have to define "JSON schemas" or some such thing for other people's glop that you just want to shovel over a fence without concern of what is in it for most of the code.

That's my nightmare, anyway.

There are plenty of things that bug me more than "intellisense" (auto-completion) not working. Although type inference in my IDE on JS actually works well most of the time. (and I get to skip transpiling and source maps)

YMMV, but if you want to understand how some of "The Other Side" feels, there you go.


> Unless you wrote the code yourself you pretty much have to run the program first and then REPL to see what the type actually is and the properties it exposes Slow, arduous, unnecessary.

I think this is true of statically typed languages as well, at least with anything larger than a single function.


Statically typed languages have a few large advantages over dynamic languages. These include:

- Refactoring. Refactoring a large JavaScript codebase (> 100k loc) is nearly impossible and at best incredibly painful, error prone and time consuming. With static types, it becomes a trivial and straightforward process.

- Your code is now more discoverable. You can easily find definitons, and discovering all methods and properties on an object is as simple as triggering an autocomplete pop up.

- Code is now more readable. Objects are never opaque. You never have to dig through multiple calls just to see what the shape of an object is. It's all right there.

For me, the killer app is refactoring. Writing huge amounts of JS is very painful to me because I refactor almost constantly as I add more code. Most dynamic languages have this problem. Static typing changes that completely.


I don't get this. Most of the known refactorings can't be easily implemented by IDEs so you're left with the trivial ones like renaming or moving things.

Static types won't help you refactor a monster class into a structure of arrays. It won't refactor your callback hell into coroutines. It won't refactor your "one-at-a-time" algorithm into batches. Yet these all yield more agility and performance.

The thing is, I usually have so much less code when throwing static types out the window that refactorings become a non-issue. I get away with basic Emacs macros and unix tools.


>I don't get this. Most of the known refactorings can't be easily implemented by IDEs so you're left with the trivial ones like renaming or moving things.

First, the trivial ones are great and useful refactorings too -- and still difficult in dynamic type systems.

Second, static types also benefit the more difficult refactorings that you still have to do manually, by giving you compiler errors and warnings when you botched them at least at the type level. With dynamic languages those need to be done both 100% manual and with no aid.

Third, static languages are a superset of dynamic typed languages, so they can do everything the latter can do, while the inverse is not true.

You can have a "var" or "variant" etc type in a dynamic language that lets you code exactly like in a dynamic typed language where you want it.

(In fact dynamic typed languages are just static type languages with a single type: https://existentialtype.wordpress.com/2011/03/19/dynamic-lan... ).


I'd rather have tests than types. Unless your type-system is sound; most of them are very, very far from it.

You can specify the domain of values with types, but not their ranges. Side-effects fall through unaffected by types as well.

I've done plenty of refactorings in huge statically typed codebases; types are a very, very superficial help there. Everything compiles fine but now you're passing 20 to a function whose range is 1-10. Or you're now generating the wrong filenames.

To me the overhead of using types outweighs the advantages they bring to the table. If I can help it I'd even choose to have a spec I can enforce at runtime using custom predicates than some vague predefined types with weak semantics or unit tests I have to maintain manually.


>I'd rather have tests than types. Unless your type-system is sound; most of them are very, very far from it.

As I wrote, static type systems are a superset of dynamic type systems. So they can have both.

Besides, static types are, among other things, automated tests for the trivial stuff -- which the computer automatically tests/ensures them instead of a human writing them as busywork (and potentially getting them wrong).

The "sound" type system requirement doesn't make sense either. A non sound type system can still catch the majority of parameter/variable misuses automatically. With dynamic type systems you don't even have that, so essentially what you wrote means "I want it all or nothing". Cool when it comes to personal ambition, doesn't make sense when what you get still protects you from all kinds of errors and helps you refactor and self-document your code.

>I've done plenty of refactorings in huge statically typed codebases; types are a very, very superficial help there. Everything compiles fine but now you're passing 20 to a function whose range is 1-10. Or you're now generating the wrong filenames.

That would matter if static types somehow prevented unit/functional testing, which they do not.

And, depending on the language, the help of static types can be far from superficial. Even in Ada, back in the 80s, you could define the 1-10 range as a constrain on the type/input parameter.

Yeah, they don't catch all problems -- but that's good too, else we would not have jobs.


> but that's good too, else we would not have jobs.

Given how mediocre the average software out there is, I'd much much rather have an industry focus on actual engineering. Its a lot more profitable to find new problems to solve rather than continuously fix your own mess.

I used to write very well documented statically typed code, and then watching people without domain knowledge butcher the hell out of it after I left.

At the end of the day knowing what you're doing is priceless. Just like having guard rails is no excuse to not learn how to drive.

Alls I'm saying is that types are very overrated when it comes to actual robustness and correctness. You can get it without types and you can miss it with types.


> I'd rather have tests than types.

They aren't mutually exclusive. I'd rather have both.


Oh I know, but my opinion and experience in half a dozen statically typed languages over a decade is that most type systems add much more overhead to development than agility.

I do want types when building native software, because these sit directly on the CPU and have to match the hardware. Other than that I feel they at best give you the illusion of robustness - unless the type-system is actually sound but very, very few are.


Type inference makes all the difference in my opinion. Once you have even simple (C# level) type inference than the overhead of static typing is so low there isn't much reason to use dynamic typing.


Yes I agree type inference is wonderful! But when the underlying type-system is just C# I feel like I'm given a half-assed solution.

What good is having a int type if you can't limit its range?

I'm not going to maintain BOTH static types and tests. The ROI is way too low on that and won't even come close to guarantee robustness.

Assertions over composable predicates gives me much more out of the time invested to write it. They are right there in the code at runtime, not separate like unit tests or in a different phase like static types.


> What good is having a int type if you can't limit its range?

Well then you don't have to test what happens when someone passes a string, an object, or a boolean. Most dynamic languages will silently convert many of these values into an int and produce incorrect results.

> I'm not going to maintain BOTH static types and tests.

You have to maintain documentation and you have to maintain tests and you have to maintain assertions for the implied types of your functions anyway so you might as well make them explicit in the code.


> Well then you don't have to test what happens when someone passes a string, an object, or a boolean.

That's useless, I still need to test the value's range which implicitly checks the type.

> You have to maintain documentation and you have to maintain tests and you have to maintain assertions

Not if I can generate most of it from the specification data.


> What good is having a int type if you can't limit its range?

Most types in the program aren't ints anyway; they're interfaces. If I want to have a range-limited value, I could just create a new type for it.


>Oh I know, but my opinion and experience in half a dozen statically typed languages over a decade is that most type systems add much more overhead to development than agility.

In what sense?

With type inference you don't have to manually specify them.

With a variant type, you don't have to confirm to a specific type, but can accept all, if you want it.

And you still need to conform to an interface in a dynamic language, if your function is x.indexOf(x) you still need to make sure to use it on two strings, if it's a math function on some numbers (and depending on the function, on a range), etc (1). So you are not even spared that -- instead, you just lose the help from the compiler when it comes to it.

(1) You could e.g. let a numeric type string autocoerce of course, but auto-coercion can also happen in static languages, is orthogonal to static vs dynamic typing, and is also generally to be avoided).


> most type systems add much more overhead to development than agility

I think this is true to a certain extent, but with a language like JS, there is a lot more composition of generics than there is inheritance. I see:

  add5toStuff<T extends {stuff: number}>(item: T): T;
drastically more than:

  class X {}
  class Y extends X {}
  class Z extends Y {}
The latter is always a nightmare of fighting the compiler. The former is a breeze to deal with. Your type casting will be limited almost completely to IO.


Both styles still encourage a lot of mutability and complexity throughout the codebase.

The vast majority of typed web codebases I've seen were exercises in Java Enterprise development of various degrees. Generics or not the time spent typing everything is not matched by the advantages of static typing.

You'd get more robustness by managing complexity and state; I've spent far more time hunting down bugs that passed through the type-system and tests than fixing typos in dynamically typed languages.


> Both styles still encourage a lot of mutability and complexity throughout the codebase.

> You'd get more robustness by managing complexity and state;

The top function has a return value of T. That's not encouraging mutability. It's only mutable because JS pass by reference, which is irrelevant to static/dynamic. If you use the return value instead of the passed value, it's "effectively" immutable and is a great way of managing state.


If I do heavy enough refactoring where even the tests break then static typing is wonderful. You literally know exactly what needs to be fixed because it won't compile (and usually you know well in advance of that in the IDE).

Heck then I can even fix the statically typed tests that might be broken.


Overhead? What overhead? Overhead is having to keep the implicit type in my brain instead of having it written on the screen right in front of me.


> Or you're now generating the wrong filenames.

Having a no-overhead Filename type would make this impossible.


How so? That type would be a glorified string at best.

Types can't check the ranges of their values in most languages. And definitely can't do so at runtime.


I can see it working in a statically types language with macros - maybe Scala or Template Haskell? I'm not 100% sure if their metaprogramming is capable of this. Ideally, you could define a type like FileNameString to be a string that has to match a certain regex. Though if you wanted to use the new type throughout your program, I suppose you'd need a String -> FileNameString function somewhere to handle instance of file names generated at runtime.

I agree that the type systems in most mainstream languages fall somewhere short of awesome. I was putting together a small web app in Elm last week, and it was nice to work with a type system that felt like it was helping me design and write better code. That, plus it has the most helpful errors message I've ever seen from a compiler.


Actually it's quite common. For example in .net you have a Uri class and a DirectoryInfo class which are basically just wrappers on top of strings with some validation and helper functions.


> I usually have so much less code when throwing static types out the window that refactorings become a non-issue.

This is almost certainly our difference. The utility of static typing is greatly diminished when the codebase is not very large.

> Static types won't help you refactor a monster class into a structure of arrays.

Sure they will. I mean, sure, it won't be a one-click magic refactor, but that was never the benefit anyways. One strong advantage of static typings is that now you'll know exactly when all your call sites break, so that finding and fixing them will be much more straightforward.


> I don't get this. Most of the known refactorings can't be easily implemented by IDEs so you're left with the trivial ones like renaming or moving things.

These alone are already huge. Think about it for a while, keeping a code base healthy as it goes through evolutions involves a lot of renaming and moving things around.

But there are so many more refactorings that are tedious or even dangerous to do manually. For example, switching the parameters of a method, lifting a method in a base class, extracting an interface out of a class and using that interface everywhere in your code base instead of the concrete class, etc...

Spend some time reading the extremely long list of refactorings offered by IDEA and Eclipse, it will open your eyes.


Renaming and moving is still more than you can get with a dynamic language.


Or in a GUI: Apple-Shift-F

Find: <old name>

Replace: <new name>

…continue working.


That crosses namespace boundaries and risks hitting embedded parts of names, which means that you can't simply replace all as a general practice. You can inspect each one before replacing and be your own type checker or just go ahead and blast them all blindly. With a little thought, blind replace-all will usually work with small code written very recently by you but will become increasingly error-prone with more code, more developers, over more time.

You can, of course, try using case-sensitivity and whole-word search modifiers while trying to maintain naming conventions to keep replace-all working a little longer, but that's just an incomplete and buggy attempt at creating your own watered-down type system, not proving that types aren't useful.


Won't work super hot if you have 2 functions with the same name in 2 different modules and you want to rename one and all its usages but not the other.

It's quite impressive what VisualStudio + Resharper + plugins or IntelliJ with a few plugins can do in their respective first class languages.


I used to like ReSharper but quickly uninstalled it from the large amount of false positives it reported.

Back when I did C# last year I was doing 2D skeletal animations in Unity3D and pretty much wrote the most non-idiomatic C# code ever. Everything was bitfields, structures of arrays and integer indices into contiguous memory buffers rather than heap references.

The tooling was completely useless there. You can't optimize for cache misses and branch predictions without throwing all that nice typed goodness out the window.

As much as types, tests and whatnot can help you, at the end of the day it is impossible to do engineering without understanding what you're doing, regardless of what is there to do heavylifting for you.


This doesn't actually work. Let's say the variable you'd like to rename is 'label,' and you also have variables named 'labelOne' and 'labelTwo'—see the problem?


I just want to point out there is very little emporical data on this front which makes almost every statement along the lines of "static is better because ..." or "dynamic is better because ..." to be pure opinion.


Statically typed languages have a few large advantages over dynamic languages

Fallacies! I'd have said "lies" but I realize you just have limited information. See below.

    - Refactoring. Refactoring a large JavaScript codebase (> 100k loc) is nearly impossible
Really? Refactoring large codebases in VisualWorks Smalltalk was a joy! Hyper nimble. If you stuck to canned refactorings, you had 100% confidence. For years, we were talking about how we could refactor an order of magnitude faster than other environments, and this is still true.

    - Your code is now more discoverable. You can easily find definitons, and discovering all methods and properties
Discovery in Smalltalk was much superior and way more nimble. Combining senders/implementors searches, syntactic pattern matching, and runtime discovery was powerful and joyful to use.

    - Code is now more readable. Objects are never opaque. You never have to dig through multiple calls 
I don't know what you're getting at here. No environment has been more transparent to work in than Smalltalk. You don't just get to read a spec of the object -- you actually get to see it and poke and prod the live version of it to verify your understanding and test your theories. (I understand you can do this in languages like C++ -- it's what I use in my day job -- but it's literally an order of magnitude nimbler in Smalltalk.)

What you have to say about dynamic languages perhaps has to do with somewhat ad-hoc language design combined with somewhat ad-hoc design of the environment and distribution/execution platform. (Javascript/Web browsers?) It certainly doesn't have to be true for dynamic environments per se.


Recall that we're talking in the context of TypeScript vs JavaScript. :P I'm not saying that it's impossible for dynamic languages to be able to refactor, but the truth in the industry is that your choice is probably between JavaScript and TypeScript, not JavaScript and VisualWorks Smalltalk. ;)


Well, amber does exist...

But yeah, probably not.


> more readable

Well, you have very detailed trees, anyway. But the forest is often quite obscured: http://stackoverflow.com/questions/39672359/make-all-identif...

Yeah, I know I'm complaining about one of the worst offenders, rather than TypeScript, but "Welcome to My Nightmare", as it were.


My experience: I don't get how in a project with several developers and maybe even teams dynamic types work at all.

If a colleague writes a function/method that returns something, in JS, how do I know what it is? I have to read the function or its tests. With a statically typed language I immediately know the structure of the returned "thing" (don't want to say object) and can infer how to work on it.


I completely agree. Learning new code without types is way slower for me.

Example: you have a function that takes a 'file' parameter, and you need to modify the function, so you need to know what the properties on the file object are. Is it some custom File class, or just a poor name choice, or the browser File interface?

In a statically typed language it would be marked explicitly and I could probably just CMD+click on it in my IDE and be done.

In, e.g., javascript what recourse do I have? No 'File' module is explicitly imported, and the function is invoked somewhere in library code so I never see the file object constructed. So, let's say it turns out to be this 'File': https://developer.mozilla.org/en-US/docs/Web/API/File —how do I discover this? So far it's been time-wasting, unsystematic trial-and-error sorts of things.

It's not as big a deal as I thought when first switching to JS—but if you believe writing readable code is important, you're lose a major tool without being able to label types.


I feel this is just a myth.

I'm constantly looking at the source even with static types. Unless you're having a Haskell-like type-system the function's signature will still miss most of what the function is actually doing.

How do I know if a function does a network call? Saves a file? Changes the DOM? These are really important things to know when calling code and the type-system is completely oblivious about them.

What I usually see however is that projects using static types frequently have at least twice the team size as the equivalent projects using dynamic types. Communication overhead follows, ownership fades and debt creeps in quickly. After a few month they usually have no traces of agility left.


> How do I know if a function does a network call? Saves a file?

It returns Promise<T>

> Changes the DOM?

It doesn't. React does that. ;)

Basically, TypeScript + React + a mostly purely functional style with a sprinkle of side-effecting IO is a really, really good combination.

Also, I find the argument a bit silly. "This cycling helmet doesn't protect your knees and elbows and spine, so its completely useless and you can remove it!"


> It returns Promise<T>

That still doesn't say anything; is the action referentially transparent? is that a delay? a network call? All a Promise tells me is that the result will come at a later point in time.

> It doesn't. React does that. ;)

My point was about side-effects and complexity in general which the static type-system is generally very clueless about. React is a runtime and dynamic solution to that problem; types aren't really useful here :)

Besides, you're most likely using React with Immutable.js and having some pattern like Redux on top. Which is basically choosing immutability and hostility to state over static types :)

> "This cycling helmet doesn't protect your knees and elbows and spine, so its completely useless and you can remove it!"

That's not what I meant, its more like "why wear winter clothes in the summer?"


> That still doesn't say anything; is the action referentially transparent? is that a delay? a network call? All a Promise tells me is that the result will come at a later point in time.

Promise<T> is like Haskell's IO<T> in terms of what it says. In short, "anything goes"

> My point was about side-effects and complexity in general which the static type-system is generally very clueless about. React is a runtime and dynamic solution to that problem; types aren't really useful here

> Besides, you're most likely using React with Immutable.js and having some pattern like Redux on top. Which is basically choosing immutability and hostility to state over static types :)

Why is everyone always making it an "either or" thing? The usefulness of types is in them describing the input/output dependencies in your code. Change the nature of your inputs, and it tells you what dependencies, or dependencies of dependencies (etc) will be affected. Change the nature of your output, and you get the same for your dependants. This is mainly what TypeScript gives you: it tells you how your modules are connected.

Immutability wont help you with the above. If in the return result of the exported function `f` from module `A`, I change this attribute from "firstName" to "name", who will be affected? TypeScript can tell you things like: `A.f` is called by `g` from module B, which then passes the data unmodified to `C.h` which then tries to access the `firstName` attribute. Voila, now you know. Now, how will immutability, hostility to state or unit testing help you with this question?


> The usefulness of types is in them describing the input/output dependencies in your code.

I agree, but I find types way too weak in that respect. Its not enough to know a function accepts ints; I want to know its range as well.

I spent so many weeks hunting down overflow and out-of-range errors and null pointer exceptions that types feel like an illusion of robustness at best.

> Now, how will immutability, hostility to state or unit testing help you with this question?

Not that much, I'll give you that. But the same is true for a function whose range was 1-20 being refactored into a range of 1-10; types won't catch that.

I used to like types, then testing, now I'm looking at specifications I can write once, compose and then generate assertions, documentation, test data and everything else from. Its by far the best ROI of the three.


> Its not enough to know a function accepts ints; I want to know its range as well.

Types actually help with this too. Instead of changing the possible range of a thing, change its name too: the compiler will quickly let you know of all the places that depend on it. Now you know what to check.


Because winter is coming.

It's easy to read code you wrote yourself 5 minutes ago, try again in 6 months.


Simplicity will help me understand my code 6 months down the road; everything else is superficial and noise in comparison.

You can't hold more than ~7 things at once in your head; once things are that simple you can see bugs a mile away, types or not.

The inverse is not true; types won't help you juggle 15 things at once and bugs will happily slide through the cracks. You're going to forget your codebase, types or not, and when you come back to it only simplicity will help you quickly figure out what you were doing with it.


I used to think like this, and I was wrong. As you add code to a software project, some of this code will be written when the problem is not well understood; thats inevitable. The solution will then need to be refactored or rewritten, the first of which is extremely painful in a dynamic language, even if you keep things simple.

For example: if you implement a store that only sells electronic books will have a lot of assumptions regarding the selling and delivery process. Later the business wants to start selling physical things and needs to handle stuff like shipping costs, tracking and so on.

For problems like online stores, the possible directions in which they can develop are well understood and its easier to plan ahead. For most other things, its not, and the ability to reorganise code to be usable in different ways is invaluable.


React is not "functional". You extend the Component type just to make a view, you can encapsulate local state, you can inherit functions, yadda yadda. Calling it a "component" doesnt make it any less OO


In terms of DOM manipulation, yes it is. The render function is pure.


No, you can choose to write it purely, but it's not pure by default.

You can see that here: https://facebook.github.io/react/docs/pure-render-mixin.html

"IF your React component's render function is "pure""

nothing stops you from writing impure rendering functions. You can delete and manipulate elements at will.


Yes, but thats not how the render function is supposed to work. Its a function from state/props to a VDOM tree. In contrast, direct DOM manipulation is meant to be stateful.

For some reason, everyone always likes dealing with absolutes. Thats not how things work

* "Tests wont exhaustively check everything!"

Yes but they exercise the common cases, and the cases where the code will trip-up in real use are rare if the code is decently covered with tests.

Yes, its still possible to encounter edge cases. If it looks like that might be the case, add fuzz testing and property testing too. Pick the tool.

* "Types wont detect all errors!" -

Yes but detecting some errors is still useful. They mostly track dependencies between parts of the codebase: they determine how modules talk to eachother. This is useful, especially when I'm reorganizing code.

Also, its exactly where unit test fail to help, due to mocks: if I change module M, i don't know whether its dependencies are affected or not without looking at all of them and checking their mocks of module M. The situation gets even worse for second-level dependencies, and so on.

* "Unsound type systems are useless!" - No they are not. Not if its possible to isolate unsound usage and "hand-prove" it by carefully checking it. There is still value there: you can write things that the type system doesn't know are sound and hand-check them (by paying with more effort), or you can write things that it does know are sound, and enjoy the type system's ability to help you avoid errors.

* "Soundness isn't very important" - It depends. Is this unsoundness pervasive, like the null/undefined unsoundness? Maybe its useful to fix it then.

There are no absolutes.


> Yes, but thats not how the render function is supposed to work.

If you weren't supposed to do it they wouldn't give you functions to do it.

I'm not 'dealing in absolutes' I'm applying the definition of pure to what React is, and it isn't pure.

The rest of your post I don't follow, you're just talking to yourself, I haven't made any of these claims.


Yeah I suppose I am talking to myself. I'll try to stay on topic.

With the browser DOM model, end-users perform the DOM mutations. This generally means that they must keep the application state in sync with the DOM state, manually.

React's VDOM model encourages pure render functions, since a new VDOM is constructed every time and mutations are performed by React itself.

Also, nothing stops you from writing impure functions in PureScript either. You could define FFI functions that claim to be pure but aren't. I guess PureScript isn't pure then? Oh, and Haskell isn't pure due to unsafePerformIO. So nothing is absolutely pure; the question is what style is generally encouraged by the design of the framework/language, and to what degree. (there are no absolutes)

And PureRenderMixin isn't default because it does a shallow reference comparison on props/state, which only works reliably for immutable data structures. If all JS datastructures were immutable, it would've been used everywhere. However thats unrelated to whether `render` is pure.


Well, yes, but it's commonly written in the functional style.


I agree (from my experience). That's mostly the fault that even with static types interface design (e.g. in Java: public methods and public classes) is still hard and most developers are not good at it.

For me, a lot of the Spring classes are designed very well. When working with them I don't often need to look into the source code. Very often just looking at the methods (by using autocompletion) is enough.


maybe its just what your used to. Most of my time I code in Java (and a bit of Scala) and i only look at the source code as a last resort. This is not really possible with JS. But i imagine with a lot of background in dynamic languages you instinctively look at the source-code and therefore not use the types that much.


I looked at SO much Java sources because the method signatures weren't complete enough.

I would never have been able to integrate netty into our game servers that optimally with only the docs as reference for one. Yet its documentation is really, really good. I still wanted to know its internals in order to hit the fast paths.

Whether you're using static or dynamic types, the very same holds true to build robust software: understand what you're doing.

Managing complexity and reducing state will always be the biggest factors to quality, regardless or type systems.


Well, considering the number of dependencies a typical web project has, I can tell that I'm far from understanding the internals of every library used in our codebase. I mean, of course you'll want to do that in some cases where performance is really important, but generally speaking type signatures and docs should be enough.


i din't say that i don't look at source code, but not intuitively. I look at it when the method is very confusing, or i have to optimise one path, it is undocumented and important etc. What i wanted to say is that types give you a pretty good first intuition to what the method does and how (including exceptions). They help me navigate my way through the code, especially with DSL like the excellent jooq (http://www.jooq.org)


...And I hate java (for perverting OO, and being annoyongly verbose), and come from a highly dynamic background.

It's ultimately a matter of preference, though.


not that java is my favourite language, i would even say that i despise it. But its here to stay and the discussion was about shitty static type-systems where Java is the poster-boy ;)


It's not even the shitty type system: C's is arguably even worse.

No, it's the fact that it's effectively the new COBOL.


Java: the language so ugly it has to wear a (IDE plugin) bag over its face while you're doing it.

Yes, I'll go have that talk with H/R now...


I think mschulze means he cannot even be sure what the function returns without having to read the source code. There could be comments but they may be outdated or incomplete. In statically typed languages you can look at the function signature or rely on the compiler errors.


Yes but my point was that this is very incomplete information to do engineering with. You're still going to look at the source to learn what side-effects are present or how your arguments are used.

Not taking these details into account will be the source of most bugs :)


A good type system will expose the existence of side effects. However, it is true that good type systems are very rare in industry.


Unless you're working with a strict sound type system, you only have a little more information: you know the properties and methods of what is returned, but you don't know what state its in. So you won't typo a method name, but you still might be dealing with errors from shit that cost cast incorrectly, nulls (even with strict null, since it wasn't there from the start you will still deal with it), arrays not containing what you thought they did, etc.

Anything but the most trivial program will still require you to investigate. Once you're familiar with a piece of code you can start making assumptions, and the types get you a little closer to that a little faster.

I've worked on multi million line mono-repo pure javascript with zero tests with hundreds of devs working on it, and it worked fine (in fact, we were moving more stuff from the Java/C# code into JavaScript to reduce overhead and friction). If you have tests on top, or if your devs are actually good, its just easier/better.

Now, I'm not saying a proper type system doesn't add value. Thats a whole different argument. But any team who can build good software in a static type language can do so in a dynamic one. Its just a different set of tradeoffs.

And aside for strict sound type systems, you need (almost) t he exact same amount of unit tests either way. If you don't have tests you're not writing good software either way.


> Unless you're working with a strict sound type system, you only have a little more information: you know the properties and methods of what is returned, but you don't know what state its in. So you won't typo a method name, but you still might be dealing with errors from shit that cost cast incorrectly, nulls (even with strict null, since it wasn't there from the start you will still deal with it), arrays not containing what you thought they did, etc.

You're throwing out (or, rather considering the tricks you can pull in Typescript, hugely reducing) entire classes of issues when using a simple type system.

> I've worked on multi million line mono-repo pure javascript with zero tests with hundreds of devs working on it, and it worked fine (in fact, we were moving more stuff from the Java/C# code into JavaScript to reduce overhead and friction). If you have tests on top, or if your devs are actually good, its just easier/better.

I've worked on a huge PHP codebase once, with 10 developers working on it and no tests. I would have given somebody else's right hand to have a type system back then.

> Now, I'm not saying a proper type system doesn't add value. Thats a whole different argument. But any team who can build good software in a static type language can do so in a dynamic one. Its just a different set of tradeoffs.

The point is, the cost of adopting Typescript is frankly, very low, from my point of view, considering the huge benefits it has over raw JS, it's all win.


I've worked on a lot of big projects with both dynamic and static languages. I think what a lot of people that are used to static languages don't realize is that dynamic langauge users typically live inside of some kind of repl. The repl gives you immediate access to the thing returned and lets you inspect it and play with it. This serves the same purpose, albeit in a different way, as the IDE for a langauge like java or c#.


That's a good explanation, thank you. My experience in big projects with dynamic languages boils down to Angular which I didn't find very REPL friendly.

BTW, with IntelliJ and its debug mode for Java we almost have some sort of weird REPL. By pressing Alt+F8 one can, during a breakpoint evaluate an arbitrary Java expression while accessing the values in scope. I use it a lot, despite having my types.


I use that in Intellij all the time, but it's very limited to something like pry in ruby.


Install Batarang in Chrome. the "$scope" objects are attached to the browser DOM, and the tool adds another tab to element inspection that shows you the data attached to each level, as well as references back up to enclosing levels.


Angular was a Bad Idea. For so many reasons. I'm barely acquainted with it, but I could already go on about all the problems I had, which other, more experienced people also had.

And I do a lot of Lisp programming in Emacs, where the support for REPLs and livecoding is ungodly. Really, really good.


> If a colleague writes a function/method that returns something, in JS, how do I know what it is?

Typically you have a set of standards for how things get returned. 'isSomething()' returns boolean, 'getSomething()' returns an object, 'getSomethingClassName()' gets a model representing that, etc.

Overall it's really the same as static: you usually have something in the function definition that makes it intuitive what it returns. The fallback is documentation directly above the function's implementation that should describe it.

When you run into the "well what does the object contain that gets returned?" situation then dynamic and static have the same issue: you have to go to the definition to get that information.


Free your mind. Drop all that getXXX setXXX Java-esque noise.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

http://es6-features.org/#Proxying

Otherwise, yeah, I can hardly make heads or tails of most "self documenting" (i.e. - undocumented, per SOP) static typed code.


> Free your mind. Drop all that getXXX setXXX Java-esque noise[...]

You confuse my statement. I was not referring to things that should be meant as synchronous properties. These are methods that do more like make an AJAX call to a server. Those that return promises or take in callbacks would be awkward or impossible to force into a property or proxy.

I was merely referring to the act of making code as obvious as possible for its intended outcome.


Gotcha. Sorry about the tangent, as you were primarily discussing grokking what the names of things were doing anyway.


For me, it's not even about "typing" or even "checking for errors as you type". The killer feature is: almost never having to read library documentation. You type the code, and get suggestions for all the properties and methods available, along with all the possible arguments you are supposed to pass. Saves you a TON of time and context switching, so you can focus better on the task at hand.

That alone makes TypeScript worth the trouble IMHO.


> You type the code, and get suggestions for all the properties and methods available, along with all the possible arguments you are supposed to pass.

Only if the library itself is written in Typescript or the ambient definitions are perfect. Not necessarily a detractor from the language, but still a practical time sink given the current state of external typings. It's definitely getting better, but it's still quite far from a minimal nuisance.


The "intellisense" crowd always kills me with this: I don't really know what this does, but the IDE suggested it and I'm just going to run with it!

What could possibly go wrong?

This is of course less ridiculous if some documentation about each routine is displayed as you up and down arrow through the choices.


Same here, I hate it when I land in a TypeScript codebase where they followed "clean code" and "best practices" and have nice OOP abstractions everywhere.. its always a kludgy monstrosity that yields everything but actual agility or performance.

The whole "lets use classes in JavaScript" movement makes me very sad. Its as if today's web developers are now rediscovering the 90's and all the mistakes that were made back when OOP was the new shiny thing.

I get WAY more annoyed fighting with TypeScript's type-system than fixing the rare runtime type error, which is usually trivial to find anyways. This all feels like a very superficial and inefficient way to achieve correctness.

The real hard to find bugs come from state and complexity, both of which are completely ignored by static type systems. Instead I see the exact opposite: the new shiny typed abstractions introduce so much state and complexity that any advantage gained by having static types is lost there.

I probably sound very pessimistic here; the older I grow the more I appreciate Alan Kay's quote about the internet and the web for being so damn spot-on.


It's important to not conflate static typing with OOP. If you think about static typing only in terms of OOP, of course you're not going to like it - classes are not the right abstraction for many problems.

The TypeScript compiler (which is written in TS) itself uses zero classes. There's no need to use classes to get static typing. If you're writing TS the "right way", you write the JavaScript you would have written anyway, and add type annotations to create contracts and descriptions of behavior.


TypeScript has an okay type system, but it has a very "C#"feel to it. I don't mean from a technical point of view, but the way its advertised, the way its documented, the language used in the terminology, and obviously, the company behind it.

So of course, when you give TypeScript to someone who doesn't have a strong "normal" JavaScript background, they'll jump straight in what they are comfortable with and go full enterprise Java on it.

Note that even vanilla ES6 had this problem, just to a lesser extent. All languages have shit like that... JavaScript itself does (we're just used to "the good parts" after so many years, but it took a long time.

The fact TypeScript provides some of those construct doesnt mean we need to use it, but it means less experienced teams will.

I'll never join a company that uses TypeScript unless I get to see the code base first.


> TypeScript has an okay type system, but it has a very "C#"feel to it. I don't mean from a technical point of view, but the way its advertised, the way its documented, the language used in the terminology, and obviously, the company behind it.

It has some very un-C# like features: https://www.typescriptlang.org/docs/handbook/advanced-types....

I am always surprised when people in JS-land say they don't like types when every major framework then goes on to recreate 80% of the framework of types rather than work in a truly prototype-oriented world.

> I'll never join a company that uses TypeScript unless I get to see the code base first.

Given the way those sorts of things work, you're basically saying you don't want to work with typescript because someone might use a feature you feel uncomfortable with. That's good to get out of the way up front, but it also projects the image you have a huge chip on your shoulder and assume everyone else is an idiot who doesn't understand things as well as you do.

Wouldn't you like to work at a place where you discover something new? I am sick to death of being the subject matter expert, myself.


I specifically said that I didn't mean from a technical point of view. I know full well about typescript's features :) I generally try to avoid talking about things I haven't tried extensively.

And for your second point, I love to learn something new! But that is specifically something I've had to deal with far too many times already (not just with TypeScript), so it wouldn't be new. And it is quite common these days for companies to show you their code when they get near offer time, or to discuss their architecture and coding philosophy, so I very rarely have surprises on that front anymore. Doesn't mean I don't learn new things. I don't avoid things that haven't burnt me yet. Heck, even if they did, it might be because I didn't do it right. But there's only so many times I can get burnt before I start avoiding certain things :)


> I generally try to avoid talking about things I haven't tried extensively.

I don't mean to press this point too hard, but you feel comfortable offering a dissuasive opinion on something but not "talking about it"? I don't know how to interpret that.

> But that is specifically something I've had to deal with far too many times already (not just with TypeScript), so it wouldn't be new.

I don't know what you mean by this either, I'm sorry.

> And it is quite common these days for companies to show you their code when they get near offer time, or to discuss their architecture and coding philosophy, so I very rarely have surprises on that front anymore.

I certainly think the second half of this is true. I think it's quite rare for companies to actually share real production code in any significant volume, unless of course it's already in the open.

> But there's only so many times I can get burnt before I start avoiding certain things :)

Again... what do you mean? Are you implying that Javascript has burnt you? Or Typescript? Or you won't use technology funded by Microsoft?

I'm sorry, I read your post several times trying to understand your intent, but I ended up with more questions than I started with. That's probably on me.


> I'll never join a company that uses TypeScript unless I get to see the code base first.

That seems reasonable. But wouldn't the same thing apply to Javascript? Terrible Javascript code bases are very common.


Generally the terrible JavaScript is stuff you don't have to argue until you're blue in the face to avoid. A lot of people have bad JS code base, but they know they are bad and are trying to do better. That's fine by me.

For this particular stuff, if a team is really into the whole OOP/classes things, it's not like a small feature like arrow functions vs not, or semi-colon vs not... it will dictate the entire architecture of the entire code base, and it's easy to detect, so why not?


It's interesting that TypeScript often gets lumped into "OOP" when a few functional projects like RxJS and Cycle use it. Are their codebases also OOP?


I think typescript development is driven more by functional languages, than OOP languages.

However, they do provide some syntactic sugar for OOP, which is useful if you have a JS codebase that is using OOP, because if nothing else, it provides a standardized method of creating objects and classes.

Unfortunately, because most devs are comfortable only with OOP and since typescript is amongst the easiest ways to do OOP in JS, a lot of Typescript code in the wild tends to be OOP heavy.


The Typescript compiler (written in Typescript) uses no classes.


Actually, yes, TypeScript uses OOP patterns like classes and interfaces:

https://github.com/ReactiveX/rxjs/blob/master/src/Observable...

But they also use the pipeline operator (::) to chain together methods in a way that's effectively functional.


Interesting! More interesting is that apparently the TS compiler itself uses no classes.

I just think jeremiep is conflating static typing with Java-style OOP and "design patterns".


TS has some functional leanings, but there are probably a good many users from enterpriseland who see the "class" keyword, and have their eyes glaze over with the assumption that they already know everything, as the continue to create monstrosities in the name of best practices.

A little common sense goes a long way.


> The real hard to find bugs come from state and complexity, both of which are completely ignored by static type systems. Instead I see the exact opposite: the new shiny typed abstractions introduce so much state and complexity that any advantage gained by having static types is lost there.

That's just not true. If you model your state and its transitions as types, then it's entirely the case that your type system can help you out. It can also force you to write down an explicit & precise guide to said system, which will help readers.

> The real hard to find bugs come from state and complexity,

No one argues that this is the case, but what's key to understand is that people still make the stupid mistakes. People like you and me. I've got over a decade of experience, I've shipped code in common lisp, javascript, ruby, python... you name it in the who's-who' of dynamic languages and odds are I've shipped code in it. And I can STILL make silly little type errors.

I'm tired of this collective fiction that we're all so awesome that we don't make those errors. Removing those is important. It lets me think more about the interesting parts of the code and trust the computer to do the tedious bits for me. That's what automation is all about, isn't it?


    The computer industry is the only industry that is more fashion-driven than women's fashion.   -- Larry Ellison
These cycles come and go. Sometimes static typing is hot, sometimes dynamic typing is hot. Best bet for pragmatic people is to figure out what works for you and run with it.


Indeed. But I'd quote Kay, not Ellison, myself. Personally, I wouldn't trust Ellison further than I can throw him.


I don't really get why flow is okay when TS isn't? TS is gradually typed, you can work with unknown objects just fine and you don't have to dive fully in on your code. Flow and Typescript actually have very similar approaches.

So why is Flow better? Have you used Typescript and Flow recently and done a comparison?

> But I always see a flock of comments saying that they couldn't possible live without static types, and thanking TS for taking them out of the hell of dynamism, and wishing there was something similar in Ruby/Python/whatever. > I don't really get that.

Because we're really tired of writing the same errors over and over. If it's just me, I can burn through a bunch of clojure code and I'm fine. But the instant I and someone else start to collaborate, subtle problems start to creep in.

What's more, so much of my job these days is about serialization, deserialization, data validation, and error handling. None of my customers have any patience for buggy software and sites. And quite frankly, they shouldn't be.

Static typing just makes these tasks easier. It makes them easier because it reminds you when forget. It forces you to think about every edge case that it's aware of, and it forces you to say something you mean and if you change that opinion, you need to make sure the code reflects that change.

You talk about static typing like Java and C++ are your experience. Using Typescript (or flow) or a modern FP like Typed Racket, Ocaml, F# or Haskell where the type systems enable new means of expressing yourself is wonderful and refreshing, to me.


Flow has better inference and is actually pursuing a sound type system.

const f = function(a) { return a * 3; } f("stuff");

this will produce a runtime error with TS, Flow will fail to compile it.

People here think that choosing a statically typed language necessarily means you need to type annotate everything, and thats not true. In Haskell and Elm you don't have to explicitly write any types if you don't want to.

Elm doesn't produce javascript that contains runtime errors, and Flow is pursuing a similar goal.


> const f = function(a) { return a * 3; } f("stuff");

Right but the instant you annotate a, it knows and gives you a good error.

The reason TypeScript did this, to hear them tell it at Build, was because (unlike Flow, although they did not say it) they're a transpiler with a mission to actually make the tool usable with real world javascript.

That's why, for example, type errors don't block code emitting but syntax errors do. It's in service of making a usable toolchain. Flow can be more aggressive because it's not making these decisions (its part of a larger configurable toolchain).

Neither Flow nor Typescript can actually project soundness onto Javascript. Mentioning that is a giant red herring. So long as compatibility with base ecmascript is offered there is code which cannot be verified as sound or unsound without the execution context at hand.

Typescript takes the approach that types are actually a useful tool for expressing concepts succinctly and safely and offers that first. Flow takes the approach that aggressive type inference is a phenomenal way to detect (potential) errors in javascript code, and takes that approach. Neither is wrong.


> Right but the instant you annotate a, it knows and gives you a good error

unless you annotate it with :any

> Neither Flow nor Typescript can actually project soundness onto Javascript. Mentioning that is a giant red herring. So long as compatibility with base ecmascript is offered there is code which cannot be verified as sound or unsound without the execution context at hand.

I don't see how you can say that. Flow can absolutely create a 'sound' type system on top of javascript. Elm transpiles to javascript and has a sound type system that doesn't produce runtime errors. Flow has different syntax but it restricts the type system in a similar way.


Fair enough.

The reason I like Flow better is that it's better integrated into the rest of the JS/Babel ecosystem, so it gets out of your way to a greater degree than TS when you're either not using it or want JS ecosystem integration with JSX/whatever.


The problem is, Microsoft can't really do this. If they hired the creator of Babel, then proceeded to add TypeScript parsing support to it, they would immediately be accused of trying to "embrace, extend, extinguish".

On second thought, that might not be such a bad idea. Babel already parses some type annotations, why not also add the little extra syntax supported by TypeScript?


Babel has a plugin architecture. MS could implement the TS extensions as a Babel plugin, and it would integrate with any other Babel plugin. That's what facebook did.


Yeah, it might be a good idea. A parser plugin to parse valid typescript, and a strip-types stage that strips them out.


...And that's what Flow does.


> JS/Babel ecosystem

I mean, sure. In that when you use typescript you probably don't need/want Babel, as most of the ES6 features you want are part of TS already.

> JS ecosystem integration with JSX/whatever.

Typescript supports both react and non-react JSX natively, so perhaps this isn't a pain point anymore?

Also: you get types. Good types are great.


Well, yeah, but what about whatever thing comes along in Babel that will make your code an order of magnitude cleaner?

What about all the tools that work with babel, rather than TS?

And from what I saw, Flow has a type system at least as good as TS's. Am I wrong?


> Well, yeah, but what about whatever thing comes along in Babel that will make your code an order of magnitude cleaner?

Why not watch http://channel9.msdn.com/Events/Build/2016/B881 and tell me what you think. It sounds to me like they're dedicated not only to being on that, but to be part of the conversation going forward.

They're already taking the well-formed parts of the next 2 iterations of JS, and adding types on top.

> And from what I saw, Flow has a type system at least as good as TS's. Am I wrong?

Flow has a type system that is "as good" at troubleshooting errors within the existing javascript ecosystem, as I read it. And that's good. TypeScript, unlike flow, makes newer features available with the type data.


Man, I feel like the only one here who doesn't really like static types. I like dynamic typing just fine (it's crazy, I know: it must be the lisp influence).

I was a Smalltalker professionally for almost 15 years. Let me say this about that: You don't absolutely need type annotations. That said, the information clearly has value in large projects, especially when they've been modified in production for a decade or longer. There were a couple of times when we really wished we could do certain refactorings, but we were blocked because we couldn't be 100% sure of what would end up in certain instance slots.

Keeping your types straight by clear thinking and convention in Smalltalk is about the same cognitive load as wrangling the type system of C++ and avoiding the gotchas there. The difference is that the consequences in the former case are exceptions that show up in production, while in the case of C++, these become coding/dev-testing/debugging gotchas. In exchange for that, you could move considerably faster while breaking things in Smalltalk.

There are also ways to have your cake and eat it too, in 2016, with regards to both type annotation and dynamic environments.


A bit off-topic, but I'm curious what your experience with Smalltalk was professionally.

I've always viewed it with rose color glasses. It looks like a wonderful environment to work in, but I'm sure I'm missing something. It seems like Smalltalk was lightyears ahead with it's tooling.

What do you work in now, do you find lack of tooling to be challenging?


There's clearly a set of lower expectations when it comes to tooling. Some of the menu-activated refactorings in VisualStudio 2015 amount to: We'll move text around for you, but you're kind of on your own. Whereas in VisualWorks Smalltalk, all of those came with iron-clad guarantees.

I could whip up a custom SQL-query-like query of my loaded code, then have that pop up in a browser. Then I could compose that with another search or another custom query, then maybe even write a syntax-driven automated rewrite of the resulting browser contents.

I currently work in C++ using Visual Studio. It's not that I lack certain tools. It's that those tools are themselves lacking. They are slower, less useful, less nimble, and less dependable than what I'm used to. Mostly, they are slower. When refactoring, it's like I'm using a Dremel, a hand-saw, and cheap bench grinder, where I really should have a full shop with a full set of tools, CNC machine, a lathe, and a 3D printer. Refactoring is literally 10X slower, due in large part to the higher cost of entry to hacking on programming tools.


Well, yeah. Lisp/Scheme, Python, and JS all have really good type annotations now.


Do you tend to work alone? I don't really mind not having types in my own code because I know what and where everything is (at least until I have to come back to some old code). But I definitely want static types with tools that navigate quickly in other people's code because I really don't have the patience to manually reverse engineer it.


I do, but when I read others' (typed) code, I don't often find the types helpful...

(Although that's usually C code, so that might have something to do with it)


TS's typing is opt-in and it'll infer any (i.e. whatever) if you don't specify a type or it can't be inferred easily. Gradual typing is the best of both worlds here: you can quickly code up something and then later add types as you wish.

Personally, I like types because entire classes of errors and bugs no longer apply without me having to think.


You're like this guy who doesn't like seat belts because he finds them uncomfortable :-)


Well TypeScript is sort of "optionally typed" (variables can have a type of `any`) it's also superset of JavaScript so any valid js is valid ts.


Dynamic typing is fine until you have to maintain someone else's code. Then it's like pulling nails to get any certainty about how the code runs and productivity tanks.


It's not about developer convenience, it is about performance. There are limits to the black magic that can be done with dynamic types to eke out performance that can be blown past with static types.


That has nothing to do with TS, which compiles to JS, which cannot make any of those assumptions.


JITs help a lot with that.


You got it exactly the opposite way.

Because JITs do type inference and compile specialized code with an assumption type doesn't change, they stop working when type(s) change(s) dynamically. When that happens, JITs need to deoptimize code, which leads to a dramatic slowdown.

In other words, changing type is the case where JITs don't help and their performance nosedives, because it breaks the underlying assumptions on type stability. Type stability is needed to generate compiled binary (x86, ARM, etc.) code.


No. Perhaps I wasn't clear.

The code running under a JIT will behave like the static typed code when the code (and data) allows it while the programmer didn't have the additional burden of doing the type analysis for the computer.

You may be confusing dynamic typing with weak types.

Also, it's perfectly fine for the JIT to generate multiple code paths that are invoked depending on runtime types even when the source code declares a single one that acts on multiple types.


Another Emacs JS dev here. I find Emacs + Tern works very well for me.


Cool. Is it better than JS2?


You're not alone, I'm fine with dynamic typing. And I'm sure lots of people were fine before TS came.


You are not alone.

/me taps your shoulder.


I really wish that MS would release typescript as a collection of plugins for babel that would handle only one thing at a time (eg, the type system). Having my production build, es6 transpiler, type system, JSX compiler and so on (including a bunch of features I would rather didn't exist at all) all in one package feels like a failure of separation of concerns.

I understand that people find Babel's plugin ecosystem confusing and intimidating (it is), but I don't think a separate monolithic typescript that reimplements popular babel functionality is the answer.


I'm actually glad they release TypeScript as a completely integrated and standalone solution.


It definitely has advantages. But I don't think using babel precludes shipping a binary with a standard pre-built config.


I agree, the javascript ecosystem needs more fragmentation.


I suppose the problem is that I see typescript as the fragmentation. If MS leverages babel (they can even keep shipping TS as their own thing if they want, I just want them to provide babel plugins), we can all use that and focus on making it as cross-compatible and streamlined as possible. (Well, really, we can focus on providing a single well-documented on-ramp to new javascript developers, which I think is the main problem and the one MS set out to own with typescript.)

Right now, we have the typescript ecosystem, the babel ecosystem, and the other wannabe ecosystems. If I like Typescript's type system but want to use babel for async-await (for instance, I'm aware it's in TS next), I'm basically SOL. Babel has more end-users (AFAIK), generally has the first/only implementation of <feature>, and my impression is that the surrounding development community is larger and more active (typescript stuff tends to come down from On High).

For instance, you can use https://github.com/gcanti/babel-plugin-tcomb to get run-time type checking with babel/flow for free. That's really cool! Unfortunately, the same is not possible with typescript (AFAIK), because MS decided that was out of scope. If Typescript was offered as a babel plugin, somebody else could implement it for typescript and we could all be happy.


If you implement TypeScript as a Babel plugin, you would likely lose all the superb IDE support that TypeScript has. Which is one of the major selling points of TypeScript IMO. When your language is unstable like in a typical Babel setup, any number of features might be on or off, the static analysis done by IDEs becomes almost impossible. Performance would be affected too.


Microsoft has absolutely done an amazing job with typescript IDE integration. But are there any end-user IDE benefits to typescript over flow/eslint? (Not being snarky.)

I've been using both on separate projects (with MS IDEs) and haven't noticed anything major.


The design of TypeScript is explicitly so that it can provide a good API (called "language service") to IDEs and other tools. And not just "give me all the errors/warnings in this file" but also to give detailed information about the types at specific positions of the source code, and the whole design is so that it can efficiently recheck a whole project if you change one part of a file. One of the lead engineers of TypeScript talked about that in one of his techtalks (can't find the link right now).


im a Flow fan, but Flow's IDE support is pretty bad. WebStorm only souped it up recently, and aside for that, outside of Nucleide (and even there!) its pretty awkward/slow/clunky and in many cases downright buggy.

TypeScript's type system is very bleh, but its IDE integration IS pretty good across many editors (not just VSCode)


I've had good experiences with https://marketplace.visualstudio.com/items?itemName=rtorr.vs... so far, but perhaps I've gotten lucky. When I first tried flow out a few months ago I was also very unhappy with the tooling.


just tried it again...its better than last time, for sure. Still weak in the refactoring department though.


I think people like not having the usual Babel plugin/config + setup soup. There's value in all-in-one solutions with clear limitations. For example, TS doesn't implement JavaScript stuff below stage 2 while many devs liberally use stage-0 and stage-1 features with Babel. Some prefer TypeScript's way.


Totally. I tell new devs to use typescript. But I don't think using babel precludes shipping a binary with a standard pre-built config.


Babel is temporary solution and we should all remember this. Babel should ideally be obsolete in 2-3 years when IE11 will get eradicated by MS. Babel imo is pretty bad idea, I think its name imply this as well.


This was discussed a couple days ago.

https://news.ycombinator.com/item?id=12538106


I can't see how this would help things. Trying to separate it all out would surely lead to lowest common denominator support in terms of strong typing if things were optional (hard to design a type system when you don't know all the features) and create further JavaScript fragmentation.


Healthy competition to the Babel nonsense is good for all of us.


> In TypeScript 2.0, null and undefined have their own types which allows developers to explicitly express when null/undefined values are acceptable. Now, when something can be either a number or null, you can describe it with the union type number | null (which reads as “number or null”).

Great news, but I suspect it's going to be pretty difficult to migrate large codebases to account for this properly, even with the help of `--strictNullChecks`. Sounds like days worth of tedious work analyzing every function.


Yes, although the same can be said for the "no implicit any" flag when migrating from code bases EcmaScript. They seem to be doing a pretty good job of supporting both legacy and greenfield projects.


Yes, I tried "no implicit any" and got nothing working. Problem were mainly 3rd party libs with out-dated, bad or no type definitions.

Is it even possible to use these flags with production code?


We've removed nearly all the implicit anys from DefinitelyTyped, so if you're getting definitions from there, you shouldn't see any.

We don't have good data on this but my perception from talking to people on GitHub is that the vast majority of people using TypeScript run with 'no implicit any' on once they get their codebases converted.

(I'm on the TypeScript team)


And even if noImplicitAny in 3rd party libraries is not honoured you now have: skipLibCheck which will limit checks to your own code. Details here: https://www.typescriptlang.org/docs/handbook/compiler-option...

I believe it's actually a perf gain to run with this set (but I'm not certain).


Nice to read :)

Had some problems with React/JSX back in the days.


That behaviour is only enabled if `--strictNullChecks` is set to true. Otherwise, by default all types include null/undefined just like in TypeScript 1.x. So it's entirely opt-in.


But it's all or nothing right? If I write a new component in a pre-2.0 codebase and want strict null checks, I can't get them.


I saw some comments in TypeScript code-bases, that excluded parts of the code.


At my work we migrated our codebase (a few hundred klines at the time, I think) with not too much effort. It helps that enabling the flag makes everything more restrictive, so the compiler only flags the places that you need to go back and add the |null bits.


Agreed. But worth it, at the end of the day, wouldn't you say?


Highlights:

* npm replaces typings/tsd

* non-nullable types (has to be switched on)

* better control flow analysis (à la Facebook Flow)

* read-only properties


Huge TypeScript fan here - been using it since its 0.8x days. And I'm very interested in the new --strictNullChecks compiler flag. But I'm trying to implement that on our current codebase, and I'm coming to the conclusion that it's still a bit premature. There are a lot of very common and harmless JS (and TS) patterns which this breaks, and for which it's been difficult (for me at least) to find a workaround.

Turning on --strictNullChecks flagged about 600+ compiler errors in our 10Kloc codebase. I've addressed about half of those so far, and I can't say that any of them have actually been a real bug that I'm glad got caught. On the contrary, because of the weird hoops it makes you jump through (e.g., encodeAsUriComponent(url || '')), I'd say that our codebase feels even less clean.


One counterintuitive observation about introducing stricter type checking into an existing codebase is that it rarely finds bugs. Why? Because the existing codebase typically "already works", in that issues that the type checker might have found were already discovered through automated (or manual!) testing.

The real value of more strict type checking is when writing new code -- you won't need to spend as much time discovering bugs in development or writing tests for issues the compiler is catching.


Good point. And I can see that I would have made different (and probably cleaner) design decisions in certain places if strict null checking had been a part of our code from the beginning.


Hmm...

    $ npm view typescript 'dist-tags'

    { latest: '2.0.3',
      next: '2.1.0-dev.20160922',
      beta: '2.0.0',
      rc: '2.0.2' }
Yet https://www.npmjs.com/package/typescript says

>typescript published 5 months ago >1.8.10 is the latest of 447 releases


I guess that page just hasn't been updated yet. npm i -g typescript@2.0 will give you 2.0.3


    class Person {
        readonly name: string;
couldn't they have just reused `const`?


`const` applies to a binding; `readonly` applies to a property. The difference is important because you can alias a mutable property through a readonly reference (thus observing two different values from the same reference if someone with a mutable handle on the object changes it), whereas a const will always have the same value because it's an immutable reference to a particular value/object.


ah i guess immutable aliasing is useful. then it's more powerful than const and can replace it wholesale, bindings included.


From my understanding, const would mean the property would be immutable even within the class, where as readonly means it's only immutable when used from outside the class but still mutable inside the class.


> "where as readonly means it's only immutable when used from outside the class but still mutable inside the class"

Small correction: The readonly modifier means you can initialize the variable, but can't mutate it (even within the same class). For example, you can initialize a readonly field inside a constructor, something you can't do with const.

Some good docs on it here: https://basarat.gitbooks.io/typescript/content/docs/types/re...


It appears you're right:

> Read-only properties may have initializers and may be assigned to in constructors within the same class declaration, but otherwise assignments to read-only properties are disallowed.

Thanks for pointing that out.


const means a completely different thing depending on what language you come from (even JavaScript). I think readonly has a much clearer meaning.


I've got to find the time to play and get typescript set up figured out. I've had several false starts, always running into duplicate type definition issues and similar problems - looking forward to see if the new @types from npm help things.


Does Typescript have a facility to support partial function application?

Say I have a function of arity 4, and want to bind / partially apply (some might say "inject") 2 arguments to it to create a function of arity 2, can TS infer the types of the remaining arguments, or, that the result is a function at all???

I use partial function application MUCH more than classes in the JS code that I write. There just seems to be less to need all that "taxonomy" related refactoring.

"Stop Writing Classes", "Executioner" in "The Kingdom of Nouns" (not!), and all that sort of thing :-)


For those of you unfamiliar with partial function application, it's a good way to replace many classes that consist of nothing other than a single "do the work" method and a constructor or setters for the configuration/dependencies with a single function.

You put the configuration / dependency parameter(s) first, and the more "volatile" parameter(s) last. Rather than having a constructor call, you partially apply the things you want pre-bound (config, deps) to create a new shorter function that acts as the "do it!" method.

E.g. - write a function to send emails. Put the "reply to" parameters first. Partially apply that data. Use the resulting function to send emails to specific people. Bind on the distribution list name argument. Use that function to send alerts to those recipients. Bind on the content of an alert. Use that to send an alert when needed, without having to come up with any of the input, just the 0-argument function. Overloading, alternate constructors, subclasses??? Screw that. As long as the parameter order is reasonable (least to most volatile), there is seldom anything to be "refactored"

"Currying" just means that you apply a single argument at a time, until you get down to an "arity 1" function, after which the final argument runs the original function with the last remaining argument, rather than returning an "arity 0" function. Here is an example library that does A LOT of currying: http://ramdajs.com/docs/

If I apply/bind a function to my higher order function, is that dependency injection, or subclassing? Who cares.

I like arity 0 functions. They make nice event handlers.

I have been gradually converting to Javascript for the last 8 years. My paradigm has definitely shifted. I know how miserable static OOP is, and won't be going to my grave not knowing :-) (here's the quote: https://www.facebook.com/groups/nodejsis/permalink/142940052...)


I suppose this is orthogonal to compile time types, but I had to write my own utility to support PFA "decoration" of functions. It of course knows nothing about the number or type of arguments in the original function. (I usually write JSDoc comments about resulting intermediate functions if they leave the nest)

For TS to do this, the compiler would need to supply the "apply"/"bind" feature and track that a function goes in, and the list of argument types, so it can check what is applied and track the types of any remaining arguments. Doable, but if it's not built into the compiler, I have to start running a transpile process that buys very little for much of my code.


Sounds like function foo(f: function<T1, T2>(T1 x, T2 y), bindY: T2) { return (x) => f(x, bindY); }

This will be type safe and return a function<T1>(T1 x).

(Disclaimer to typos and erros for typing on my phone)


Similar to that, yes - you have a higher order function, "foo" in this case, that accepts a function as an argument, and returns another function.

FWIW, you want to have an operation to bind the first (or first N) formal parameter to a value, and you want to be able to have an arbitrary number of remaining parameters.

Whatever facility would be in place needs to allow for N remaining formal parameters, of various types, not merely do the ("generic" / templated / type-parameter) recipe for one additional parameter.

I am not a Haskell or F# programmer, but maybe the TS team wants to look at what those languages do.


>>> "Stop Writing Classes", "Executioner" in "The Kingdom of Nouns" (not!), and all that sort of thing :-)

Are these references to blog posts?



I want to hear more about this technique. I will email you.


Consider this: http://ramdajs.com/docs/#sort

Say I want to sort a list of objects/records that have a "name" field by name. I can compose some functions to do this, and use the resulting function where needed (regardless of the input object list "type(s)", as long as it/they quacks back with a "name" property/field).

I'm going to assign some functions to intermediate symbols, but that's not strictly required, since functions are an expression/value like many other things.

    var name_comp = function( l, r ) { return l < r }
    var sort_by_name = R.sort( name_comp )
    // alternatively: ... = R.sort( function ( l, r) { return l < r } )
    ...
    var old_list = [
        { name: 'Middle', foo: 'bar' },
        { name: 'Zero', bluk: 'phooey' },
        { name: 'Alpha', answer: 42 }
    ]
    ...
    var new_list = sort_by_name( old_list )  // ... Alpha ... Middle ... Zero ...
In general, the curried arguments can be primitives and objects, as well as functions.

The Ramda library is primarily geared around taking common "collections" types of operations and chaining them together. It has other FP "mathy" stuff that I still have not got my head around yet, as well.


Awesome release! Yet, I'm still waiting for 2.1 to bring finally async/await generators.


async-await for ES5/ES3 is already available in `typescript@next`. give it a try.


Have you tried transpiling to ES6 and then use Babel?


I've gone that route for a while now. It's a nightmare of fragility in your build, not to mention little things like how it totally kills your sourcemaps. I just upgraded to typescript@next and it has been a dream. I eliminated like 50% of the cruft around my build just by doing that.


It's "yet another 'transpilation(?!)' step". I currently use this combination but I would be way happier with just Typescript as in the current config the lag becomes noticeable.


If you use webpack, you could just add ts-loader as a first loader and babel-loader as a second one. Source-map works great too.


Yup - though you need to make use of lib if you want to write es2016 TypeScript and have Babel transpile it. Not too hard to get set up though:

http://blog.johnnyreilly.com/2016/09/typescript-20-es2016-an...


before typescript@next I had exactlt that setup, but sourcemaps were broken despite all my attempts to make them work. Now I'm using ts 2.1 and have completely removed babel out of my build.


Seems the spread operator (a roadblock for a lot of JS interop) will have to wait until 2.1.


ES2015 Object.assign() doesn't seem to me much more verbose than the not yet standardized object spread operator.


I'm currently using the spread operator liberally. Why do you think it's unavailable?


It's available in JSX but not outside that scope, e.g. const { name, ...rest } = person; won't work


probably meant the object spread one, not array spread.


Why choose "readonly" as the modifier for immutable properties? A little long, no?


Probably consistency with C#.


typescript is a nicely conservative set of extensions to javascript, but if you're willing to venture a bit further afield, redhat's ceylon [https://ceylon-lang.org/] is well worth a look. it has an excellent type system, and seems to be under active development, particularly in terms of improving the runtime and code generation.

i played with it for a bit before deciding that for my personal stuff i prefer more strongly ML-based languages, but if i ever have to develop and maintain a large team project i'll definitely give ceylon a very serious look.


Still no async/await for ES5 build targets, but other than that a plethora of excellent new features.


async-await transpilation for ES5/ES3 target is already available in the nightly drops of TS (`typescript@next`).


I gave TypeScript a try but honestly thought it was more trouble than it's worth in most javascript applications/libraries. Maybe that's just the lazy person inside me, or maybe my projects aren't big enough to make use of it's features.


I think you'd see the benefits once the code base gets big enough you can't fit it all in your head any more and the chance of mistakes rises rapidly.


I'm curious specifically what friction you ran into.


The biggest obstacle for Typescript by far is using libraries which have no or outdated declaration files on DefinitelyTyped.

You can get good at writing the declarations yourself, but it's hugely annoying.


Well, you don't have to write any declarations -- everything will just be typed as `any`, which isn't preferable but is exactly what you'd get if you weren't using typescript.


Eh, I guess it was mainly the learning curve and lack of payoff. As mentioned here, I think my project size wasn't big enough for it to show it's usefulness.


Aweyissssss!




Join us for AI Startup School this June 16-17 in San Francisco!

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

Search: