
Migrate Jest to TypeScript - whatever_dude
https://github.com/facebook/jest/pull/7554
======
dcosson
Interesting move. If major projects within Facebook are migrating away it
seems pretty likely that Flow is on the way out.

Which I think would be a good thing, it seems like a lot of projects and
libraries haven't fully embraced either because it's unclear which to choose.
In this case I don't think the "competition makes them better" aspect
outweighs the downsides of having a fragmented community.

~~~
jamesisaac
So, I was one of (or I suppose the only...) person in the linked issue arguing
that competition is useful, and that it makes sense for Facebook's products to
be tied into the same ecosystem.

As others have mentioned, when Flow was first launched, TS had an extremely
limited type system (e.g. no null checking, no union types). Of course this
has improved a lot over time, as the two have converged, but there's still a
long way to go for either project to allow JS reach the level of correctness
and expressiveness of, say, OCaml or Haskell.

Flow has consistently for the past few years been bringing new ideas to the
table from this algebraic data types background, which often have ended up
proving to be good ideas, and are in various stages of trickling down to TS.

I worry that if the ecosystem becomes completely dominated by TS, the overall
focus will end up back where TS started: rudimentary OOP inspired types,
without the underlying goal of overall correctness, which Flow strives for,
while TS openly eschews in favour of "pragmatism".

~~~
tigershark
You can’t have the same level of correctness as ocaml if you want to maintain
the compatibility with JavaScript. Typescript type system is unsound for this
reason. You can’t have anything approaching ocaml correctness when in
typescript all objects with the same shape are interchangeable.

~~~
jamesisaac
Yeah I realise you'd never reach the same level of soundness due to the
limitations of the underlying JS (although presumably you could get close with
a subset?). But that's why it's an interesting challenge, and I think what
Flow has shown is that it's possible to get a lot closer than had previously
been imagined.

If everyone just accepted the argument 4 years ago that "JS will never be
sound" then maybe today TS would still just be Java style `interface`
annotations for classes. It's not like the Flow team has reached a ceiling at
this point... there's still plenty on their roadmap that would continue to
improve soundness and expressiveness.

> You can’t have anything approaching ocaml correctness when in typescript all
> objects with the same shape are interchangeable.

Could you elaborate? Flow has recently switched to exact objects by
default[1], which I would have thought would be enough for a sound approach?

[1] [https://medium.com/flow-type/on-the-roadmap-exact-objects-
by...](https://medium.com/flow-type/on-the-roadmap-exact-objects-by-
default-16b72933c5cf)

~~~
tigershark
For example in typescript this is valid:

    
    
        type A = {name: string}
        type B = {name: string}
        function print(obj: A) { alert(obj.name);}
        let a: A = {name: “hello”};
        let b: B = {name: “world”}
        print(a);
        print(b);
    

This is because of typescript structural equality and I think that the same
applies to flow given your link. Obviously if I want a function to accept an
email I don’t want the same function to accept an address, but in typescript
you can’t guarantee it because you have no way to get rid of structural
equality as far as I understood.

~~~
jamesisaac
Ah I see. That can be achieved since Flow 0.51 with opaque types[1][2]. It
seems like TypeScript hasn't yet caught up with this functionality[3].

[1] [https://medium.com/flow-type/hiding-implementation-
details-w...](https://medium.com/flow-type/hiding-implementation-details-with-
flows-new-opaque-type-aliases-feature-40e188c2a3f9)

