Development / Tools

TypeScript Expands to Offer Functional Programming, Node.js Integration

8 Dec 2016 11:50am, by

In the four years since it went from an internal to a public open source, open design project, the combination of static type checking, transpiling and tooling in TypeScript has become something of a behind-the-scenes success, especially on large projects. You’d expect Microsoft projects like Visual Studio Code (and the Office Online apps) to be written in TypeScript, but so is Angular 2. Slack is currently migrating its Electron-based desktop app to TypeScript.

The recently released TypeScript Version 2.0 brings a broadened scope to the language, which was originally designed as a superset of JavaScript that also offers static typing. The release adds new types, more concepts from functional programming — like tagged unions, and several handy features to improve developer productivity.

Many fundamental pieces in TypeScript 2.0 are also building blocks for features that will come in the next version TypeScript 2.1 (released into preview Wednesday), like using code flow analysis to better assign implicit types to variable and arrays. And with async/await set to become part of the next ECMAScript standard, TypeScript 2.1 will be able to transpile asynchronous code for a wider range of  browsers.

The New Stack asked Anders Hejlsberg, the lead architect of C# and now also a core developer for TypeScript, what’s important in TypeScript 2.0 and why Microsoft wanted to bring new features to JavaScript in the first place.

Making JavaScript Scale

Back in 2011, Microsoft could already see that JavaScript was going to be a critical language, and not just for the web, Hejlsberg said.

“One reason being that it’s really the only thing that runs cross-platform. Even Java is no longer truly cross-platform; it doesn’t run on a bunch of mobile devices. And that’s becoming super-important because the world is becoming more heterogeneous, because of the mobile revolution. People were starting to write really large JavaScript apps and they were it’s hard to write a large app in a dynamic programming language with almost zero tooling that can validate the work you’re doing,” Hejlsberg said. “The only way to find out if it code works was to run it, and you’d better run all of it in all the possible states you can be in, or else you never know. But we know from decades of experience that if you add a static type system and better tooling, you can validate your code before the space shuttle flies rather than while it’s flying!”

The team considered trying to popularize an internal tool for cross-compiling C# to JavaScript called Script#, in the same way, Google was pushing GWT as a way to use java tools and cross-compile to JavaScript.

“But we also realized that you don’t appeal to a community by telling them to write in a different language and cross-compile into this thing we tell you to think of as IL for the web,” noted Hejlsberg. “We realized we had to work with the JavaScript community to figure out what JavaScript was lacking and find creative ways to fix that.”

What stood out most was that JavaScript had none of the methodologies other languages give you for structuring large applications. “There were no modules, no classes, no interfaces. In particular, there was no static type system and because of that you couldn’t do static verification; you also couldn’t do things like Intellisense, go to definition and find all references or safe refactoring. What if we could add that to JavaScript and do it in a way that doesn’t compromise the core value proposition, that’s cross platform and runs everywhere?”

Static types have been in TypeScript since version 1.0; modules and decorators arrived in version 1.5; intermediate releases brought support for ES2015 and more JavaScript patterns and libraries. And the focus on tooling and making TypeScript easy to embed in a wide range of editors has also been key. “Developer productivity doesn’t just come from the type checking but from the editing and authoring experience; getting great Intellisense, great refactoring, great code navigation. Things that used to take a whole day take a second with refactoring and that’s just invaluable.”

Building on Node

He’s enthusiastic about the way TypeScript 2 makes it easier to get the type declarations you need by using the Node Package Manager, taking advantage of the way TypeScript uses node — which as he points out is the standard way to get JavaScript outside a browser.

“TypeScript is very much the Switzerland of transpilers. We have no affinity with any particular development stack; it works with Angular and also with React. It works with Vue and Dojo and Aurelia and Ember, you name it… But to use TypeScript, you have to get the type information from somewhere. If it’s a module that was written in TypeScript, that’s easy, but if it’s written in JavaScript and someone has authored a declaration file you have to get that file; it may not come with that other framework when you install that.”

The DefinitelyTyped site has more than 2,000 type declaration files and the TypeScript community created tools like TSD and Typing to pull type definitions from that and other repos, but Hejlsberg admits that’s become rather ‘messy.’

