Migrate Jest to TypeScript
github.com
github.com
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.
More a fad than the future, I suppose. But at least flow brought some valid ideas to the table, e.g., strictness.
I think that could be seen as a bit harsh, especially in light of the follow-up sentence. What Flow added to the JS ecosystem is probably the future, it's just that the implementation of that future seems to be TypeScript.
Then of course, TypeScript greatly improved and added many of those features. The Flow type inference engine is probably still more advanced, but TypeScript does good enough, and has good developer ergonomics all across the board. Hopefully Flow improved since I last used it but if not it regularly ate tons of memory, was difficult to configure, and had poor IDE integration. So in the modern TypeScript world it's hard to choose Flow despite it's potential advantages, imo.
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".
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...
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.[1] https://medium.com/flow-type/hiding-implementation-details-w...
[2] https://flow.org/en/docs/types/opaque-types/
[3] https://github.com/Microsoft/TypeScript/issues/15807#issueco...
These days, yeah, you're probably right that having only one might be better. Hopefully WebAssembly and languages running on top of it will create the awareness and competition required to keep things moving.
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.
tldr: This release meant that adopting TypeScript no longer meant buying into the entire TypeScript ecosystem and that we could keep using Babel to emit JavaScript. More importantly, this meant that we could actually use TypeScript as a type checker, and not so much as a "language" per se.
[1] https://davidgom.es/porting-30k-lines-of-code-from-flow-to-t...
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.
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
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.
Like most metaphors, it's not a one-on-one match.
TypeScript support as its implemented in CRA just uses Babel like it did before, with some minor modifications such as also passing it .ts files. In parallel, it also runs the ForkTSChecker plugin for Webpack, which notifies you of type errors you made - however, it would work just the same if that plugin was not activated. Hence, there is far less divergence from regular CRA projects.
For example, you _could_ use TypeScript before with React Native. But it was convoluted: there were 3 different way to do it, none of them perfect, and all really brittle. But with Babel 7, you just add another transformer to your babel file and bam, it's treated as a first class citizen. It's literally a one line change.
I definitely see the use case for TypeScript in my project, though: I'm dealing with lots of different types of data. It's useful to know what I've got in my hands.
That being said, Vue... Oh Vue. It settled on its own string template syntax that never got the tooling love of JSX. There have been efforts to get them typed, but those efforts never quite rounded second. Lack of typing in the Vue templates seems to be a sticking point for many.. I don't believe they are long does this world; JSX is the future for Vue.
Coming from React + TS projects, Vue + TS is a lesser experience in many ways. Another such way is the community’s infatuation with exporting raw object literals for component definitions, and forcing you to defy common language idioms to support them hoisting this object literal into a component context.
I wonder whether that's really true. Most adoption of Vue is from after React and JSX were a thing, and many of the Vue adopters (or at least the ones I encounter online) are adopting it because they found React to complex, or had trouble collaborating with their designers. That sounds like templates are one of its main selling points, especially when compared to React.
I don't have a problem with React either. I try to avoid PHP.
I can imagine a day soon when Babel is integrated into tsc to do all of the non typesystem stuff.
I also can imagine the TS team continuing to improve Babel support to a point where TypeScript is “just another plugin” for Babel. At which point tsc can be deprecated.
The less the TS devs have to maintain the more they can focus on their core value add.
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).
In VSCocde I can hover over variable names to display the type of an object in a tooltip. I assume this information is available for other editors as well via the typescript language server.
When TypeScript first came out, this really helped me learn JavaScript & DOM types that browsers treated differently. It also helped me learn to write cross browser compatible JavaScript without depending on jQuery.
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 anys 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 anys 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.Funny, but that was the biggest impediment to big refactorings when I've worked in dynamically typed environments without type annotations. (A decade in Smalltalk.)
* 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 ...).
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.
This is easily enforced in your tsconfig.json
For anyone confused: `"strict": true` in `tsconfig.json` just blanket enables all type checks, including future ones. You can then opt out of specific ones of your choosing if there's too much pain caused by the original authors, but none of those things are added by default. The TS team wants you to leave strict mode on.
It is clear to someone with even cursory knowledge of Javascript and TypeScript what options are available in this regard. Whatever the default is, people can probably make the right decision for their application. It's not hard and it's not hidden.
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "../dist",
"declaration": false,
"strict": true,
"resolveJsonModule": true,
"noImplicitAny": true,
"noImplicitThis": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"jsx": "react",
"lib": [
"es2017",
"dom"
]
},
"compileOnSave": false,
"buildOnSave": false
}https://www.typescriptlang.org/docs/handbook/compiler-option...
`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.)
Even that example usage of `any` should be less common, now. I think `unknown` (which is fairly new) is better there.
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] 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. 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.https://www.typescriptlang.org/docs/handbook/advanced-types....
Unfortunately, it doesn't work in `checkJs` mode, and I always wish I could do it inline.
I mostly use it to cheat when instantiating / using HoCs. Across various packages, they are rarely entirely correctly typed.
Now ts come long way. If your start any js project - start in on ts. And by god - enable full strict mode.
- Use the —noImplicitAny flag to prevent implicitly using any (and if you really want — I don’t think you do, but you can — completely ban any with TSLint)
- Use the —strictNullChecks flag to promote null and undefined to explicit types
Or, use —strict to do both of those and more.
Example tsconfig.json: https://github.com/bcherny/json-schema-to-typescript/blob/ma...
Btw, what specifically is indecent about TS’s type guards?
Welcome to reality! When you do this in any decently-sized TS codebase, you want to kill yourself, because the "smart" devs that started the project didn't do it at the beginning, and fixing it now would take you a man month, in order to be able to enforce it moving forward.
> Use the —strictNullChecks flag
My previous reply also applies to this one, plus: you can still compare against undefined when using this flag (we're talking about unreadable code... even if comparing it with undefined wouldn't make any sense in a codebase with structNullChecks enabled, it's not a compiler error).
> Or, use —strict to do both of those and more.
My gripes above would only be solved if these strict modes were the default. Otherwise shitty and unfixable (read again: man months for a normal project) typescript code keeps being written.
> what specifically is indecent about TS’s type guards?
How about you read the link I posted?
Also strict has been the default for quite a while!
That would prevent anyone to rename a .js file to .ts and compile successfully. Which I think is not the case today. Prove otherwise please.
https://www.typescriptlang.org/docs/handbook/migrating-from-...
Re: type guards, Daniel and everyone else in that thread gave a really reasonable response IMO. I think you might just be misunderstanding TS’s design goal of not affecting runtime behavior?
I dunno, on top of the correctness argument: if you successfully write a codebase without any in it, and assuming your data types and algorithms are sane, then the type stability probably would likely result in really good performance.
No programming language can stop this. Your issue is with bad devs creating bad code.
>> Using the type 'any'.
Using 'any' is either for prototyping, truly dynamic data, or edge-case scenarios, but Typescript is still far better than having no types at all.
With that in mind though, a lot of JS libraries did add it, and the people running the @types repository did a lot of work on volunteering to add it even when the maintainers of the library didn't want it.
JavaScript, and increasingly in the Typescript flavor, is the language of the web. What real alternatives are there presently, that additionally gives a developer decent career opportunities?
TS vastly improves on JS in most aspects, while keeping a 100% compatibility with pure JS, i.e. you can just change the extension of a working .js file to .ts and instantly get access to the TS goodies.
You seem to complain about this compatibility, but a serious TS developer will not maintain such compatibility for long (will typically start restricting 'any' type, etc). This compatibility is the effect of the TS onboarding strategy, a crucial one at that.
The typeguards problem you mention is just one of the problems a JS/TS developer deals with as a matter of course, and will usually have solved by creating/using a utility library, something which JS notoriously requires, and something TS doesn't aspire to help you with, for the same above mentioned compatibility reasons.
As a Scala developer who realised the writing was on the wall for server-side rendering, I spent a good few months trying to use Typescript. It's decent, but the type system was still a huge step down from what I was used to.
A month or so ago I got around to trying Scala.js, and it was... nice, and oh so easy. Facades available for all the big-name javascript libraries. Write ordinary Scala code with the advanced type system and full IDE support that I was used to, and get the same ability to rule out huge classes of errors that I have on the server side.
So, Scala? It's controversial for many but it supports a lot of development styles, uses a runtime that already has a lot of enterprise backing (and will be able to interoperate with your existing libraries if you're a Java shop), and is also used for various bits of exciting newish technology (Kafka, Spark and the like). So it definitely has decent career opportunities.
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.
Having to import basic types, use awkward syntax, etc... Blergh. I really hope we can be more pragmatic and learn from typescript.
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.
[1]: https://opensource.com/life/14/9/why-python-4-wont-be-python...
Mypy started out life as a separate language with pythonic but not Python-compatible syntax and multiple backends that was plannining to take advantage of static typing information and avoiding a GIL to be more performant than Python when compiled to native code rather than using the Python backend.
It later developed a Python-compatible syntax, before becoming a static typing front-end for Python.
Outside of JS land (and that only because of the browser being an environment where the only universally available thing is JS, though WebAssembly maturing may radically change this), there's not really a lot of demand for a separate language that fixes perceived warts in a target language but otherwise hews very close to the target and compiles to that target. Languages that aim to improve another languages ecosystem usually target the same VM instead of being transpiled, and usually offer different style syntax (e.g., Elixir for Erlang.)
ATM I'm doing a pure JS project, it's just some React components / views and some functions that provide glue between 3rd party services. I might do a POC to see how easy it is to use in this project / setting.
There are whole categories of bugs that you can completely eliminate by simply annotating your code with some types. IMHO with the current state of technology, opting out of a static type system is getting pretty hard to defend. Why would you open yourself up to all the nasty bugs that can trivially be detected by a type system? How is that acceptable or better? Transpilers, type inference, linters decent editor integration, etc. have removed most of the traditional argumentation against this (e.g. verbosity, expressiveness, etc.).
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?
[1] https://github.com/joarwilk/flowgen [2] https://github.com/bcherny/flow-to-typescript
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.
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 :(
TypeScriot has a lot of features and the time to move those through standardization and then runtime (and browser) implementation is nontrivial.
If TS runs stalls and doesn’t innovate it _could_ happen, but like I say, subsiding all of those features into the base language would be a win for everyone.
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.
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.
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.
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.
Why not Reason?