Announcing TypeScript 3.9
devblogs.microsoft.com
devblogs.microsoft.com
However coming from languages where types are a first element of the language (c++, rust, go...), I often miss a lot of features in typescript (e.g. type conversion overload, generic specialization, etc...)
I know that by design Typescript doesn't want those features and I understand the rationale behind it. I'm just wondering if I'm the only one in that case and if someone would know a language transpiling (not compiling) to JS more appropriate to my tastes (and hence with different goals).
Elm/Purescript syntaxes are not my kink. Open to other suggestions though.
What's your definition of transpiling and what are you looking for?
* I personally find the difference meaningless, lots of languages use intermediate compilation targets like C or JS or LLVM IR or assembly so transpiling and compiling mean the same thing to me
Just adding as it might interest someone :)
For js, specifically : https://haxe.org/manual/target-javascript.html
Coincidentally, Haxe Foundation announced a new version here today : https://haxe.org/blog/haxe-4.1.0-release/
(disclosure : member of Haxe compiler team)
Types absolutely are a first class citizen in TypeScript. Especially coming from Go, which doesn't even support generics, Typescript is really quite powerful. It even has support for ADTs via discriminated unions, which gives you the same power of enums with associated types that you'd get in Rust/Swift.
Is it possible the reason you feel like Typescript doesn't have Types as a first class citizen is because it leverages structural typing rather than nominal typing?
This article mentions material-ui and styled-components. My experience with typescript has been cumbersome with these libraries. A lot of time is spent figuring out what ”types” to return. I find this very difficult in most cases and not fun at all.
I figure there must be something wrong in my approach or in my ts config (no explicit any).
In short. How to best handle styled-components/material-ui/other library in ts environment? Or is typescript just to much overhead in these usecases?
The main issue I've had with these libraries and typescript is compiler/IDE performance, which 3.9 seems to suggest improvements.
I'm not quiet sure what issues you are facing without some examples. Given you are listing react libraries, the react community discord server might be a good place to ask specific questions. They have library and typescript specific channels to ask beginner questions in:
Just to follow up what I meant i created a quick gist. Not working code but maybe can explain it a bit better.
What I mean as an example is this. I create a function that uses styled-components. I have no idea what the return type should be at first. I must dig into internals of styled-components and eventually find something like "AnyStyledComponent" which is basically the same as "Any" but for styled-components.
https://gist.github.com/slackday/7142251cf2bb3660f8c24492aa1...
This is just one example. Just curious. Not to pick at either Typescript or styled-components which are both great!
If there’s not I recommend disabling your linter for the line and adding an entry in .d.ts. You lose effectiveness but it still works.
I’m using Blueprint 3 in TS environment and it’s really nice to get feedback about, say, wrong props passed to one of its styled components right as you type.
> My experience with typescript has been cumbersome with these libraries. A lot of time is spent figuring out what ”types” to return. I find this very difficult in most cases and not fun at all.
Whether your code is statically typed or not, you generally have to be aware of which data structure goes where—otherwise it’s easy to break things.
When code is statically typed, most things break at compile time, enabling your IDE to give immediate feedback. I find the flow much more pleasant if I don’t have to hunt down runtime errors resulting from using a library (BP3 or anything else) in a wrong way.
There is some upfront effort in specifying types explicitly where compiler can’t figure it out or does so mistakenly; how fun that is might depend on your personality and established habits. In addition, I believe it heavily depends on tooling—I like using TS in VS Code environment, but TS with Vim (which I’ve been using for many years) was somewhat of a hell.
Once in a while I come across an obscure library without TS typings, in which case I would generally provide a `.d.ts` file for it, starting with a catch-all `any` type for its exports, later potentially specifying it further if useful and feasible. This is by far the least fun part.
I wasn't aware of the `.d.ts` files. It sounds a lot like what I was looking for! Thanks again for your feedback and help :-)
By the way, keep in mind that it is often unnecessary to specify types explicitly because TS can infer them from context. I used to specify way too many types when I was initially learning TS.
If you have time, I have a question. Note that my professional exposure to Typescript projects is minimal.
I've built a Javascript library which lives in GitHub, NPM, etc (I won't spam the link). It is entirely module-based Javascript.
My understanding is that while Typescript-based projects can use non-TS JS libraries (because TS is a superset of JS), using that library would require more work - initial code, and maintenance - than using an equivalent library either written in TS, or one that includes a TS Declaration File.
If yes to the above, then - given that I'm serious about my library and want other people to use it if it meets their project needs - I assume I need to write a .d.ts Declaration File (or maybe several?) for it.
- How much initial work are we talking here: weeks? Months?
- After the initial work, how much additional work is required to maintain the .d.ts files(s)?
- How much damage could a poorly written .d.ts file do to a library?
- I've seen the Microsoft documentation[1] and ... this looks like a massive amount of work for my library. I know how popular and useful TS has become but, at the end of the day, would I be wasting my time doing what would be, for me, unpaid work?
[1] https://www.typescriptlang.org/docs/handbook/declaration-fil...
> My understanding is that while Typescript-based projects can use non-TS JS libraries (because TS is a superset of JS), using that library would require more work - initial code, and maintenance - than using an equivalent library either written in TS, or one that includes a TS Declaration File.
More work, yes, but often not a lot of it depending on need. (You can just tell Typescript some modules are `any` and treat them as a black box.)
It's not so much "more work" as it is "less confidence". If you are looking for trust from TS developers in your library, a TS Declaration is API documentation directly in their IDE that does basic sanity/usage checks for them.
> How much initial work are we talking here: weeks? Months?
I find it is usually in the order of hours. The variables are the size of your library and in particular its external API surface and how well your API is already documented. A .d.ts file is just another sort of API documentation. If you've got good JSDOC comments, for instance, that does a lot of the work already. In some cases you can get a .d.ts file for "free" from Typescript if you follow a couple patterns in your JSDOC comments and run Typescript on your JS files. (It might also give you errors where your code doesn't agree with type hints in your JSDOC comments, which you may or may not find useful to discover potential bugs or edge cases in your code.)
> After the initial work, how much additional work is required to maintain the .d.ts files(s)?
It depends on your API changes, especially breaking changes. I've told a number of projects to feel free to @ me when they make API changes and I'll PR a .d.ts update and it's rarely more than a couple minutes to look at what their breaking API changes are and what update what needs to be updated.
> How much damage could a poorly written .d.ts file do to a library?
Again, it's mostly a "loss of confidence" style issue. A poorly written .d.ts isn't going to stop a Typescript user from using your library, it's mostly at worst just going to get in their way and they have to use an escape valve (such as a cast to `any` telling Typescript to get out of the way) and it is no worse than having no .d.ts.
Again, if it helps to think of it as API documentation: a bad .d.ts file is like finding an out of date API document for an old version of the API. It can still offer sign posts to what the expected API is supposed to be, it just requires the user of the library to distrust that documentation and either read the source directly or find other documentation sources (StackOverflow or example code from other users, for example).
> I've seen the Microsoft documentation[1] and ... this looks like a massive amount of work for my library. I know how popular and useful TS has become but, at the end of the day, would I be wasting my time doing what would be, for me, unpaid work?
As with any open source work it is a trade-off and you need to make that determination based on what you are comfortable with maintaining. That's why whenever I've written .d.ts files for libraries I don't maintain, I make sure to explain the maintenance effort, often volunteer to try to do my best to keep it maintained, and also realize and respect that not every library wants to maintain their own .d.ts.
It's also why you don't necessarily need to build the types yourself if you aren't (yet) comfortable learning Typescript or switching to Typescript. (Aside: I find that curiosity in adding your own .d.ts file is often a baby step for learning where Typescript helps you in making a better library, and some of the projects I first helped maintained a .d.ts eventually learned and switched to Typescript themselves.)
If you can find a user of your library that uses Typescript, they may already have a partial type definition you can start from and/or be willing to help you write/maintain the type definitions.
There is a central repository called DefinitelyTyped that happily maintains shared type definitions for a large number of libraries that don't intend to or cannot own and/or maintain their own type definitions. It publishes to an @types/ organization on npm. Your library may already be on there if you have enough users. In that case you also already have a path to starting with something someone else wrote, and GitHub username's to contact and reach out for additional help. If you aren't already in DefinitelyTyped and don't know specific users of your library that use Typescript who could help contribute, there are Definitions Wanted tags in DT's Issue tracker on GitHub and sometimes you can find help from DT's large number of contributors.
Hope that helps.
The other thing I'd recommend is if your focus really is just specifically on writing .d.ts files, and you aren't expecting to use more Typescript directly yourself: get more familiar with and start regularly using JSDoc comments. Typescript in JS mode already understands and can do a lot with JSDoc comments. As I mentioned, it will sometimes give you a fully formed .d.ts if you ask and you have enough JSDoc comments, you'll even get the advantage of some of its type analysis in your project (not as much as if you were writing Typescript directly, but more than just a linter will do). If you use an editor such as VSCode where the JS experience is already backed by the Typescript language service you'd start to see some things almost Typescript-like light up in your development experience as you add more JSDoc comments (maybe even to help explain why you might want to use more Typescript directly).
Thank you! This is a fantastic response (now bookmarked).
I think it best not to do the work now - the library is still evolving and keeping the basic documentation up-to-date (inline comments, but not in JSDOC format) is already an overhead. But this is something I'll need to address at some point. I'll add it to the library's roadmap.
To generate typings for your library, you can start with converting from jsdoc if you have docstrings with types, or if you want to infer types at runtime during a testing suite you can use something like https://github.com/microsoft/dts-gen
I've never used dts Gen but it looks promising as a starting point. But as an additional point, only the public functions and classes really need type declarations, so unless you export all of your functions that could cut down on the burden to write up the types.
Typescript infers return types, so even if you don't write out a return type, it will still be fully typed.
If you still want to specify the return type, you can take advantage of IDE support. Write the function without an explicit return type, then you can hover over it to see the inferred type, then copy the type.
In my preferred IDE (PyCharm), it's even easier since there's a lightbulb action for it. Alt+Enter > "Specify return type explicitly" > Enter
There are Javascript patterns that just don't type well. There are other ways to write your code that will be easier to fit into the type system. It might be more verbose and less reusable at times, but it ends up being a worthwhile tradeoff.
That's general advise and might not apply to the libraries you mention, but it's worked well for us to explicitly call out the differences.
For example, using thunks, one can pass actions directly, or functions that resolve to an action. So, when you're chaining them, it becomes fiddly with types. Compiler complaining about some type or just resolving to any type. I've spent quite some time on that one. Similarly with Formik, I wanted to have generic validators and generic way of applying those validators ... another one that cost me hours to get through and I wasn't satisfied with the result.
There is a lot of information around about Typescript, also various guides like the one here: https://github.com/piotrwitek/react-redux-typescript-guide
But in the end I've felt that while I've become somewhat proficient with Typescript, I was still quite slow to pump out screens and features. And honestly, I didn't enjoy working with it.
(Then there is another can of worms, which is dpendencies and their typings, where it happened that some minor version was bumped and it broke the typings of another library that depended on previous one. So, you might ask, why don't you just pin the dependencies that work together? Well, sometimes an important bug is fixed in a library and you want to upgrade, but you can't, because a person unrelated to library maintainer that handles typings hasn't upgraded them yet ...)
It's probably a good idea to learn how to use generics (type parameters) effectively. For me, it helped immensely to think of them as basically declarative functions in the type system, with the generic/type parameter being just like a function parameter. The cool thing is that while you have to declare them on a function, a lot of times they can be inferred at the call site. With higher level abstractions, most of the time the types just flow through these generics and you get what you want at the other side just based on inference.
[0] https://redux-toolkit.js.org
[1] https://redux.js.org/recipes/usage-with-typescript
[2] https://react-redux.js.org/using-react-redux/static-typing
[3] https://redux-toolkit.js.org/usage/usage-with-typescript
This is a heretic/unpopular opinion, but I think especially for existing JS/React projects, the laxest possible TS setting is the way to go.
You should be able to get to no type errors in your existing JS project with not too many changes. In these contexts (existing projects) I like to think of TS as more editor experience support than seperate language. Modern React is very friendly to TS automatic type inference, so IMHO you should be getting decent benefits from typescript without annotating anything at all. And instead of fixing complicated type errors for no real gain, just // @ts-ignore and move on.
I don't know what your specific issue is with styled-components. Should work pretty much out of the box? My suggestion would be to use CSS objects over string literals because that way you get typechecking for your CSS.
Not sure why you think it's "heretic/unpopular", but I think it's the only reasonable way to incrementally migrate an existing codebase to TypeScript.
Definitely agree with you about the IDE experience, just that alone is enough for me to justify the transition.
The company must pay someone to do the cleanup. Otherwise, of course it won’t work.
https://react-typescript-cheatsheet.netlify.app is a super detailed guide to exactly this, complete with worked examples for lots of common cases.
Styled Components has a specific section in the docs on using SC with TypeScript, which might be useful too: https://styled-components.com/docs/api#typescript
A lot was happening back in 2018. A Googler put together a proposal to add ignorable "pluggable" type annotations to JavaScript, which would allow browsers to run TypeScript directly without transpilation (and without type checking). https://github.com/samuelgoto/proposal-pluggable-types
And a member of the TypeScript team at Microsoft put together a proposal to add enums to JS. https://github.com/rbuckton/proposal-enum
Neither one of these seem to be active. What happened? What would it be like to get these landed?
It also has enum support. If someone wants to add enums to EcmaScript, it has nothing to do with TypeScript or their team.
I glad to see this. One of the most painful moment was when writing tests in TS. You will have to deal with countless type errors.
Although @ts-expect-error will partially solve the problem, what I have learned is don't write tests in TS - you should test it in the real runtime environment where there is no type checking.
This shows clearly why the language server protocol is such a bad design decision and so broken — every language has to implement it itself, and there are no shared features or functionality across languages.
Coming from IDEA, where the exact same refactoring functionality and features work no matter if using typescript, kotlin, Rust, C#, golang or dart, exactly identical in all ways, this has been a huge issue for myself.
Languages Servers should just expose a clean standardized AST format, representing standardized nodes, and this should in turn allow the IDE to act upon this (which would immediately be represented in changed source).
IDEA does a lot of language specific stuff, it just unifies the UX. Which is what language servers aim anyway.
BTW, I'm a long term user of powerline-go. Fantastic piece of software!
Yeah, but with IDEA I have the exact same functionality for Rust, Typescript or Java, while the language servers will never agree on the exact same functions being called the same and doing exactly the same. It means relearning your editor every time you switch your language.
I realize I’m probably in the minority as a person who writes basically every project in another language, whichever happens to work best for the project, while most others probably use only a few languages for most of their career, but it’s still annoying.
On top of that most LSP implementations are open source which lowers the cost of entry for developers and avoids lock-in with proprietary IDE's. And the well specified network protocol makes it much more flexible to different dev setups (e.g. run the LSP on more powerful cloud/remote hardware for large apps, use it with docker-based development setups, etc).
So I would argue the exact opposite, the model of proprietary IDE's building walled gardens around so much useful developer tooling for otherwise open-source languages and ecosystems, is what is broken.
Every editor works the same now — but every language completely different. A user writing JS in vim can write it the same way in VSCode or Atom, but a user using Atom to write JS can’t write Rust in Atom the same way.
I’d love to see a different LSP protocol, one where the LSP exposes much more information, and the editor implements the functionality on top of that, so every language works the same.
But to your point, LSP have brought the IDE experience to others programming editors. Ex: Emacs now can do everything VSCode does for JS because of LSP.
- Native TypeScript runtime interpreter in Deno (TypeScript alternative to Node.js).
- Native TypeScript runtime interpreter in all major browsers.
- At least 20% performance improvement over plain JavaScript.
The build step has to go away because:
- Source maps are unreliable, bulky, slow and add too much complexity for some environments; many environments fail at using them correctly and this can make it difficult to debug code. Being forced to debug ugly transpiled JavaScript is unacceptable and should never happen.
- It's slow to work with. TypeScript often claims to be 'scalable' but reality is that large projects often take multiple minutes to build for every change. There are no good incremental build solutions which also do proper type checking. There is no runtime type checking.
Native browser support is also essential. The bundling step makes in infeasible to freely mix and match modules written in the two languages in a way which is debuggable.
Microsoft should look into Adobe Flash's ActionScript 3 migration from ActionScript 2 for inspiration (both based on ECMAScript spec BTW, just like JavaScript/TypeScript). I remember ActionScript 3 clearly because it was able to deliver a 40% speedup AND runtime type checking...
In spite of these huge benefits, I remember that some developers were still hesitant to switch to ActionScript 3! This new generation of developers has clearly lost its ability for critical thinking - I find the current complete lack of resistance to TS is very strange.
There are a lot more reasons to resist JS to TS migration compared to AS2 to AS3 migration.
I remember in AS2, most people were not declaring types in their code (even though there was support for compile-time type checking). Only in AS3 people started adding Type annotations to their code.
That doesn't make sense. Browsers are unlikely to add native typescript support in the foreseeable future; whereas meanwhile typescript offers huge benefits compared to untyped javascript when it comes to large codebases and refactorings.
It's not my fault that browsers are not going to do it. It doesn't change the fact that it is necessary and that TS is useless without it (the cons outweigh the pros).
>> huge benefits compared to untyped javascript when it comes to large codebases and refactorings
I've provided you at least 1 robust argument why this is not the case. You've provided 0.
I can provide another argument against this:
TypeScript only protects the code from compile time type mismatches, it does not prevent every other possible kind of error; it does not even protect the code from runtime type mismatches (for example from JSON objects passed in an HTTP or RPC request).
It also does not protect from race conditions, memory leaks, issues with multiple sources of truth, unexpected asynchronous state mutations, poor choice of abstractions, poor encapsulation of state changes, poorly handled runtime exceptions, poorly handled runtime schema validation errors, bidirectional data flow issues (which lead to glitchy state changes and infinite loops), poor choice of ADTs which lead to inefficient code, poor choice of libraries for the use case, misuse of common programming patterns, and any other major logic errors... At best, it projects code from only 5% of all possible bugs; typically the simplest, most obvious kinds of bugs. Please think about this objectively. TS adds value, but very little value and also it takes away value in other ways.
For the really difficult runtime bugs which take serious debug time, it adds no value; it makes debugging harder because of its reliance on source mapping.
And by the way, instead of down-voting, please try to convince me otherwise because I'm really suffering with the new TS-first reality (I'm on the losing side). I really do want to see the light but I'm not seeing it at all.
I'm seeing masses of people running towards a cliff. I know there is a cliff there because I pulled myself out of it (learned the hard way) and have been walking in the opposite direction for the past few years and I don't see why I should go back there simply because that's the direction where all the cool people are heading.
I can share anecdotal data about my own experience while refactoring: I do rely on the type checker (be it Flow or TypeScript) to alert me when my code changes have introduced type errors. Every time I run the type checker I realise that it would have taken me ages to read through my code and hunt down the type mismatches that might have been introduced.
I can also point you to the famous AirBnB's slide, which says that they estimate that around 40% of their bugs can be prevented with TypeScript [0]
> TypeScript ... does not
Sure. It's not perfect. It's not Haskell, or PureScript, or Scala, or OCaml. But it does protect you from some of the errors. Protection from some of the errors is better than no protection at all, that's my opinion.
As a bonus point, type annotations serve as a living documentation of your code.
> instead of down-voting, please try to convince me otherwise
I did not downvote your post. I do not downvote other people's posts.
[0] - https://twitter.com/remohjansen/status/1093815648566894594?l...
I totally understand what you're talking about here. I know that TS feeling of being able to just tell the IDE to rename that variable or type anywhere and have that change automatically applied everywhere in the whole codebase. That said, my anecdotal data (having gone back and forth between first AS2 and AS3 for several years and then later between JS and TS multiple times over many years) is that good tests (especially integration tests) even with modest coverage are equally good at finding these sorts of bugs. If I forgot to rename a variable, my tests will fail straight away.
Also, usually I try to keep my classes and functions localized with well defined responsibilities so that any specific kind of data does not need to traverse too many different files; that makes refactoring a lot easier. IMO, not using TS puts more pressure on me to design code in this way and this design approach yields many other benefits.
It takes encapsulation to another level. For example, I don't even believe in the idea of 'cross-cutting concerns' anymore (which is central to the Dependency Injection pattern). For me, the idea of cross-cutting concerns implies a violation of the separation of concern principle (a violation of the cross-cutting kind to be exact). There are almost always ways to avoid these in your code and doing so is always worth it if the programming environment allows it.
>> I can also point you to the famous AirBnB's slide, which says that they estimate that around 40% of their bugs can be prevented with TypeScript
I did read that article when it came out but my point of view on this is that if mostly the same developers rewrite a project (even if they did so in the same language), I would expect at least 40% to 50% fewer bugs. I don't think TypeScript should get the credit there. The reality is that people learn from their mistakes so if they rewrite something, it's going to be better the next time round.
Compile-time checking is well worth the switch. Refactoring old JS express apps is a nightmare.
You can add TS incrementally, so your argument about "downsides" is not valid. You can use it as strictly as you'd like.
That is exactly my point.
My argument then follows that that these are in fact the most important issues and that they dwarf all other possible issues; not only in terms of being the most difficult ones to debug but also the most common ones.
My argument is then that the problems which TypeScript does solve are so insignificant in the grand scheme of things that it's simply not worth it.
Like putting lipstick on a pig.
How would that work? TS is not an optimizing compiler, it's only a type checker.
The fact that Microsoft does not want to hire serious compiler engineers and prefers to spend all the money on marketing is not my fault.
Many performance improvements come from being able to do code analysis during generation, which is already a trade-off for environments doing in-time interpretation, code generation and optimization.
Large performance increases would most come from removing dynamic language complexity, such as having use of the 'class' feature added in ECMAScript create non-mutable properties by default for function declarations.
But when working with senior developers on open source projects (when people don't get paid), I've seen at least 50% drop in developer velocity using TypeScript and lower code quality.
My theory is that developers who are passionate about coding don't need TypeScript to produce high quality code. It mostly just takes the fun out of it.
But I guess if there is no passion to begin with, then I can see how TypeScript can't hurt in that respect. I've worked for a company like this once for 6 months; I had to quit because I enjoy coding too much to spend most of my time writing and renaming type definitions and waiting for the compiler.
More like: Imagine being passionate enough about something to complain about it online, while not even bothering to think it through.
How does having native (as in internally having the transpiler embedded) in deno make you suddenly use TS one day? You can use ts-node.
How long do you think all the browsers would agree that TS would totally be the future of JS and implement it natively, let alone wait until everyone out there to start using such browsers that non TS supporting browsers are almost all eliminated for them to be ignored? There's a reason TS can be compiled down to ES5.
And why are you asking TS for performance over raw JS? Seems off topic from TS' point of view. TS and JS use same principle in the runtime environment and not sure how TS can suddenly beat JS by a good margin.
A project that needs multiple minutes for every change sounds like you're doing it wrong. Split the code or use ts-node?
And you want to throw away all the benefits of TS until all of the above which I don't really feel are required are solved? I don't see why.