“We realized we needed to focus on making this a better experience, so for TypeScript we’re automatically scraping Definitely Typed and automatically packaging anything you put on there into node modules and putting those in a private namespace, @types. If you say ‘npm install jQuery’, you get the typing — it’s just a node module. Those node modules can have dependencies on other node modules, so we use the node dependency manager. You just install types now.”

He notes that frameworks like Angular ship with TypeScript types included so you get them automatically; “but if you don’t it’s just another npm install away, and that makes configuration a lot easier.”

Similarly, glob support was a popular request, so you can use wildcards in file paths in config files to include or exclude specific files, which gets very useful as projects get larger and need to pull source code from different locations. TypeScript couldn’t simply use the standard node module globbing support library, he explained.

“The way we’ve written TypeScript, it has very few dependencies. Often what happens with node projects is you have dependencies on this and on that and before you know it you’ve sucked down hundreds of node modules. We want TypeScript to be embeddable. If you want to run TypeScript in a browser, you can’t depend on node, so we had to write our own.”

Functional Programming for JavaScript

Other new features are more fundamental, and let TypeScript adopt some of the programming ideas that developers are starting to become familiar with thanks to the success of functional languages like Swift and F#.

Giving both JavaScript’s ways of marking values as empty — null and undefined — their own types avoids a large number of programming mistakes when you forget to account for null or undefined values being returned from APIs.

He calls the ability to reason about non-null types as one of the precursors to that: “It’s the billion dollar mistake, or two billion, since JavaScript has both null and undefined; that’s something we were keen to work on and we’ve got that covered now with a nice backward-compatible story that allows you to gradually get there.”

That, in turn, depends on control flow analysis. “Control flow analysis is about the compiler reasoning about what happening in your code. When you write an if statement …

or

 

… then you know x is not null inside there and if you return in there then you know x is not null in the remainder of the block you’re in. But it takes the compiler being to do code flow analysis to figure this out. It turns out non-nullability isn’t meaningful to do without code flow analysis.”

Once you have both of those, use can use control flow analysis for other patterns. “One thing that’s very common in JavaScript is to write message style processing applications. Lots of microservices are ‘receive a request that can be one of following 17 requests, and they all have a header, and all the headers have a request property that’s a string and some variable data beyond that.”

You could use classes and have a class for each request and a dispatcher; he calls that the object-oriented way of doing it. But that’s not the only option, proving that TypeScript isn’t just “C# for JavaScript’.

“With TypeScript and ECMAScript 2015 you can write OOP-style code with more each than before, but it’s also a very nice place to write functional style code,” he points out. (TypeScript itself is written entirely in functional style code with no classes at all).

“The functional way of handling those requests is more that you describe the various request shapes using object type declarations that each have a discriminant property. For example you may have a ‘kind’ property that in one declaration has the literal type ‘get,’ in another has the literal type ‘update,’ and in a third has the literal type ‘delete.’ You then say that a request can be any one of those objects by declaring a union type with each of the possibilities. So now you’ve described, in a closed world way, all the things that are possible and you’ve described the discriminants.”

Formalization

“We’re Just formalizing patterns that are commonly in use, but this allows you to have the compiler validate that you handled all the possible requests and you didn’t access properties off this request that actually belong to a different type of request,” he said.

That should sound familiar to developers familiar with functional languages. “This is a JavaScript formalization of functional programming’s ADT — Abstract Data Types — where you declare all of the different shapes a record can have and you do pattern matching over them.” But interestingly, the TypeScript team didn’t have to change JavaScript to support this. “It’s done here by declaring union types that are unions of interfaces with discriminates in them, and using switch statements to do your pattern matching — but it’s done without adding any new language constructs in JavaScript!”

As with almost everything Hejlsberg has worked on in his career (which now includes 20 years at Microsoft), this isn’t functional programming for the sake of it; these patterns are fundamentally about developer productivity. “The thing that we’re doing… You already have this picture in your head but your tooling doesn’t when you’re sitting in a dumb editor typing JavaScript. And even when you have the picture in your head, there are a lot of minutiae that maybe you get wrong. If you can teach the tool to think about your code more like the way you think about it, then the tool can be much more helpful. That’s what we’re doing by formalizing these common paradigms and idioms that people use when they write JavaScript.”

Feature image by Paul Morris, via Unsplash.

A newsletter digest of the week’s most important stories & analyses.

View / Add Comments

Please stay on topic and be respectful of others. Review our Terms of Use.