You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 16, 2023. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 16, 2023. It is now read-only.
What would be the recommended practice for switching from flow to typescript?
We (nteract) have a large code base (as a lerna monorepo) written with flow and this seems like a good way for us to transition individual packages to typescript, since everything is currently babel backed in our code base.
go one project at a time; then within a given project...
add a tsconfig.json with strict on
replace the Flow Babel plugin with the TypeScript plugin
rename from .js to .ts
as you go through each project, keep the strictest settings on and declare your monorepo dependencies in a .d.ts file
This is a good question; I think that one of the challenges you may face is that type annotations are not considered valid in .js files, so in that regard, you may need to migrate Flow files to use the .ts extension.
Additionally, when trying to import from node_modules, TypeScript will complain under noImplicitAny if you don't have a .d.ts file for a respective .js file. To get around this (while using the strictest settings), each project can temporarily add a declare module "foo/*" for a given inter-project dependency.
So for example, if you have the following layout once you've compiled everything:
Root
+- a
| + a/lib/index.js
|
+ b
| + b/lib/index.js
|
+ c
+ c/lib/index.js
+ c/lib/something/else.js
If b depends on a and c, then in b/src/, you might define an external-types.d.ts with the following ambient module declarations:
// Note: this file cannot have any imports or exports; it needs to be globally scopeddeclare module "a";declare module "c";declare module "c/lib/*";
One more thing is that for a given compilation, Babel can't have both TypeScript and Flow plugins loaded at the same time, so you'll need to remove the Flow plugin for a given project's compilation.
This helps give me an idea of how I should start this off, thank you so much for taking the time to write it. I'm guessing the hardest part of this is assessing how long this refactor will take and any other costs. Right now I'm still a bit scared of the investment, it helps me plan for doing it after a couple more releases of our apps+packages though.
Thanks for answering this.
I am curious though if there could be any ways to keep using .js and .jsx extensions for Javascript code annotated with TS types?
To play the devil's advocate, as an alternative to using Flow or switching to TypeScript, you can get TypeScript type safety for JavaScript.
TypeScript Types for JavaScript
You can keep your files as Javascript and use TypeScript for checking types if you're using VSCode: Type Checking JavaScript. Doing this provides many of the famous benefits of TypeScript, such as intellisense: code completion, Go to Definition, Peek Definition, Find All References, Rename Symbol (across files), Change All Occurences, hover type reveal, etc. You can read more about TypeScript intellisense through JSDoc on the VSCode site. VSCode does not support every feature of JSDoc. You can check out their documentation of the features they do support for intellisense.
Setup
Open user settings and add:
"javascript.implicitProjectConfig.checkJs": true
This tells VSCode to use TypeScript to type check the JavaScript files. Now in this the trick is to use JSDoc comments to document your types. When the TypeScript language service sees JSDoc comments, it uses those to understand the JavaScript's type system.
You can define a type using @type:
/** * @type {string} name */functionannounce(name){alert(`Hello, ${name}!`)}
You can also do type casting, but it is more verbose. Say you have an element of type Node but you want to add an attribute to it. setAttribute is on Element, not Node, so you would get a type error. You can use a JSDoc comment to cast the Node to Element like this. Notice how we use an inline type definition and we tell the language service to apply to the node by surrounding it in braces.
// btn will be type Node:constbtn=document.createElement('button')// Make btn disabled.// Since it's type Node, we need to cast it to type Element:/** @type {Element} */(btn).setAttribute('disabled')
Nice thing about JSDoc comments, including the verbose type casting, when you minify all of it goes away, leaving you with just JavaScript.
Type Checking at Build Time
You can add TypeScript type checking for your JavaScript as part of your build process with an NPM script:
If you look at the default .d.ts files that TypeScript provides, you'll see that they make use of JSDoc comments for better intellisense. Microsoft recommends using JSDoc for enhancing the intellisense that TypeScript produces. VSCode has built in support for JSDoc comments. They also recommend JSDoc for documenting JavaScript code in Visual Studio for intellisense.
JSDoc Comments are Standard JavaScipt
Unlike TypeScript, which needs to be compiled, or Flow, which needs to be stripped out at build time, JSDoc comments are standard JavaScript comments. This means that the type information they provide stays in the source code and can also be in the development version of the code before minification. Minification with Uglify will automatically strip out the JSDoc comments, including any extra markup for type casting. Although proponents of TypeScript and Flow are fond of saying they are just JavaScript, you can run them in the browser as is. JavaScript with JSDoc types can.
Expando Properties
Because TypeScript is a static type checker that only checks during code time and build time, it can't handle expando properties. Instead it will flag these as not existing on the object. When using JSDoc for types, because TypeScript is running under the hood, you'll run into the same problem. Although using expando properties is a normal thing in JavaScript, to use them with TypeScript you need to escape them with braces and quotes.
Which is better? If you want the very best support for types, go with TypeScript. If you just want to be able to write JavaScript and use Babel stage 0 and stage 1 now, but you want enhanced intellisense and type safety, use JSDoc.
If your team consists of geeking JavaScript nerds who are hesitant about introducting types, go with JSDoc. If your team have previously worked with C++, C# or Java, they're going to love TypeScript.
TypeScript features may not always match Babel features. Take for example how TypeScript implements private members in a class with the private declaration, whereas the ECMAScript proposal for class fields has a different approach. When you use JSDoc for types, there is no disparity in what you're writing and what it will be in JavaScript because Babel is based on actual ECMAScript proposals.
Activity
DanielRosenwasser commentedon Feb 22, 2018
TLDR:
tsconfig.jsonwithstricton.jsto.ts.d.tsfileThis is a good question; I think that one of the challenges you may face is that type annotations are not considered valid in
.jsfiles, so in that regard, you may need to migrate Flow files to use the.tsextension.Additionally, when trying to import from
node_modules, TypeScript will complain undernoImplicitAnyif you don't have a.d.tsfile for a respective.jsfile. To get around this (while using the strictest settings), each project can temporarily add adeclare module "foo/*"for a given inter-project dependency.So for example, if you have the following layout once you've compiled everything:
If
bdepends onaandc, then inb/src/, you might define anexternal-types.d.tswith the following ambient module declarations:One more thing is that for a given compilation, Babel can't have both TypeScript and Flow plugins loaded at the same time, so you'll need to remove the Flow plugin for a given project's compilation.
[-]Using typescript babel to transition to flow[/-][+]Using typescript babel to transition from flow[/+]rgbkrk commentedon Feb 22, 2018
This helps give me an idea of how I should start this off, thank you so much for taking the time to write it. I'm guessing the hardest part of this is assessing how long this refactor will take and any other costs. Right now I'm still a bit scared of the investment, it helps me plan for doing it after a couple more releases of our apps+packages though.
richard-lopes commentedon Mar 27, 2018
Thanks for answering this.
I am curious though if there could be any ways to keep using
.jsand.jsxextensions for Javascript code annotated with TS types?DanielRosenwasser commentedon Mar 28, 2018
Richard Lopes (@richard-lopes) Nope, not at this time. We've tried to avoid confusing users with syntax that won't actually work at runtime.
rbiggs commentedon Sep 2, 2018
To play the devil's advocate, as an alternative to using Flow or switching to TypeScript, you can get TypeScript type safety for JavaScript.
TypeScript Types for JavaScript
You can keep your files as Javascript and use TypeScript for checking types if you're using VSCode: Type Checking JavaScript. Doing this provides many of the famous benefits of TypeScript, such as intellisense: code completion, Go to Definition, Peek Definition, Find All References, Rename Symbol (across files), Change All Occurences, hover type reveal, etc. You can read more about TypeScript intellisense through JSDoc on the VSCode site. VSCode does not support every feature of JSDoc. You can check out their documentation of the features they do support for intellisense.
Setup
Open user settings and add:
This tells VSCode to use TypeScript to type check the JavaScript files. Now in this the trick is to use JSDoc comments to document your types. When the TypeScript language service sees JSDoc comments, it uses those to understand the JavaScript's type system.
You can define a type using
@type:You can define a custom type using
@typedef:You can also define generics using the
@templatetag:You can also import type definitions from other files:
You can also do type casting, but it is more verbose. Say you have an element of type Node but you want to add an attribute to it.
setAttributeis on Element, not Node, so you would get a type error. You can use a JSDoc comment to cast the Node to Element like this. Notice how we use an inline type definition and we tell the language service to apply to the node by surrounding it in braces.Nice thing about JSDoc comments, including the verbose type casting, when you minify all of it goes away, leaving you with just JavaScript.
Type Checking at Build Time
You can add TypeScript type checking for your JavaScript as part of your build process with an NPM script:
D.TS Files
If you look at the default
.d.tsfiles that TypeScript provides, you'll see that they make use of JSDoc comments for better intellisense. Microsoft recommends using JSDoc for enhancing the intellisense that TypeScript produces. VSCode has built in support for JSDoc comments. They also recommend JSDoc for documenting JavaScript code in Visual Studio for intellisense.JSDoc Comments are Standard JavaScipt
Unlike TypeScript, which needs to be compiled, or Flow, which needs to be stripped out at build time, JSDoc comments are standard JavaScript comments. This means that the type information they provide stays in the source code and can also be in the development version of the code before minification. Minification with Uglify will automatically strip out the JSDoc comments, including any extra markup for type casting. Although proponents of TypeScript and Flow are fond of saying they are just JavaScript, you can run them in the browser as is. JavaScript with JSDoc types can.
Expando Properties
Because TypeScript is a static type checker that only checks during code time and build time, it can't handle expando properties. Instead it will flag these as not existing on the object. When using JSDoc for types, because TypeScript is running under the hood, you'll run into the same problem. Although using expando properties is a normal thing in JavaScript, to use them with TypeScript you need to escape them with braces and quotes.
The following code is valid JavaScript:
With TypeScript type checking,
mountedwould be flagged as not existing on type Node. Escapingmountedeleviates the problem:JSDoc vs TypeScript
Which is better? If you want the very best support for types, go with TypeScript. If you just want to be able to write JavaScript and use Babel stage 0 and stage 1 now, but you want enhanced intellisense and type safety, use JSDoc.
If your team consists of geeking JavaScript nerds who are hesitant about introducting types, go with JSDoc. If your team have previously worked with C++, C# or Java, they're going to love TypeScript.
TypeScript features may not always match Babel features. Take for example how TypeScript implements private members in a class with the
privatedeclaration, whereas the ECMAScript proposal for class fields has a different approach. When you use JSDoc for types, there is no disparity in what you're writing and what it will be in JavaScript because Babel is based on actual ECMAScript proposals.