[2] [https://flow.org/en/docs/types/opaque-
types/](https://flow.org/en/docs/types/opaque-types/)

[3]
[https://github.com/Microsoft/TypeScript/issues/15807#issueco...](https://github.com/Microsoft/TypeScript/issues/15807#issuecomment-301196459)

~~~
tigershark
Yup that seems to help.

------
Vinnl
The TypeScript team really made the right call by adding support for
TypeScript syntax to Babel. Ever since that got merged, the floodgates have
opened: more and more projects support TypeScript by default or practically
only requiring you to flip a switch, making the cost of adopting it (if you
don't need to spend time learning it as well) practically zero. No matter how
small the project, if I start a new one today, it will be written in
TypeScript.

Adoption is now at a point where it is exponential: more projects adopting
TypeScript, resulting in more typings being available, resulting in more
projects adopting TypeScript.

If there's one thing you can focus on to learn as a Javascript developer in
the near future, I'm sure it is TypeScript.

~~~
scrollaway
As an uninformed typescript dev, can you explain to me how TS Babel support
changed things? I understand its mechanical implications, but I don't see why
it would matter for adoption.

~~~
Vinnl
For example, it made it much easier for projects like Create React App to add
optional support for TypeScript. When they added support, that just involved
adding an optional extra step to the compilation process (checking whether you
violated the type constraints) to make sure you actually get the benefits of
TypeScript. Other than that, though, TypeScript projects using CRA use the
exact same infrastructure when they use TypeScript, and the compiled output
should be similar.

Before, this would have involved replacing Babel with TypeScript for
transpiling. This means projects could have slightly different results
depending on whether they were using TypeScript or not, increasing the surface
area for bugs and adding an extra step to the debugging process.

~~~
Rapzid
Doesn't create react app use webpack behind the scenes?ts-loader already
worked pretty well? Not sure how that affected anyone using Babel In a built
pipeline, but the announcement made it sound like there were tons of people
doing bespoke balbel-only builds.. Have not experienced that myself.

~~~
akras14
Babel is a commonly used plug-in Webpack though. So I am guessing all projects
that used Babel/Webpack got TypeScript support for free. It’s a TIL for me,
definitely going to have to look into this. Sounds exciting.

~~~
Vinnl
Note that "TypeScript support" in Babel means that Babel can now strip the
extra syntax that is part of TypeScript applications. It doesn't actually
parse them.

A way to think about it is to consider TypeScript to be a linter, like ESlint
- but one that you can help by annotating your code with e.g. the types of
values you expect it to get passed. Babel can now strip those annotations
before it transpiles your code, but you still need TypeScript to do the actual
"linting". See [https://vincenttunru.com/TypeScript-vs-
Javascript](https://vincenttunru.com/TypeScript-vs-Javascript)

~~~
koolba
It’s more than a linter though. The Typescript compiler can handle the most
common usage of Babel, namely targeting older runtimes.

If you set the build target to ES5 you can still use modern features like
async/await and it will rewrite them using a regenerator function that runs on
older platforms.

~~~
Vinnl
Sure, it _can_ do that - but in CRA's setup, it doesn't; Babel handles that
for you. Babel's TypeScript support allows CRA to re-use its Babel pipeline,
and the linter metaphor was meant to help people understand that.

Like most metaphors, it's not a one-on-one match.

------
sonaltr
I like TS. I really do. It makes life nice and easy to catch bugs quite
quickly and also makes you think about your code quite a bit more (which I
guess makes you a bit slower but it's important enough so it's ok).

What is annoying is when you are stuck on something and can't continue because
you can't figure out the type of a specific object (and you've disabled any /
or you are on the strictest settings).

I was recently stuck on ReactJS + Redux + Redux Saga and it took me a while (~
1 day) to figure it all out (and I'm still not 100% sure if I did it right).
It was fine when I disabled the strictest settings for a bit but it's
definitely annoying (asking for help in Typescript, React, Redux, Saga and
elsewhere didn't really help at all).

~~~
AriaMinaei
I basically do two things to make sure type checking doesn't slow me down:

1) Use _emitOnly: true_. This means that if your code has type errors, it
still compiles. And you can fix the type error later.

2) Never use _any_ directly. Not all _any_ s are equal. Some are there because
you don't have the time to figure out a proper type annotation. Others are
there because you _can_ express a proper annotation, but think that it's just
not worth the effort. And some _any_ s are there because the type system is
not capable of expressing the type you have in mind.

What you want to do is to clearly annotate your intention when you're typing
something as _any_. So what I do is to simply disallow directly using _any_ ,
and instead, use a few global type aliases that better communicate my
intention:

    
    
      type $FixMe = any // Fix this type, preferably before accepting the PR
      type $IntentionalAny = any // This `any` is intentional => never has to be fixed
      type $Unexpressable = any // TS cannot express the proper type atm
    

I often put these aliases in a defs.d.ts file and use them instead of _any_.

------
knocte
I much prefer TypeScript than JavaScript, but TS can still allow shitty code,
such as:

* Using the type 'any'.

* Using the immediate value `undefined` (JS is mental in the fact that it has two kinds of null... and with TS there's really no excuse for using this one, however TS compiler doesn't complain).

* Using very ugly, or very easy to be misleading, typeguards (granted, TS doesn't have decent typeguards, see [https://github.com/Microsoft/TypeScript/issues/28337](https://github.com/Microsoft/TypeScript/issues/28337) ...).

For these reasons, I applaud JS people moving to TS. But I will not recommend
any other people (non-JS) to use TS at all.

~~~
eropple
I very rarely see TypeScript developers actually use `any` (usually to reflect
something like something parsed from arbitrary JSON that needs to be
interrogated rather than just type-asserted) and in my experience it's a rare
shop that doesn't use `strict` for everything to at least force it to be
called out and checked in code review.

`undefined` and `null` seem conventionally used to mean different things
amongst the TypeScript developers I know. `null` is typically used to denote
something that is consciously known to be nonexistent; `undefined` is not
rarely, in my experience, used at all except as a check against something
coming in from untyped modules. I'm sure there are people who honor this more
in the breach than the observance, but this is pretty consistent in my
experience.

Personally, I've moved to TypeScript for most of my personal projects, away
from both Ruby and C#, and it's _fantastic_. (Some things remain more
appropriate for the JVM, typically Kotlin, but that's OK, too.)

~~~
dvlsg
> I very rarely see TypeScript developers actually use `any` (usually to
> reflect something like something parsed from arbitrary JSON that needs to be
> interrogated rather than just type-asserted)

Even that example usage of `any` should be less common, now. I think `unknown`
(which is fairly new) is better there.

~~~
Zarel
Is it? My impression is that `unknown` type doesn't solve that specific
problem.

    
    
        const out: unknown = JSON.parse("{a: 1}");
        if (out && typeof out.a === 'number') console.log(out.a);
    

gives the error:

    
    
        [ts] Object is of type 'unknown'. [2571]

~~~
charrondev
Pretty sure you’re missing a typeof check for ‘out’.

~~~
Zarel
I'm pretty sure I'm not.

    
    
        const out: unknown = JSON.parse("{a: 1}");
        if (typeof out === 'object' && out && typeof out.a === 'number') {
          console.log(out.a);
        }
    

gives the error:

    
    
        [ts] Property 'a' does not exist on type 'object'. [2339]
    

It's a completely unnecessary check, anyway: `out &&` is sufficient to exclude
`null` and `undefined`, which is all that's needed to ensure that `out.a`
won't crash. I challenge you to give a single input to `JSON.parse` that would
crash my code without the `typeof` check.

~~~
charrondev
I see what you mean. I guess unknown just doesn't work that well with inline
type checks for objects, although in that case you probably want a function
anyways. Using the `in` return type you can do something like this:

    
    
      const out: unknown = JSON.parse("{a: 1}");
      
      interface MyStructure {
          a: number;
      }
      
      function isMyStructure(toCheck: unknown): toCheck is MyStructure {
          return toCheck instanceof Object && 'a' in toCheck;
      }
      
      if (isMyStructure(out)) {
          console.log(out.a);
      }
    

This will give you no type errors, and gives you the benefit of having a re-
usable function for this validation. I just discovered this today. I seem to
have missed it in a recent release note.

~~~
Zarel
Oh, yeah, that feature's existed for years; it's called "user-defined type
guards".

[https://www.typescriptlang.org/docs/handbook/advanced-
types....](https://www.typescriptlang.org/docs/handbook/advanced-
types.html#user-defined-type-guards)

Unfortunately, it doesn't work in `checkJs` mode, and I always wish I could do
it inline.

------
knowThySelfx
I like plain Javascript more. I guess those who are from Java/C# background
would like TS.

~~~
peteretep
> I guess those who are from Java/C# background would like TS

Been using dynamic languages almost entirely for the last 20 years. I love
TypeScript. Starting to wish the other languages I worked with had optional
types.

~~~
scrollaway
Good optional types that is. Python, my love of the last 15 years, is finally
adopting optional typing but it's an atrociously bad system compared to
typescript, to the point that I am seriously wondering if the language will
ever have a decent typing system.

Having to import basic types, use awkward syntax, etc... Blergh. I really hope
we can be more pragmatic and learn from typescript.

~~~
speedplane
> Python ... I am seriously wondering if the language will ever have a decent
> typing system.

Considering that everyone seems to use six to target both Python 2 and 3, I am
seriously wondering if the language will ever advance at all.

~~~
basil-rash
I don't think we'll get a Python 4 in the foreseeable future ([1] goes into
more detail, from a core CPython developer's perspective). But that doesn't
mean it can't advance, just that everything will be forwards compatible. Think
C and C++, or even ECMAScript, for that matter.

[1]: [https://opensource.com/life/14/9/why-python-4-wont-be-
python...](https://opensource.com/life/14/9/why-python-4-wont-be-python-3)

------
GutenYe
But both Flow and Jest are both developed by the Facebook team. First of all,
like the author, I didn't say Flow is bad than TypeScript. Secondly, I moved
from Flow to TypeScript last year. Anyway, this going to have a huge impact on
Flow ecosystem.

~~~
_the_inflator
FB devs show that there are no dogmas, only different solutions to different
problems. Flow has its merits and was a good start as an experiment back then.

------
Rapzid
As a TypeScript Jest consumer can't complain, though @types/jest is pretty
good.

I would be much more excited if they opened up Jest to be more "programmable"
though. Dynamically creating tests and etc(before you ask, I was looking into
wrapping an existing bash test framework in Jest). Perhaps the move to TS will
make more of the internal interfaces feel public?

------
jamesisaac
Something which I think could be helpful for the overall ecosystem, and allow
both type systems to coexist and thrive, would be more attention put into
tools which transpile code and type definitions between the two languages. The
two most popular projects that I could find[1][2] are unfortunately incomplete
and have not received any real updates in months.

[1] [https://github.com/joarwilk/flowgen](https://github.com/joarwilk/flowgen)
[2] [https://github.com/bcherny/flow-to-
typescript](https://github.com/bcherny/flow-to-typescript)

------
ojosilva
This is awesome. Just yesterday I was asking around the TS community what good
(opensource) CLI with plugins/extensions were there that were written in TS. I
was looking for code I could use as learning and inspiration. I was led to
vscode and angular-cli, which are both in github. Funny enough, they are also
mentioned in this PR's comments.

Jest, once/if migrated will be another great addition. Hopefully that will
happen soon. The community would really profit from great inspirational
codebases (CLIs in my case) written in Typescript.

~~~
Rapzid
Vscode project is a beast with some pretty unintuitive module boundriea due to
their platform separation and not bothering to export anything separately
(like their IPC system)

Check out the CLI for TypeORM. It uses yargs which has pretty good types, and
I have used it successfully a couple places now (internally). No plugins or
extension examplea though last I looked :(

------
Dirlewanger
So how long until the best parts of TypeScript are subsumed into JavaScript,
and TypeScript is discarded like CoffeeScript?

~~~
alangpierce
CoffeeScript and TypeScript are different enough that I don't think TypeScript
could possibly have the same fate. CoffeeScript was all about syntax sugar,
but 95% of the value of TypeScript is the typechecker that runs in your dev
environment (editor, CI, etc) and has no business running in the browser. I
sure hope we don't get to a world where every browser needs to implement a
standards-compliant typechecker; that would be both architecturally
questionable and greatly slow down improvements to the type system.

It would be nice if the browser could accept and execute TypeScript code (that
is, ignore the type annotations), which would avoid the need for a transpile
step, but that's a relatively minor improvement, and would certainly not be a
replacement for TypeScript itself.

~~~
yazaddaruvala
FWIW, “the browser” already type checks Javascript.

Where a compiler would throw an exception, the Javascript runtime
creates/destroys optimizations.

For example, ‘1 + a’ type checks ‘a’ and optimizes the assembly if ‘a’ is a
number. As soon as there is some other type represented by ‘a’ the runtime
deoptimizes that method.

If the runtime could just throw an exception in those situations and keep the
typed optimization a lot of our Javascript might run faster.

~~~
alangpierce
Browsers certainly collect runtime types of variables in hot code paths, but
that's pretty different from the whole-program static verification that
TypeScript does. TypeScript is designed to have an expressive and flexible
type system, and typechecking a large codebase might take tens of seconds or
minutes, not something you want running every time any user loads your site.

That said, including types in JS could be useful as a hint for the optimizer,
but at least in TypeScript and Flow, the types can always be wrong even if no
errors are reported (e.g. from misuse of escape hatches), so the runtime would
need to double-check them.

~~~
yazaddaruvala
I agree with you. They definitely should keep doing "type checking" lazily.

From what I understand, it would be a lot cheaper if types were built into the
language, and the runtime's contract could trust the type and if it is wrong
then undefined behavior occurs.

------
k__
I don't understand.

Why not Reason?

~~~
alangpierce
In addition to the "more approachable to contributors" answer, Flow and
TypeScript are easy to port between, since they're both light extensions to JS
and have almost the same syntax. I've done a Flow to TS port a few times and
almost all of the code stays the same, it's just accounting for little
differences in the type system details. Switching to a completely different
programming language is much more work and much riskier.

