
TypeScript 2.4 - DanRosenwasser
https://blogs.msdn.microsoft.com/typescript/2017/06/27/announcing-typescript-2-4/
======
moomin
They've just fixed what I regarded as the top reason for avoiding it
completely: the broken type checking on functions.

It's a source of mystery that they didn't realise that was going to be a
problem right from the start.

~~~
boromi
glad to see this fixed

------
donatj
> Strict contravariance for callback parameters ?TypeScript has always
> compared parameters in a bivariant way. There are a number of reasons for
> this, and for the most part it didn’t appear to be a major issue until we
> heard more from users about the adverse effects it had with Promises and
> Observables…

> TypeScript 2.4 now tightens up how it checks two function types by enforcing
> the correct directionality on callback parameter type checks.

I understand what they mean after quite a bit of wrestling with that and the
example, but I feel like that could have been far better worded for laypeople.

~~~
Analemma_
I would love for an ELI5 explanation of covariance/contravariance, but I've
never seen one. I get it now, but only after reading and rereading
explanations very carefully.

~~~
dotancohen
So, then how would you explain it to a five year old?

~~~
Arnavion
Imagine a pipe that only fits dogs. The pipe has two ends. One side has person
A pushing dogs into the pipe - the source. The other side has person B pulling
dogs out of the pipe - the sink.

The source can push anything into the pipe that is a dog or _more_ specialized
than a dog, ie they can push in specific dog breeds like only terriers. So the
source can treat the "Pipe of Dog" as a "Pipe of Terrier". It's okay because
they're dogs and the pipe accepts dogs. The source cannot push in any animal
that isn't a dog.

When the sink pulls something out of the pipe, they can expect to receive
anything that's a dog or _less_ specialized than a dog, eg they can expect
that everything they receive will be an animal. So the sink can treat the
"Pipe of Dog" as a "Pipe of Animal". The sink can expect not to receive
anything that isn't an animal. The sink can't expect that they'll only receive
_terriers,_ since the source may decide to push bulldogs instead.

The source end of the pipe is contravariant on Dog. The sink end of the pipe
is covariant on Dog.

Edit: To bridge this with programming: A function is a pipe. The input of the
function is the source. The output of the function is the sink. A function
that accepts a Dog could be given a Terrier, and a function that returns a Dog
can be considered to return an Animal.

Data structures are equivalent to functions in this respect. A data structure
that produces instances of Dog is the same as a function that produces a Dog -
IEnumerable<Dog> in C# is also an IEnumerable<Animal>, Promise<Dog> in
JavaScript is also a Promise<Animal>. A data structure that both accepts and
returns instances of Dog is invariant on Dog - List<Dog> in C# can't be
List<Animal>, Array<Dog> in JavaScript can't be Array<Animal>, because that
would let someone push Cats into them.

Edit 2: By the same reasoning, a callback parameter flips the input-output-
variance association for every level of nesting. For a first-level callback,
the inputs to the callback are produced by the function, so the input of the
callback is equivalent to an output of the function, and the output of the
callback is equivalent to an input of the function. Eg consider a JS function
`function foo(x: (y: A) => B): C { }` This is covariant on A, contravariant on
B, covariant on C.

~~~
kmill
I'm not exactly sure where the contra- and co- originally came from, but
here's some cat-egory theory.

Now suppose you have a special pipe that when you push a dog into it, a cat
comes out on the other end. This is called a dog-to-cat pipe. If you stick a
dog-to-cat pipe to the end of a pipe of dog, then you get a pipe of cat (from
the point of view of the sink end). The transformation varies with the
direction of the dog-to-cat pipe. Hence covariant.

Now, what if you have a cat-to-dog pipe and stick it to the source end of a
pipe of dog? Then you have a pipe of cat, from the source's point of view. The
transformation varies against the direction of the cat-to-dog-pipe. Hence
contravariant.

The example in the parent comment is with the more realistic example of a
terrier-to-dog pipe or a dog-to-animal pipe. Of course, a pipe of dog is just
a special name for a dog-to-dog pipe.

(Where this gets somewhat more complicated is when you have pipes which take
pipes.)

------
olingern
> Dynamic import() expressions

This is exciting. About a month ago, I tried this just expecting it to already
be supported. I was sad to learn it wasn't.

Kudos to the Typescript team for the awesome, continual improvements.

------
hamstercat
I'm really excited about String enums. I've been avoiding enums in TypeScript
until now, since every time I've wanted to use them, I realized that a literal
union was easier to use when the times come to log or persist the value. But
with this you keep the string representation, and get a typed constant at the
same time.

Dynamic imports is pretty huge too, that should come in handy for a lot of
people.

------
tkubacki
Dart with dynamic js compiler (DDC) is getting better too:
[http://news.dartlang.org/2017/06/a-stronger-dart-for-
everyon...](http://news.dartlang.org/2017/06/a-stronger-dart-for-
everyone.html)

~~~
adrianlmm
The problem with Dart, is that it is a pain to interact with JavaScript
libraries, let's see if Dart 2 makes it better.

~~~
thebosz
Luckily, the story is getting better. Now all it takes is a "definitions" file
much like @types for Typescript[1].

[1]: [https://medium.com/@thebosz/creating-a-dart-to-javascript-
in...](https://medium.com/@thebosz/creating-a-dart-to-javascript-interop-
library-c97da204c34a)

