Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit c46bb3b

Browse files
extract utility-types.js and convert FlowFixMe to any, fixes #200 (#247)
1 parent bb1762d commit c46bb3b

File tree

7 files changed

+107
-86
lines changed

7 files changed

+107
-86
lines changed

src/transform.js

Lines changed: 8 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ const path = require("path");
22
const t = require("../babel-types/lib/index.js");
33

44
const declare = require("./transforms/declare.js");
5-
const react = require("./transforms/react.js");
5+
const reactTypes = require("./transforms/react-types.js");
66
const objectType = require("./transforms/object-type.js");
7+
const utilityTypes = require("./transforms/utility-types.js");
78

89
const { trackComments } = require("./util.js");
910

@@ -30,69 +31,6 @@ const transformFunction = (path) => {
3031
}
3132
};
3233

33-
// TODO: figure out how to template these inline definitions
34-
const utilityTypes = {
35-
$Keys: (T) => {
36-
// $Keys<T> -> keyof T
37-
// TODO: patch @babel/types - tsTypeOperator should accept two arguments
38-
// return t.tsTypeOperator(typeAnnotation, "keyof");
39-
return {
40-
type: "TSTypeOperator",
41-
typeAnnotation: T,
42-
operator: "keyof",
43-
};
44-
},
45-
$Values: (T) => {
46-
// $Keys<T> -> T[keyof T]
47-
return t.tsIndexedAccessType(
48-
T,
49-
{
50-
type: "TSTypeOperator",
51-
typeAnnotation: T,
52-
operator: "keyof",
53-
}
54-
// TODO: patch @babel/types - tsTypeOperator should accept two arguments
55-
//t.tsTypeOperator(typeAnnotation, "keyof"),
56-
);
57-
},
58-
$ReadOnly: (T) => {
59-
// $ReadOnly<T> -> Readonly<T>
60-
const typeName = t.identifier("Readonly");
61-
const typeParameters = t.tsTypeParameterInstantiation([T]);
62-
return t.tsTypeReference(typeName, typeParameters);
63-
},
64-
$Shape: (T) => {
65-
// $Shape<T> -> Partial<T>
66-
const typeName = t.identifier("Partial");
67-
const typeParameters = t.tsTypeParameterInstantiation([T]);
68-
return t.tsTypeReference(typeName, typeParameters);
69-
},
70-
$NonMaybeType: (T) => {
71-
// $NonMaybeType<T> -> NonNullable<T>
72-
const typeName = t.identifier("NonNullable");
73-
const typeParameters = t.tsTypeParameterInstantiation([T]);
74-
return t.tsTypeReference(typeName, typeParameters);
75-
},
76-
$Exact: (T) => {
77-
// $Exact<T> -> T
78-
return T;
79-
},
80-
$PropertyType: (T, name) => {
81-
// $PropertyType<T, "name"> -> T["name"]
82-
return t.tsIndexedAccessType(T, name);
83-
},
84-
Class: null, // TODO
85-
86-
// These are too complicated to inline so we'll leave them as imports
87-
$Diff: null,
88-
$ElementType: null,
89-
$Call: null,
90-
91-
// The behavior of $Rest only differs when exact object types are involved.
92-
// And since TypeScript doesn't have exact object types using $Diff is okay.
93-
$Rest: "$Diff",
94-
};
95-
9634
const transform = {
9735
Program: {
9836
enter(path, state) {
@@ -472,28 +410,15 @@ const transform = {
472410
return;
473411
}
474412

475-
if (typeName.name in utilityTypes) {
476-
if (
477-
(state.options.inlineUtilityTypes &&
478-
typeof utilityTypes[typeName.name] === "function") ||
479-
typeName.name === "$Exact" // $Exact doesn't exist in utility-types so we always inline it.
480-
) {
481-
const inline = utilityTypes[typeName.name];
482-
path.replaceWith(inline(...typeParameters.params));
483-
} else if (typeof utilityTypes[typeName.name] === "string") {
484-
const replacementName = utilityTypes[typeName.name];
485-
path.replaceWith(
486-
t.tsTypeReference(t.identifier(replacementName), typeParameters)
487-
);
488-
state.usedUtilityTypes.add(replacementName);
489-
} else {
490-
state.usedUtilityTypes.add(typeName.name);
491-
}
413+
let replacement;
492414

415+
replacement = utilityTypes.GenericTypeAnnotation.exit(path, state);
416+
if (replacement) {
417+
path.replaceWith(replacement);
493418
return;
494419
}
495420

496-
const replacement = react.GenericTypeAnnotation.exit(path, state);
421+
replacement = reactTypes.GenericTypeAnnotation.exit(path, state);
497422
if (replacement) {
498423
path.replaceWith(replacement);
499424
return;
@@ -509,7 +434,7 @@ const transform = {
509434
const left = qualification;
510435
const right = id;
511436

512-
const replacement = react.QualifiedTypeIdentifier.exit(path, state);
437+
const replacement = reactTypes.QualifiedTypeIdentifier.exit(path, state);
513438
if (replacement) {
514439
path.replaceWith(replacement);
515440
return;

src/transforms/declare.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const t = require("../../babel-types/lib/index.js");
2-
const {trackComments} = require("../util.js");
2+
const { trackComments } = require("../util.js");
33

44
exports.DeclareVariable = {
55
exit(path) {

src/transforms/object-type.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const t = require("../../babel-types/lib/index.js");
2-
const {trackComments} = require("../util.js");
2+
const { trackComments } = require("../util.js");
33

44
exports.ObjectTypeAnnotation = {
55
enter(path, state) {
@@ -126,7 +126,7 @@ exports.QualifiedTypeIdentifier = {
126126
path.replaceWith(replacement);
127127
return;
128128
}
129-
129+
130130
// fallthrough case
131131
path.replaceWith(t.tsQualifiedName(left, right));
132132
},
File renamed without changes.

src/transforms/utility-types.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
const t = require("../../babel-types/lib/index.js");
2+
3+
// TODO: figure out how to template these inline definitions
4+
const utilityTypes = {
5+
$Keys: (T) => {
6+
// $Keys<T> -> keyof T
7+
// TODO: patch @babel/types - tsTypeOperator should accept two arguments
8+
// return t.tsTypeOperator(typeAnnotation, "keyof");
9+
return {
10+
type: "TSTypeOperator",
11+
typeAnnotation: T,
12+
operator: "keyof",
13+
};
14+
},
15+
$Values: (T) => {
16+
// $Keys<T> -> T[keyof T]
17+
return t.tsIndexedAccessType(
18+
T,
19+
{
20+
type: "TSTypeOperator",
21+
typeAnnotation: T,
22+
operator: "keyof",
23+
}
24+
// TODO: patch @babel/types - tsTypeOperator should accept two arguments
25+
//t.tsTypeOperator(typeAnnotation, "keyof"),
26+
);
27+
},
28+
$ReadOnly: (T) => {
29+
// $ReadOnly<T> -> Readonly<T>
30+
const typeName = t.identifier("Readonly");
31+
const typeParameters = t.tsTypeParameterInstantiation([T]);
32+
return t.tsTypeReference(typeName, typeParameters);
33+
},
34+
$Shape: (T) => {
35+
// $Shape<T> -> Partial<T>
36+
const typeName = t.identifier("Partial");
37+
const typeParameters = t.tsTypeParameterInstantiation([T]);
38+
return t.tsTypeReference(typeName, typeParameters);
39+
},
40+
$NonMaybeType: (T) => {
41+
// $NonMaybeType<T> -> NonNullable<T>
42+
const typeName = t.identifier("NonNullable");
43+
const typeParameters = t.tsTypeParameterInstantiation([T]);
44+
return t.tsTypeReference(typeName, typeParameters);
45+
},
46+
$Exact: (T) => {
47+
// $Exact<T> -> T
48+
return T;
49+
},
50+
$PropertyType: (T, name) => {
51+
// $PropertyType<T, "name"> -> T["name"]
52+
return t.tsIndexedAccessType(T, name);
53+
},
54+
$FlowFixMe: () => {
55+
return t.tsAnyKeyword();
56+
},
57+
Class: null, // TODO
58+
59+
// These are too complicated to inline so we'll leave them as imports
60+
$Diff: null,
61+
$ElementType: null,
62+
$Call: null,
63+
64+
// The behavior of $Rest only differs when exact object types are involved.
65+
// And since TypeScript doesn't have exact object types using $Diff is okay.
66+
$Rest: "$Diff",
67+
};
68+
69+
exports.GenericTypeAnnotation = {
70+
exit(path, state) {
71+
const { id: typeName, typeParameters } = path.node;
72+
73+
if (typeName.name in utilityTypes) {
74+
const value = utilityTypes[typeName.name];
75+
76+
if (
77+
(typeof value === "function" && state.options.inlineUtilityTypes) ||
78+
// $Exact and $FlowFixMe don't exist in utility-types so we always inline them.
79+
typeName.name === "$Exact" ||
80+
typeName.name === "$FlowFixMe"
81+
) {
82+
return typeParameters ? value(...typeParameters.params) : value();
83+
}
84+
85+
if (typeof value === "string") {
86+
state.usedUtilityTypes.add(value);
87+
return t.tsTypeReference(t.identifier(value), typeParameters);
88+
}
89+
90+
state.usedUtilityTypes.add(typeName.name);
91+
}
92+
},
93+
};
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// @flow
2+
type A = $FlowFixMe;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
type A = any;

0 commit comments

Comments
 (0)