zxbodya / flowts Goto Github PK
View Code? Open in Web Editor NEWutility script to convert project from flow to typescript
utility script to convert project from flow to typescript
Input:
// @flow
(a, b) =>
// comment
x
Output with --no-prettier
, with or without recast:
(a, b) => // comment
x;
It didn't need to change that. I was hoping recast
would stop babel-plugin-flow-to-typescript
from messing with this line.
If you let it run prettier, it gets worse:
(
a,
b, // comment
) => x;
Found something odd. Commands all run with --no-prettier
.
Input:
// @flow
import a from 'a';
// b
import b, {type btype} from 'b';
Output:
import a from 'a';
// b
import b from 'b';
// b
import type { btype } from 'b';
With --no-recast
:
import a from 'a'; // b
import b from 'b';
import type { btype } from 'b';
Input:
// @flow
import {Node} from 'react';
Output:
import { ReactNode } from 'react';
Validation error:
verification failed, diff after stripping type annotations:
- Expected
+ Received
- import { Node } from "react";
+ import { ReactNode } from "react";
The --no-recast
option makes no difference. The --no-prettier
option just changes the spacing around the brackets.
I'm pretty sure this didn't happen in the previous version of flowts.
Should it make the import a specific type import so it doesn't confuse babel?
Thanks for creating this awesome tool!!
I have some codes includes IndexedAccessType.
But, flowts
seem to does not support the IndexedAccessType.
Is there a workaround?
// @flow
type Foo = {
id: string,
name: string,
}
type IndexedFoo = {
id: Foo['id'], // IndexedAccessType
name: Foo['name'], // IndexedAccessType
}
run flowts
โ error while trying to convert
Error: sample/test.js: Unsupported flow type FlowType(type=IndexedAccessType)
at convertFlowType (/node_modules/flowts/node_modules/@zxbodya/babel-plugin-flow-to-typescript/dist/converters/convertFlowType.js:302:11) {
code: 'BABEL_TRANSFORM_ERROR'
}
TypeScript has both undefined
and void
types. But in flow there is only void
, which is used for both use-cases.
Currently void
type is not changed in converted code, however - in most cases it looks undefined
can be more appropriate.
Suggestion is to replace void
with undefined
for all cases, except when it is a return type:
void
in function return typePromise<void>
I'm pretty sure it didn't do this in the previous version of flowts. This issue was just introduced. Now, when I put in this input, it produces output that fails the validation because it removed some parenthesis. It doesn't actually matter, but it is a needless change.
Input:
// @flow
export default (function () {});
Output is the same regardless of the --no-prettier
flag:
export default function () {}
Console:
verification failed, diff after stripping type annotations:
- Expected
+ Received
- export default (function () {});
+ export default function () {}
When I run it with --no-recast
it produces this and doesn't fail validation:
export default (function () {});
We have the need to generate a type report that we can see to what the types of a package are converted. Basically generating a report.json that shows all types and what they will be migrated to.
Im happy to implement it, but would appreciate some guidance as you have a much better overall idea about the architecture of flowts.
{
"lines": 500,
"files": 20,
"types": {
"abstract": {
"count": 23,
"SomeAbstractType": {
"targetType": "SomeAbstractType",
"count": 23,
"importedFrom": "@scope/abstract-type-package"
}
},
"composed": {
"count": 3,
"Omit<AbstractType, { children: any }>": {
"targetType": "Omit<AbstractType, { children: any }>",
"count": 3
}
}
},
}
Interesting concept. Wondering if this could be something that is also interesting for flowts: https://github.com/Airtable/typescript-migration-codemod/blob/main/src/typescript/flow_type_at_pos.ts
This would add annotations, where flow knows the type so it would increase type coverage. Just bringing that up in case you are interested.
Input:
// @flow
const f = x => ({a: 'a', b: 'b'}[x]);
Output:
const f = (x) =>
({
a: 'a',
b: 'b',
}[x]);
With --no-prettier
:
const f = x => ({
a: 'a',
b: 'b'
})[x];
It could have left that line alone.
๐ big fan of this project! Has worked surprisingly well for my use case :)
Though doing a roughly 1:1 syntax translation is nice, I've found that migrations can often involve other more complex codebase-specific transforms (for example, using a slightly altered generic signature for a TS package). Though I could implement these as standalone codemod scripts run after flowts, it would be great if they could be run right in the flowts execution to take advantage of existing features like post-transform Prettier formatting.
I'm imagining this as an option to convert
/ convertFile
where an array of Babel plugins (similar to existing ones like tsTypesPlugin
) can be passed. This could in theory also be supported via the CLI, though not sure if there's an elegant way to pass in transform plugins.
I do see that there's several places where transformAsync
is applied - I personally see value in supporting post-Flow-To-TS transforms though perhaps transforms could be passed for any stage of the conversion process.
That all being said, I completely understand if this is out of the scope of this project! Just thought I'd mention as an idea to aid large-scale migrations - feel free to close if you'd like. Thanks!
What do you think about removing all sorts of flow suppression comments? Happy to do it if nothing speaks against it :)
If I run flowts
on a file containing this:
// @flow
export const x = g(2 * (n / 2) ** 0.5);
It converts it to this:
export const x = g(2 * (n / 2 ** 0.5));
This changes the formula.
If I use --no-prettier
, I get this:
export const x = g(2 * (n / (2 ** 0.5)));
It has one extra parenthesis, and the logic is still changed in the same way.
If I use --no-recast
, the code is unchanged besides the removal of the flow comment.
I discovered this after running flowts
on a very large code base and manually inspecting all the results, so this problem is pretty rare. However, it's a pretty scary problem to have.
If I remove the export
, it fails fails verification like so:
// @flow
const x = g(2 * (n / (2 ** 0.5)));
verification failed, diff after stripping type annotations:
- Expected
+ Received
- const x = g(2 * (n / 2) ** 0.5);
+ const x = g(2 * (n / 2 ** 0.5));
I was looking for the code that removes @flow
in order to support @flow strict
and @flow strict-local
. Could you point me into the right direction. Have a hard time finding the right spot.
Input:
/* @flow */
() =>
`
x
`
Output is the same regardless of the --no-prettier
setting:
() => `
x
`;
It also fails verification:
verification failed, diff after stripping type annotations:
- Expected
+ Received
() => `
- x
+ x
`;
If you pass --no-recast
it leaves the code unchanged.
Here's a similar example that it leaves unchanged:
/* @flow */
() => `
x
`
It converts this example into the example above:
/* @flow */
() =>
`
x
`
If you input this:
/* @flow */
() =>
`
x
`
It gives you this:
() => `
x
`;
Very interesting! It seems like it's trying to do something nice for you, by looking at the first line of the template and stripping that amount of whitespace from the following lines. In another context, that'd be pretty cool. But here, I just want it to leave my code alone.
Flow has support for enums: https://flow.org/en/docs/enums/
tsflow can properly convert Typescript enums to Flow enums, but flowts will error with a babel parse error if it encounters a Flow enum.
Is this something on the roadmap or planned to be supported? Thanks!
Intl$DateTimeFormatOptions
with expressions like Intl.DateTimeFormatOptions
, generate such replacements for built-in types.importFlow
- currently it might work not correctly when import needs to be renamed, or can result in duplicated import(which would be babel syntax error)Thank you for this CLI. Currently it reads babel.config.js
from the projects it's being executed on, so the config has to be renamed to something else prior to execution. You could set babelrc:false
in babel option to disable lookup of config
This issue also occurs if I just use babel-plugin-flow-to-typescript
directly so I filed the issue there. Creating an issue here as well so you're aware of it.
I really appreciate your work on these conversion tools. I just ran it on a large code base and audited all the changes and now I'm filing issues about any oddities I found.
I am doing a conversion from Flow to TypeScript when I am modifying the Flow source in order to get the TypeScript to compile properly without errors with tsc. So want to keep the source and have the TypeScript output in another directory tree, so need TypeScript like --outDIr.
e.g. to translate from src to ts :-
flowts --outDir ts src
Commands run with --no-prettier
Input:
// @flow
({
a,
b: (
<></>
),
c,
});
Output with recast:
({
a,
b: (
<></>
),
c
});
Output with --no-recast
({
a,
b: <></>,
c
});
But if the input looks like this, the output with recast is the same as above:
// @flow
({
a,
b: <></>,
c,
});
Input:
// @flow
({
a,
b: {
c,
},
c,
})
Output with recast:
({
a,
b: {
c,
},
c
});
Output with --no-recast
:
({
a,
b: {
c
},
c
});
But if the input looks like this:
// @flow
({
a,
b: {c},
c,
})
Then the output with recast looks like this:
({
a,
b: {c},
c
});
While the output with --no-recast
continues to look like this:
({
a,
b: {
c
},
c
});
Input:
// @flow
({
a,
// comment
b,
c,
});
Output with recast:
({
a,
// comment
b,
c
});
Output with --no-recast
:
({
a,
// comment
b,
c
});
If the input is:
// @flow
({
a,
b, // comment
c,
})
Then the output with recast is still:
({
a,
// comment
b,
c
});
Though the output with --no-recast
is different:
({
a,
b,
// comment
c
});
Input:
// @flow
({
a,
b:
x,
c,
});
Output with recast:
({
a,
b:
x,
c
});
Output without recast:
({
a,
b: x,
c
});
But if the input is:
// @flow
({
a,
b: x,
c,
});
Then the output with and without recast is the same:
({
a,
b: x,
c
});
It seems like the rule is that if a property takes more than one line, including just because it has a comment, recast will reserve two extra lines for it.
This also triggers the problem:
// @flow
({
a,
b: [
],
c,
});
But this doesn't:
// @flow
({
a,
b: [],
c,
});
Input:
// @flow
type t = {
+[id: string]: string,
};
Output:
type t = {
[id: string]: string
};
Using --no-recast
and --no-prettier
makes no difference.
It just removed the +
. Shouldn't it put readonly
in its place?
Output:
class A {
a: Function;
a() {}
}
Output:
class A {
a: Function;
a() {}
}
It should strip the a: Function;
line. If you compile the code with flow, that line gets stripped out of the output, but if you compile it with TypeScript, it acts as a duplicate declaration which overrides the original, resulting in code where a
is undefined
.
If I run flowts
on a file containing this:
export type t = ('a' | 'b')[]
It converts it to this:
export type t = 'a' | 'b'[];
This doesn't mean the same thing.
If I pass --no-recast
, it leaves the code as is.
This isn't bad but it's a pointless delta. I was hoping recast would suppress it.
Input:
// @flow
type a = string;
type b = string;
Output is the same with and without recast.
type a = string;
type b = string;
But if there's something else there, like this, recast doesn't change anything.
// @flow
type a = string;
x;
type b = string;
Ditto if it's like this:
// @flow
type a = string;
x;
type b = string;
Prettier has no effect on this.
Hi @zxbodya.
I was wondering what's the current state of the project? What made you not use https://github.com/Khan/flow-to-ts for the migration from flow to TypeScript? For context, we are currently evaluating which tool we want to use to migrate our codebase from flow to Typescript.
All the best,
Max
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.