~~~
untog
Is it also possible to go without a definition? TS allows that and it's quite
useful.

~~~
thebosz
No, because it's not a JS-superset.

~~~
tkubacki
Which is precisely why I don't like Typescript - still easy to shot own foot
hardly

------
drk4
The string enums don't seem to work the same way as the number enums, there's
no 2 way access.

For example.

enum Test { a } let a = Test.a; let b = Test[ 0 ]; // isn't available on the
string ones

I wonder why its like that.

~~~
RyanCavanaugh
If there were a reverse map like for numeric enums, there'd be no way to (at
runtime) distinguish a Name from a Value. With a numeric enum you can use
typeof Test[x] to figure out if x was a valid Name or valid Value, but this
doesn't work for string enums because they're both typeof == 'string'.

~~~
drk4
That seems like a much minor situation compared to not being able to reverse
map.

You could have a situation where you have a string as a code, and then the
display name for example, and you can't really do that as is now. This seems
more useful than checking for the type (which in a numeric enum is either a
number or string, so you would still need to do some work to properly validate
it).

~~~
RyanCavanaugh
If you want to have the reverse map, you can trivially build it yourself. But
if the reverse map did exist (rather, if the map started off as bidirectional,
which is the only option on the table), it'd be impossible to properly
construct the one-way map.

~~~
drk4
You mean because of using the same string for a key/value? I guess I see the
potential problem. Anyway just think that it might be a bit confusing to have
the enum work slightly different depending on whether its using numbers or
strings. It can caught some people off guard.

------
pitaj
Darn. Unfortunately they didn't fix this issue [1] which I was really looking
forward to. Bumped it to TS 2.5

Of course, it does look like this release has no? Salsa-related fixes or
improvements, so it doesn't surprise me.

[https://github.com/Microsoft/TypeScript/issues/15809](https://github.com/Microsoft/TypeScript/issues/15809)

------
azr79
> String enums

This language is getting better and better with each release

------
zeusly
I only know a little bit of JavaScript, what's the best way to learn
TypeScript? Read Eloquent JavaScript then some TS related stuff? Or is there a
TypeScript for Dummies that don't know JS?

~~~
josephst18
I learned JS through Eloquent JavaScript and did the various projects in the
book, then changed all my .js files to .ts, turned on all of TypeScript's
checks, and started adding types to my files.

I'd recommend doing a similar path; transitioning existing code to TS is IMO a
better way to learn it than from scratch. TypeScript Deep Dive is a great
resource.

------
Scarbutt
Is Typescript goal to be the Java/C# of the browser/nodejs? static type
checking, tooling and heavily OOP(as in Java/C#) based?

~~~
mohamedhegazy
No. TypeScript has no dependency on classes the way Java or C# does; nor is
class-oriented code the recondeded style by the TS team. As a matter of fact
the typescript compiler core is all written as functions and immmutable
objects with no classes (except for a polyfill for Map and Set).

TypeScript 2.3 has support for vue.js this injection style patterns (see
[https://github.com/Microsoft/TypeScript/pull/14141](https://github.com/Microsoft/TypeScript/pull/14141))
which are way out of the realm of class-centric programming languages.
Similarly the inference cabalities (expanded in 2.4) and the fundamental
nature of the type system being structural rather than nominal is another give
away of the language nature and direction.

So the short answer is TypeScript is a superset of JavaScript; and is as
class-centric as JavaScript is.

------
PhrosTT
Won't we stop transpiling everything once ES6 support (& modules) are
ubiquitous?

I kind of feel like this is when everybody converted codebases to CoffeeScript
and are now stuck with having to undo that...

Yes, I get strong typing has merits - but so does writing the native language.

~~~
DaiPlusPlus
I see a potential end-game being TypeScript _becoming_ the new ECMAScript.

~~~
WorldMaker
Even in that case it's easy to expect the Typescript compiler to remain in
existence for its language services (such as intellisense) alone. (Just as
Typescript is already used in "salsa" mode by many IDEs/Editors for providing
language services for non-Typescript JS code today.)

That said, you would expect more of a middle ground like Python where
Typescript type annotations become syntactically valid in ECMAScript but with
no clear semantics at runtime, and Typescript would still be needed to
compile/verify type assertions.

There's also the case that transpilers will likely remain test beds for both
future features for the language and supporting complicated backwards
compatible scenarios.

------
brokebook
this is great news. the code below failed to compile in 2.3 but works in 2.4.
it was an annoying bummer when working with ADTs in typescript. It's also nice
that you can use string enum for the discriminators now. "{ kind: Kind.Ok,
value: 'bla' }" feels less stringly.

    
    
      interface Ok<T> { kind: "ok"; value: T; }
      interface Err { kind: "err"; error: string; }
      type Result<T> = Ok<T> | Err
    
      const maybeNumbers: Result<number>[] = [
        { kind: "ok", value: 10 },
        { kind: "err", error: 'some error' },
        { kind: "ok", value: 9 },
      ];
    
      function isOk<T>(thing: Result<T>): thing is Ok<T> {
        return thing.kind === "ok";
      }
    
      const okNumbers: Ok<number>[] = maybeNumbers.filter(isOk);

