We spread ourselves thin, but this is the moment you’ve been awaiting – TypeScript 2.1 is here!
For those who are unfamiliar, TypeScript is a language that brings you all the new features of JavaScript, along with optional static types. This gives you an editing experience that can’t be beat, along with stronger checks against typos and bugs in your code.
This release comes with features that we think will drastically reduce the friction of starting new projects, make the type-checker much more powerful, and give you the tools to write much more expressive code.
To start using TypeScript you can use NuGet, or install it through npm:
npm install -g typescript
You can also grab the TypeScript 2.1 installer for Visual Studio 2015 after getting Update 3.
Visual Studio Code will usually just prompt you if your TypeScript install is more up-to-date, but you can also follow instructions to use TypeScript 2.1 now with Visual Studio Code or our Sublime Text Plugin.
We’ve written previously about some great new things 2.1 has in store, including downlevel async
/await
and significantly improved inference, in our announcement for TypeScript 2.1 RC, but here’s a bit more about what’s new in 2.1.
Async Functions
It bears repeating: downlevel async
functions have arrived! That means that you can use async
/await
and target ES3/ES5 without using any other tools.
Bringing downlevel async
/await
to TypeScript involved rewriting our emit pipeline to use tree transforms. Keeping parity meant not just that existing emit didn’t change, but that TypeScript’s emit speed was on par as well. We’re pleased to say that after several months of testing, neither have been impacted, and that TypeScript users should continue to enjoy a stable speedy experience.
Object Rest & Spread
We’ve been excited to deliver object rest & spread since its original proposal, and today it’s here in TypeScript 2.1. Object rest & spread is a new proposal for ES2017 that makes it much easier to partially copy, merge, and pick apart objects. The feature is already used quite a bit when using libraries like Redux.
With object spreads, making a shallow copy of an object has never been easier:
let copy = { ...original };
Similarly, we can merge several different objects so that in the following example, merged
will have properties from foo
, bar
, and baz
.
let merged = { ...foo, ...bar, ...baz };
We can even add new properties in the process:
let nowYoureHavingTooMuchFun = {
hello: 100,
...foo,
world: 200,
...bar,
}
Keep in mind that when using object spread operators, any properties in later spreads “win out” over previously created properties. So in our last example, if bar
had a property named world
, then bar.world
would have been used instead of the one we explicitly wrote out.
Object rests are the dual of object spreads, in that they can extract any extra properties that don’t get picked up when destructuring an element:
let { a, b, c, ...defghijklmnopqrstuvwxyz } = alphabet;
keyof and Lookup Types
Many libraries take advantage of the fact that objects are (for the most part) just a map of strings to values. Given what TypeScript knows about each value’s properties, there’s a set of known strings (or keys) that you can use for lookups.
That’s where the keyof
operator comes in.
interface Person {
name: string;
age: number;
location: string;
}
let propName: keyof Person;
The above is equivalent to having written out
let propName: "name" | "age" | "location";
This keyof
operator is actually called an index type query. It’s like a query for keys on object types, the same way that typeof
can be used as a query for types on values.
The dual of this is indexed access types, also called lookup types. Syntactically, they look exactly like an element access, but are written as types:
interface Person {
name: string;
age: number;
location: string;
}
let a: Person["age"];
This is the same as saying that n
gets the type of the age
property in Person
. In other words:
let a: number;
When indexing with a union of literal types, the operator will look up each property and union the respective types together.
// Equivalent to the type 'string | number'
let nameOrAge: Person["name" | "age"];
This pattern can be used with other parts of the type system to get type-safe lookups, serving users of libraries like Ember.
function get<T, K extends keyof T>(obj: T, propertyName: K): T[K] {
return obj[propertyName];
}
let x = { foo: 10, bar: "hello!" };
let foo = get(x, "foo"); // has type 'number'
let bar = get(x, "bar"); // has type 'string'
let oops = get(x, "wargarbl"); // error!
Mapped Types
Mapped types are definitely the most interesting feature in TypeScript 2.1.
Let’s say we have a Person
type:
interface Person {
name: string;
age: number;
location: string;
}
Much of the time, we want to take an existing type and make each of its properties entirely optional. With Person
, we might write the following:
interface PartialPerson {
name?: string;
age?: number;
location?: string;
}
Notice we had to define a completely new type.
Similarly, we might want to perform a shallow freeze of an object:
interface FrozenPerson {
readonly name: string;
readonly age: number;
readonly location: string;
}
Or we might want to create a related type where all the properties are boolean
s.
interface BooleanifiedPerson {
name: boolean;
age: boolean;
location: boolean;
}
Notice all this repetition – ideally, much of the same information in each variant of Person
could have been shared.
Let’s take a look at how we could write BooleanifiedPerson
with a mapped type.
type BooleanifiedPerson = {
[P in "name" | "age" | "location"]: boolean
};
Mapped types are produced by taking a union of literal types, and computing a set of properties for a new object type. They’re like list comprehensions in Python, but instead of producing new elements in a list, they produce new properties in a type.
In the above example, TypeScript uses each literal type in "name" | "age" | "location"
, and produces a property of that name (i.e. properties named name
, age
, and location
). P
gets bound to each of those literal types (even though it’s not used in this example), and gives the property the type boolean
.
Right now, this new form doesn’t look ideal, but we can use the keyof
operator to cut down on the typing:
type BooleanifiedPerson = {
[P in keyof Person]: boolean
};
And then we can generalize it:
type Booleanify<T> = {
[P in keyof T]: boolean
};
type BooleanifiedPerson = Booleanify<Person>;
With mapped types, we no longer have to create new partial or readonly variants of existing types either.
// Keep types the same, but make every property optional.
type Partial<T> = {
[P in keyof T]?: T[P];
};
// Keep types the same, but make each property to be read-only.
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
Notice how we leveraged TypeScript 2.1’s new indexed access types here by writing out T[P]
.
So instead of defining a completely new type like PartialPerson
, we can just write Partial<Person>
. Likewise, instead of repeating ourselves with FrozenPerson
, we can just write Readonly<Person>
!
Partial,
Readonly,
Record, and
Pick
Originally, we planned to ship a type operator in TypeScript 2.1 named partial
which could create an all-optional version of an existing type.
This was useful for performing partial updates to values, like when using React‘s setState
method to update component state. Now that TypeScript has mapped types, no special support has to be built into the language for partial
.
However, because the Partial
and Readonly
types we used above are so useful, they’ll be included in TypeScript 2.1. We’re also including two other utility types as well: Record
and Pick
. You can actually see how these types are implemented within lib.d.ts
itself.
Easier Imports
TypeScript has traditionally been a bit finnicky about exactly how you can import something. This was to avoid typos and prevent users from using packages incorrectly.
However, a lot of the time, you might just want to write a quick script and get TypeScript’s editing experience. Unfortunately, it’s pretty common that as soon as you import something you’ll get an error.
“But I already have that package installed!” you might say.
The problem is that TypeScript didn’t trust the import since it couldn’t find any declaration files for lodash. The fix is pretty simple:
npm install --save @types/lodash
But this was a consistent point of friction for developers. And while you can still compile & run your code in spite of those errors, those red squiggles can be distracting while you edit.
So we focused on on that one core expectation:
But I already have that package installed!
and from that statement, the solution became obvious. We decided that TypeScript needs to be more trusting, and in TypeScript 2.1, so long as you have a package installed, you can use it.
Do be careful though – TypeScript will assume the package has the type any
, meaning you can do anything with it. If that’s not desirable, you can opt in to the old behavior with --noImplicitAny
, which we actually recommend for all new TypeScript projects.
Enjoy!
We believe TypeScript 2.1 is a full-featured release that will make using TypeScript even easier for our existing users, and will open the doors to empower new users. 2.1 has plenty more including sharing tsconfig.json
options, better support for custom elements, and support for importing helper functions, all which you can read about on our wiki.
As always, we’d love to hear your feedback, so give 2.1 a try and let us know how you like it! Happy hacking!
Congratulations on this release! Fantastic work guys
In your example for `keyof`:
“`interface Person {
name: string;
age: number;
location: string;
}
let propName: Person;
“`
Should it say
“`
let propName: keyof Person;
“`
Fixed! Thanks for catching!
Typo: the keyof example doesn’t actually use “keyof”!
let propName: Person;
should be
let propName: keyof Person;
I think you’re missing keyof in the example:
“`
interface Person {
name: string;
age: number;
location: string;
}
let propName: >>>keyof<<< Person;
“`
Perfect timing…. Starting project in January… Looking forward using ALL the language features
Isn’t something missing in
function get(obj: T, propertyName: K): T[K] {
return obj[propertyName];
}
K extends keyof T maybe?
Fixed as well – there was a copy/paste error with occurrences of ‘keyof’. Thanks for catching. 🙂
small typo:
same way that typeofcan be used
same way that typeof can be used
interface Person {
name: string;
age: number;
location: string;
}
let a: Person[“age”];
This is the same as saying that n gets the type of the *name* property in Person. In other words:
let a: number;
—————
Should read
This is the same as saying that n gets the type of the *age* property in Person. In other words:
This is the same as saying that *a* gets the type of the *age* property in Person. In other words:
Awesome work! Great to see object spread (would be interesting to read a post detailing major hurdles to implementing this) and keyof.
Brilliant as ever.
Kudos. You guys are really moving the needle for modern dynamic+typed language design.
“Do be careful though – TypeScript will assume the package has the type any, meaning you can do anything with it”
Does it not use the javascript type annotations of the library (if available)? If not, why is that?
> Does it not use the javascript type annotations of the library (if available)
If one is available it will be used, no error will be reported. the error is reported if a `.js` file was found with no `.d.ts` to use. it will be considered `any`, and an error will be reported for it if you have `–noImplicitAny` on.
For the easier imports, is there a way to specifiy an explicit any when importing modules without types in a –noImplicitAny project?
You can use the `declare module “foo”;` syntax in a non-module file to declare the “foo” module as existing with type `any`.
amazing
Thanks guys, keep up the amazing work.
Yeeeeeeeees! Async is a great Christmas gift! Can’t wait to start using it!
And wow, object spead and keyof operators are an unexpected surprise, and appear quite useful.
TypeScript is amazing! Love this language.
Cool!!!
Love the work you guys have been doing.
TypeScript really is taking JavaScript to a new level!
I was wondering about this section: Partial, Readonly, Record, and Pick.
To me it’s pretty clear what partial, readonly and pick (just grab a few of the properties) do. But could you provide a small example (either in the post or just here in the comments) for what “Record” does?
I’m guessing it’s related to the “booleanify” example you had before, but a small explanation would really help.
Looking forward to the new release! Great job!
I was wondering the same and there was a small example in one of the merge:
function mapObject(obj: Record, f: (x: T) => U): Record
const rec = { foo: “hello”, bar: “world”, baz: “bye” };
const lengths = mapObject(rec, s => s.length); // { foo: number, bar: number, baz: number }
So it looks like Record is the same as {[i:string]:boolean}
but I’m not an expert..
Record<string, boolean >
function mapObject<K extends string, T, U>(obj: Record<K, T>, f: (x: T) => U): Record<K, U>
const rec = { foo: “hello”, bar: “world”, baz: “bye” };
const lengths = mapObject(rec, s => s.length); // { foo: number, bar: number, baz: number }
Looks like a cat walking on the keyboard.
I don’t get one thing: downlevel async-await seems to generate state machine that goes through generator (it’s even called __generator). Why in that case async-await is transpiled down-level but generator functions are not, if they could use just the same helper? (this is similar to what facebook/regenerator does)
The transformation is mostly the same. but the main issue with generators is not transforming the `function *` and `yield` but rather the ability to iterate of generators (and on iterators as a prerequisite).
TS should be supporting ES3/ES5 generators as well as iterating over iterables. Issue https://github.com/Microsoft/TypeScript/issues/1564 tracks this work.
Also related is the asynchronous iterator, see https://github.com/Microsoft/TypeScript/issues/11326
Just don’t upgrade if you’re using Angular 2! Breaks Angular-cli (hangs while trying to build project).
Our app has a C# object model where every object is a dictionary and the objects in the dictionary are also dictionary. It’s easy to add/remove properties from any object.
Our UI layout language also uses list where the objects in a list are also recursively a list.
The nicest part though is that we can customize the look of any UI element using a functional language like lisp giving the element to match and the rules to apply to that element (even recursively)
Thank you very much, imports, async are lovely as well as other stuff. <3
No mention on compiler speed improvement? SIN
Wow, this might well be the best TypeScript feature release yet.
Amazing job guys, keep up the great work! 😀
I CAN’T EVEN TELL YOU HOW HAPPY I AM. Typescript team you are the best!!! Congrats on the release!!!
It would be nice to see an explanation of what “P” is in the examples.
Record<string,boolean>
When does this land in Azure app services? When 2 shipped it wasn’t ready for App services initially until a bug fix was released.
Nice release!
I have a concern regarding the “easier import”:
Babel generates code to import ‘*’ when the imported module has no default exports. For instance this is working with babel:
`import React from ‘react’;`
With TS, the same code will result in `React` being undefined 🙁
This difference makes converting Babel projects to TS pretty painful.
I know that TS is right but anyway, I think that most users will be frustrated and may blame TS for that.
What is the best way lo learn TypeScript 2.1 from the begining considering that i have zero knowledge of JavaScript?
Any books, tutorials, online courses, etc?
Thanks!
We have the TypeScript Handbook: https://www.typescriptlang.org/docs/handbook/basic-types.html
But if that’s not your thing, there’s also TypeScript Deep Dive: https://www.gitbook.com/book/basarat/typescript/details
> serving users of libraries like Ember.
This is misleading at best. Since Ember has its own entire home-brew class/inheritance system, unrelated to ES6 classes, with its own wrinkles such as pseudo-inheritance of methods inside an `actions` hash, and mixins, TS cannot deduce the shape of Ember objects, making this inapplicable.
This **could** be applicable to some future version of Ember which uses ES6 classes–which would be a major rearchitecting. However, any such future version of Ember is likely to (or should, anyway) use ES6 getters and setters instead of `this.get(‘a’)` and `this.set(‘a’, val)`, making this particular feature irrelevant.
Ember’s `get` also supports syntax such as `this.get(‘a.b.c’)`, which is impossible to support using this new feature.
Are object spread and keyof evaluated at compile-time or during run-time? I.e: would they be compatible with third-party javascript code, or must everything be typescript for them to work?
The reason i ask is that typescript historically has been very compatible with javascript code but you say that keyof is equivalent to “name” | “age” | “location”; which looks like a compile time constant. It could potentially also have big impact on performance: iterating Object.keys vs just a constant.
This must really be documented properly
TypeScript always strips all type declarations. `keyof` is a compile time-only.
The only typing thing leaking into rutime is non-static enums.
Actually you can just go to TS playground (https://www.typescriptlang.org/play/) and see that by yourself.
I meant `const enum`.
See `enum T { A, B }` vs `const enum T { A, B }` in playground.
Is there any chance that new spread operator will interfere with React’s spread that works in TS since v1.6 ?
There should be no interference that I’m aware of. I assume you’re talking about JSX spread elements.
Good, JSX spread.
That release follows the wrong direction: keyOf operator, Mapped Types: as nice as these appear to java scripters, because they shortcut code, as bad they are: they are obscuring code:
I don’t want to dive into libraries to figure out what one or another function or operator is doing: I want to *see* that from code *at first glance*!
Before turning to such “quick-winning” special operators, you should have first fixed the problems with the findIndex method, a.o…
Could you please elaborate on what you meant by “keeping parity” in the async section? I would like to research this further to understand it better. Also, is there a code example of this new language feature?
Thanks!
We rewrote our emit pipeline to use a tree-transform model. This meant that there would be several stages, each which rewrites bits of syntax at a time (e.g. the ES2016 transform will rewrite the exponentiation operator, the ES2015 transform will rewrite arrow functions etc.)
This tends to be slower (as it exhausts memory & adds GC pressure from allocating new nodes, and requires some re-walking of the program’s trees). We wanted this not to be a cost imposed on every person, so we worked hard on keeping overhead low.
You can check out the results by running tsc with the –diagnostics flag, which will report differences in emit time.
Our 2.1 RC blog post talks a little bit about async/await here: https://blogs.msdn.microsoft.com/typescript/2016/11/08/typescript-2-1-rc-better-inference-async-functions-and-more/
love TypeScript! a very welcome release!
Is typescript a substitute for javascript? If so, don’t’ most browsers lack it?
TypeScript is basically JavaScript with optional static types. It builds on features from the newest version of JavaScript, and adds types on top.
TypeScript acts as a type-checker (so you can avoid errors), a language service (something that gives your editors cool features like completions), and a compiler (so that it can strip out the types and you can run your code in any browser).
See more at our website: https://www.typescriptlang.org/
And feel free to try it out on our playground: https://www.typescriptlang.org/play/index.html
If you were serious about TS and SASS, you would force browser vendors to support TS ans SASS directly.
The actively used versions of CSS and JS should never have gotten into browsers in the first place… They are a disgrace to engineering.
The same goes for HTML. It should function the same as XML and should be equal to . But no… That would be too sane for the crazy browser vendors…
It’s quite evident to me that web technologies are like toilet paper. Nothing fancy about them, just a way to wipe temporary problems away. Building on top of them makes no sense. Just replace those technologies already, even if you have to break the whole web (although that should not be necessary).
the problem is, that you cant do what you are saying. Browsers vendors are not going to break the whole internet, and are doing a great job of designing new backward compatible features, such as es2015+
For the rest of us living in the real world, building ontop of standards and extending them, as SASS and typescript do, seems a good approach
The real world is what you decide to make of it, not what you find in your plate by others.
If you accept having to deal with compilations for TS and SASS, the unnecessary bandwidth spending that comes with sending the “compiled” versions to the client, the problems dealing with mapping JS code back to the original TS code (same goes with SASS), the extra tools needed, the extra time spent, the extra load for your PC, the extra room you need to make in your head for yet another language that tries to defy common modern code syntaxes, etc, etc, then I give up. Obviously, you have no desire to be productive, simple and efficient at all – although, yes, TS and SASS is a step towards the right direction, but definitely not enough and definitely not an achievement compared to what the web really needs and what could be done. Excuse me for not bowing down to your “real world”, the world built by “geniuses” that made the worst scripting language ever, which had bugs even in its syntax, which had global functions more useless that the ones of C, which has no ability of doing even remotely reliable math calculations, which allowed people to shoot themselves in the foot 10 times more often than C++ did, which has specs that very often give browser vendors the freedom to do whatever they like (which is what they do anyway…), which requires at least 3-4 libraries in order to perform the most basic operations, which has a community that is totally confused and not sure yet (even after so many years) what the proper coding style and best practices should be, etc, etc.
And those are only for JS and only what flew through my mind in a couple of minutes. I will not even go into HTML and CSS, which suck as well.
> doing a great job of designing new backward compatible features
They are doing a horrible job actually.
The features are totally not prioritized correctly (I am not even sure if they can list all the required features, since I doubt these people code anything useful, any time in their life), they often deprecate features for which there is no alternative solution, etc, etc, etc.
As far for ES6, which is partially a patch for terribly wrong decisions of the past, the new features do not remove the old smelly baggage. And also, the set of functions available in JS remains the same, poor, unreliable and bad designed. Plus, most of the “new features” are things that every language on this earth had already at least 15 years back. So, JS is only starting to approach real modern languages, it’s not “getting new features”. Unless looping an array not in C-style code, getting the results you expect and using default function parameters, can be considered features that one could be proud of… So, it should be called es2003 instead. That’s the proximate date they are stuck in.
Long story short, if I did my work the same way as these people do theirs, I would have been fired 100 times already. No kidding. Too bad there is no-one to fire these people and we are stuck with them.
Very nice additions! Very cool
Awesome. I’ve already taken advantage of keyof, Type Mappings, and object rest/spread in our Aurelia app!
Good.
Now that TS becomes more mature, can you just make it use types the right way and convert:
name: string;
…to :
string name;
?
I hate this syntax because it is both ugly and it reminds me of languages that are dead (thank God for that).
Plus no developer out there is used to writing the type after the variable name.
If you change that, I might use TS.
If not, I will not use it.
So simple.
It’s the same as trying to replace the `new` operator in JS with `Object.create()`.
No sane developer will follow you.
And even if he does, he will hate you for it.
I guess that explains why JS developers have so much hate towards their community.
> “No sane developer will follow you.”
Lol
Jarrod, is that you??
For the Record type, K extends string | number. How come it doesn’t extend symbol as well?