flow-api-translator 0.36.0 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,3 @@
1
- /**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- *
8
- * @format
9
- */
10
1
  'use strict';
11
2
 
12
3
  Object.defineProperty(exports, "__esModule", {
@@ -24,6 +15,8 @@ var _ErrorUtils = require("./utils/ErrorUtils");
24
15
 
25
16
  var _DocblockUtils = require("./utils/DocblockUtils");
26
17
 
18
+ var _TSNodeUtils = require("./utils/TSNodeUtils");
19
+
27
20
  var _os = require("os");
28
21
 
29
22
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
@@ -45,18 +38,15 @@ function constructFlowNode(node) {
45
38
  return node;
46
39
  }
47
40
 
48
- const cloneJSDocCommentsToNewNode = // $FlowExpectedError[incompatible-type] - trust me this re-type is 100% safe
49
- _hermesTransform.cloneJSDocCommentsToNewNode;
50
- const makeCommentOwnLine = // $FlowExpectedError[incompatible-type] - trust me this re-type is 100% safe
51
- _hermesTransform.makeCommentOwnLine;
41
+ const cloneJSDocCommentsToNewNode = _hermesTransform.cloneJSDocCommentsToNewNode;
42
+ const makeCommentOwnLine = _hermesTransform.makeCommentOwnLine;
52
43
  const VALID_REACT_IMPORTS = new Set(['React', 'react']);
53
44
 
54
45
  function isValidReactImportOrGlobal(id) {
55
46
  return VALID_REACT_IMPORTS.has(id.name) || id.name.startsWith('React$');
56
47
  }
57
48
 
58
- let shouldAddReactImport = null; // Returns appropriate Identifier for `React` import.
59
- // If a global is in use, set a flag to indicate that we should add the import.
49
+ let shouldAddReactImport = null;
60
50
 
61
51
  function getReactIdentifier(hasReactImport) {
62
52
  if (shouldAddReactImport !== false) {
@@ -84,10 +74,7 @@ function flowDefToTSDef(originalCode, ast, scopeManager, opts) {
84
74
 
85
75
  for (const node of ast.body) {
86
76
  if (node.type in transform) {
87
- const result = transform[// $FlowExpectedError[prop-missing]
88
- // $FlowFixMe[incompatible-type]
89
- node.type]( // $FlowExpectedError[incompatible-type]
90
- node);
77
+ const result = transform[node.type](node);
91
78
  tsBody.push(...(Array.isArray(result) ? result : [result]));
92
79
  } else {
93
80
  throw (0, _ErrorUtils.unexpectedTranslationError)(node, `Unexpected node type ${node.type}`, {
@@ -156,11 +143,8 @@ const getTransforms = (originalCode, scopeManager, opts) => {
156
143
  leading: true,
157
144
  printed: false
158
145
  };
159
- code = makeCommentOwnLine(code, comment); // $FlowExpectedError[prop-missing]
160
- // $FlowExpectedError[cannot-write]
161
-
162
- (_node$comments = node.comments) != null ? _node$comments : node.comments = []; // $FlowExpectedError[incompatible-type]
163
-
146
+ code = makeCommentOwnLine(code, comment);
147
+ (_node$comments = node.comments) != null ? _node$comments : node.comments = [];
164
148
  node.comments.push(comment);
165
149
  }
166
150
 
@@ -240,19 +224,15 @@ const getTransforms = (originalCode, scopeManager, opts) => {
240
224
 
241
225
  currentScope = currentScope.upper;
242
226
  }
243
- })(); // No variable found, it is not imported.
244
- // It could be a global though if isValidReactImportOrGlobal returns true.
245
-
227
+ })();
246
228
 
247
229
  if (variableDef == null) {
248
230
  return false;
249
231
  }
250
232
 
251
- const def = variableDef.defs[0]; // Detect:
233
+ const def = variableDef.defs[0];
252
234
 
253
235
  switch (def.type) {
254
- // import React from 'react';
255
- // import * as React from 'react';
256
236
  case 'ImportBinding':
257
237
  {
258
238
  if (def.node.type === 'ImportDefaultSpecifier' || def.node.type === 'ImportNamespaceSpecifier') {
@@ -261,15 +241,11 @@ const getTransforms = (originalCode, scopeManager, opts) => {
261
241
 
262
242
  return false;
263
243
  }
264
- // Globals
265
244
 
266
245
  case 'ImplicitGlobalVariable':
267
246
  {
268
247
  return VALID_REACT_IMPORTS.has(name);
269
248
  }
270
- // TODO Handle:
271
- // const React = require('react');
272
- // const Something = React;
273
249
  }
274
250
 
275
251
  return false;
@@ -279,49 +255,10 @@ const getTransforms = (originalCode, scopeManager, opts) => {
279
255
  const body = node.body;
280
256
 
281
257
  if (body.type === 'EnumSymbolBody') {
282
- /*
283
- There's unfortunately no way for us to support this in a clean way.
284
- We can get really close using this code:
285
- ```
286
- declare namespace SymbolEnum {
287
- export const member1: unique symbol;
288
- export type member1 = typeof member1;
289
- export const member2: unique symbol;
290
- export type member2 = typeof member2;
291
- }
292
- type SymbolEnum = typeof SymbolEnum[keyof typeof SymbolEnum];
293
- ```
294
- However as explained in https://github.com/microsoft/TypeScript/issues/43657:
295
- "A unique symbol type is never transferred from one declaration to another through inference."
296
- This intended behaviour in TS means that the usage of the fake-enum would look like this:
297
- ```
298
- const value: SymbolEnum.member1 = SymbolEnum.member1;
299
- // ^^^^^^^^^^^^^^^^^^ required to force TS to retain the information
300
- ```
301
- Which is really clunky and shitty. It definitely works, but ofc it's not good.
302
- We can go with this design if users are okay with it!
303
- Considering how rarely used symbol enums are ATM, let's just put a pin in it for now.
304
- */
305
258
  return unsupportedDeclaration(node, 'symbol enums', node.id, FlowESTree.isDeclareEnum(node));
306
259
  }
307
260
 
308
261
  if (body.type === 'EnumBooleanBody') {
309
- /*
310
- TODO - TS enums only allow strings or numbers as their values - not booleans.
311
- This means we need a non-ts-enum representation of the enum.
312
- We can support boolean enums using a construct like this:
313
- ```ts
314
- declare namespace BooleanEnum {
315
- export const member1: true;
316
- export type member1 = typeof member1;
317
- export const member2: false;
318
- export type member2 = typeof member1;
319
- }
320
- declare type BooleanEnum = boolean;
321
- ```
322
- But it's pretty clunky and ugly.
323
- Considering how rarely used boolean enums are ATM, let's just put a pin in it for now.
324
- */
325
262
  return unsupportedDeclaration(node, 'boolean enums', node.id, FlowESTree.isDeclareEnum(node));
326
263
  }
327
264
 
@@ -332,7 +269,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
332
269
  case 'EnumDefaultedMember':
333
270
  {
334
271
  if (body.type === 'EnumNumberBody') {
335
- // this should be impossible!
336
272
  throw unexpectedTranslationError(member, 'Unexpected defaulted number enum member');
337
273
  }
338
274
 
@@ -383,22 +319,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
383
319
  loc: DUMMY_LOC
384
320
  },
385
321
  members
386
- }, // flow also exports `.cast`, `.isValid`, `.members` and `.getName` for enums
387
- // we can use declaration merging to declare these functions on the enum:
388
-
389
- /*
390
- declare enum Foo {
391
- A = 1,
392
- B = 2,
393
- }
394
- declare namespace Foo {
395
- export function cast(value: number | null | undefined): Foo;
396
- export function isValid(value: number | null | undefined): value is Foo;
397
- export function members(): IterableIterator<Foo>;
398
- export function getName(value: Foo): string;
399
- }
400
- */
401
- {
322
+ }, {
402
323
  type: 'TSModuleDeclaration',
403
324
  loc: DUMMY_LOC,
404
325
  declare: true,
@@ -407,8 +328,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
407
328
  body: {
408
329
  type: 'TSModuleBlock',
409
330
  loc: DUMMY_LOC,
410
- body: [// export function cast(value: number | null | undefined): Foo
411
- {
331
+ body: [{
412
332
  type: 'ExportNamedDeclaration',
413
333
  loc: DUMMY_LOC,
414
334
  declaration: {
@@ -456,8 +376,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
456
376
  source: null,
457
377
  exportKind: 'value',
458
378
  assertions: []
459
- }, // export function isValid(value: number | null | undefined): value is Foo;
460
- {
379
+ }, {
461
380
  type: 'ExportNamedDeclaration',
462
381
  loc: DUMMY_LOC,
463
382
  declaration: {
@@ -519,8 +438,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
519
438
  source: null,
520
439
  exportKind: 'value',
521
440
  assertions: []
522
- }, // export function members(): IterableIterator<Foo>;
523
- {
441
+ }, {
524
442
  type: 'ExportNamedDeclaration',
525
443
  loc: DUMMY_LOC,
526
444
  declaration: {
@@ -546,7 +464,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
546
464
  loc: DUMMY_LOC,
547
465
  name: 'IterableIterator'
548
466
  },
549
- typeParameters: {
467
+ typeArguments: {
550
468
  type: 'TSTypeParameterInstantiation',
551
469
  loc: DUMMY_LOC,
552
470
  params: [{
@@ -562,8 +480,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
562
480
  source: null,
563
481
  exportKind: 'value',
564
482
  assertions: []
565
- }, // export function getName(value: Foo): string;
566
- {
483
+ }, {
567
484
  type: 'ExportNamedDeclaration',
568
485
  loc: DUMMY_LOC,
569
486
  declaration: {
@@ -765,13 +682,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
765
682
  BigIntLiteralTypeAnnotation(node) {
766
683
  var _node$bigint;
767
684
 
768
- // technically hermes doesn't support this yet
769
- // but future proofing amirite
770
- const bigint = // $FlowExpectedError[prop-missing]
771
- (_node$bigint = node.bigint) != null ? _node$bigint : node.raw // estree spec is to not have a trailing `n` on this property
772
- // https://github.com/estree/estree/blob/db962bb417a97effcfe9892f87fbb93c81a68584/es2020.md#bigintliteral
773
- .replace(/n$/, '') // `BigInt` doesn't accept numeric separator and `bigint` property should not include numeric separator
774
- .replace(/_/, '');
685
+ const bigint = (_node$bigint = node.bigint) != null ? _node$bigint : node.raw.replace(/n$/, '').replace(/_/, '');
775
686
  return {
776
687
  type: 'TSLiteralType',
777
688
  loc: DUMMY_LOC,
@@ -826,7 +737,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
826
737
  type: 'TSClassImplements',
827
738
  loc: DUMMY_LOC,
828
739
  expression: transform.Identifier(node.id, false),
829
- typeParameters: transform.TypeParameterInstantiation(node.typeParameters)
740
+ typeArguments: transform.TypeParameterInstantiation(node.typeParameters)
830
741
  };
831
742
  },
832
743
 
@@ -839,8 +750,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
839
750
  }
840
751
 
841
752
  for (const member of transformedBody.members) {
842
- // TS uses the real ClassDeclaration AST so we need to
843
- // make the signatures real methods/properties
844
753
  switch (member.type) {
845
754
  case 'TSIndexSignature':
846
755
  {
@@ -850,8 +759,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
850
759
 
851
760
  case 'TSMethodSignature':
852
761
  {
853
- // flow just creates a method signature like any other for a constructor
854
- // but the proper AST has `kind = 'constructor'`
855
762
  const isConstructor = (() => {
856
763
  if (member.computed === true) {
857
764
  return false;
@@ -885,7 +792,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
885
792
  generator: false,
886
793
  id: null,
887
794
  params: member.params,
888
- // constructors explicitly have no return type
889
795
  returnType: undefined,
890
796
  typeParameters: member.typeParameters
891
797
  }
@@ -983,22 +889,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
983
889
  {
984
890
  var _node$body$callProper;
985
891
 
986
- /*
987
- TODO - callProperties
988
- It's not valid to directly declare a call property on a class in TS
989
- You can do it, but it's a big complication in the AST:
990
- ```ts
991
- declare Class {
992
- // ...
993
- }
994
- interface ClassConstructor {
995
- new (): Class;
996
- // call sigs
997
- (): Type;
998
- }
999
- ```
1000
- Let's put a pin in it for now and deal with it later if the need arises.
1001
- */
1002
892
  return unsupportedDeclaration((_node$body$callProper = node.body.callProperties[0]) != null ? _node$body$callProper : node.body, 'call signatures on classes', node.id, true, node.typeParameters);
1003
893
  }
1004
894
 
@@ -1020,9 +910,8 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1020
910
  id: transform.Identifier(node.id, false),
1021
911
  implements: node.implements == null ? undefined : node.implements.map(transform.ClassImplements),
1022
912
  superClass: superClass == null ? null : superClass.id.type === 'QualifiedTypeIdentifier' ? transform.QualifiedTypeIdentifier(superClass.id) : transform.Identifier(superClass.id, false),
1023
- superTypeParameters: transform.TypeParameterInstantiation(superClass == null ? void 0 : superClass.typeParameters),
1024
- typeParameters: node.typeParameters == null ? undefined : transform.TypeParameterDeclaration(node.typeParameters) // TODO - mixins??
1025
-
913
+ superTypeArguments: transform.TypeParameterInstantiation(superClass == null ? void 0 : superClass.typeParameters),
914
+ typeParameters: node.typeParameters == null ? undefined : transform.TypeParameterDeclaration(node.typeParameters)
1026
915
  };
1027
916
  },
1028
917
 
@@ -1031,7 +920,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1031
920
  const declaration = node.declaration;
1032
921
 
1033
922
  switch (declaration.type) {
1034
- // TS doesn't support direct default export for declare'd classes
1035
923
  case 'DeclareClass':
1036
924
  {
1037
925
  const classDecl = transform.DeclareClass(declaration);
@@ -1047,7 +935,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1047
935
  exportKind: 'value'
1048
936
  }];
1049
937
  }
1050
- // TS doesn't support direct default export for declare'd functions
1051
938
 
1052
939
  case 'DeclareFunction':
1053
940
  {
@@ -1064,7 +951,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1064
951
  exportKind: 'value'
1065
952
  }];
1066
953
  }
1067
- // TS doesn't support direct default export for declare'd functions
1068
954
 
1069
955
  case 'DeclareComponent':
1070
956
  {
@@ -1081,7 +967,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1081
967
  exportKind: 'value'
1082
968
  }];
1083
969
  }
1084
- // TS doesn't support direct default export for declare'd functions
1085
970
 
1086
971
  case 'DeclareHook':
1087
972
  {
@@ -1098,16 +983,10 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1098
983
  exportKind: 'value'
1099
984
  }];
1100
985
  }
1101
- // Flow's declare export default Identifier is ambiguous.
1102
- // the Identifier might reference a type, or it might reference a value
1103
- // - If it's a value, then that's all good, TS supports that.
1104
- // - If it's a type, that's a problem - TS only allows value variables to be exported
1105
- // so we need to create an intermediate variable to hold the type.
1106
986
 
1107
987
  case 'GenericTypeAnnotation':
1108
988
  {
1109
- const referencedId = declaration.id; // QualifiedTypeIdentifiers are types so cannot be handled without the intermediate variable so
1110
- // only Identifiers can be handled here.
989
+ const referencedId = declaration.id;
1111
990
 
1112
991
  if (referencedId.type === 'Identifier') {
1113
992
  const exportedVar = topScope.set.get(referencedId.name);
@@ -1118,16 +997,11 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1118
997
  switch (def.type) {
1119
998
  case 'ImportBinding':
1120
999
  {
1121
- // `import type { Wut } from 'mod'; declare export default Wut;`
1122
- // `import { type Wut } from 'mod'; declare export default Wut;`
1123
- // these cases should be wrapped in a variable because they're exporting a type, not a value
1124
1000
  const specifier = def.node;
1125
1001
 
1126
1002
  if (specifier.importKind === 'type' || specifier.parent.importKind === 'type') {
1127
- // fallthrough to the "default" handling
1128
1003
  break;
1129
- } // intentional fallthrough to the "value" handling
1130
-
1004
+ }
1131
1005
  }
1132
1006
 
1133
1007
  case 'ClassName':
@@ -1135,7 +1009,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1135
1009
  case 'FunctionName':
1136
1010
  case 'ImplicitGlobalVariable':
1137
1011
  case 'Variable':
1138
- // there's already a variable defined to hold the type
1139
1012
  return {
1140
1013
  type: 'ExportDefaultDeclaration',
1141
1014
  loc: DUMMY_LOC,
@@ -1153,12 +1026,10 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1153
1026
  throw translationError(def.node, `Unexpected variable def type: ${def.type}`);
1154
1027
 
1155
1028
  case 'Type':
1156
- // fallthrough to the "default" handling
1157
1029
  break;
1158
1030
  }
1159
1031
  }
1160
- } // intentional fallthrough to the "default" handling
1161
-
1032
+ }
1162
1033
  }
1163
1034
 
1164
1035
  case 'TypeofTypeAnnotation':
@@ -1188,24 +1059,11 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1188
1059
  }
1189
1060
  }
1190
1061
  }
1191
- } // intentional fallthrough to the "default" handling
1192
-
1062
+ }
1193
1063
  }
1194
1064
 
1195
1065
  default:
1196
1066
  {
1197
- /*
1198
- flow allows syntax like
1199
- ```
1200
- declare export default TypeName;
1201
- ```
1202
- but TS does not, so we have to declare a temporary variable to
1203
- reference in the export declaration:
1204
- ```
1205
- declare const $$EXPORT_DEFAULT_DECLARATION$$: TypeName;
1206
- export default $$EXPORT_DEFAULT_DECLARATION$$;
1207
- ```
1208
- */
1209
1067
  const SPECIFIER = '$$EXPORT_DEFAULT_DECLARATION$$';
1210
1068
  return [{
1211
1069
  type: 'VariableDeclaration',
@@ -1262,17 +1120,13 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1262
1120
  }
1263
1121
  }
1264
1122
  } else {
1265
- // eslint-disable-next-line eqeqeq
1266
1123
  if (node.source === null) {
1267
- // eslint-disable-next-line eqeqeq
1268
1124
  if (node.declaration === null) {
1269
1125
  return {
1270
1126
  type: 'ExportNamedDeclaration',
1271
1127
  loc: DUMMY_LOC,
1272
- // flow does not currently support attributes
1273
1128
  assertions: [],
1274
1129
  declaration: null,
1275
- // flow does not support declared type exports with specifiers
1276
1130
  exportKind: 'value',
1277
1131
  source: null,
1278
1132
  specifiers: node.specifiers.map(transform.ExportSpecifier)
@@ -1352,7 +1206,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1352
1206
  return [{
1353
1207
  type: 'ExportNamedDeclaration',
1354
1208
  loc: DUMMY_LOC,
1355
- // flow does not currently support attributes
1356
1209
  assertions: [],
1357
1210
  declaration,
1358
1211
  exportKind,
@@ -1387,7 +1240,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1387
1240
  loc: DUMMY_LOC,
1388
1241
  specifiers: [],
1389
1242
  exportKind: 'type',
1390
- // flow does not currently support attributes
1391
1243
  assertions: []
1392
1244
  }];
1393
1245
  }
@@ -1396,7 +1248,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1396
1248
  const exportNamedDeclaration = {
1397
1249
  type: 'ExportNamedDeclaration',
1398
1250
  loc: DUMMY_LOC,
1399
- // flow does not currently support attributes
1400
1251
  assertions: [],
1401
1252
  declaration,
1402
1253
  exportKind,
@@ -1410,10 +1261,8 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1410
1261
  return {
1411
1262
  type: 'ExportNamedDeclaration',
1412
1263
  loc: DUMMY_LOC,
1413
- // flow does not currently support attributes
1414
1264
  assertions: [],
1415
1265
  declaration: null,
1416
- // flow does not support declared type exports with a source
1417
1266
  exportKind: 'value',
1418
1267
  source: transform.StringLiteral(node.source),
1419
1268
  specifiers: node.specifiers.map(transform.ExportSpecifier)
@@ -1425,13 +1274,11 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1425
1274
  DeclareComponent(node) {
1426
1275
  const id = transform.Identifier(node.id, false);
1427
1276
  const typeParameters = node.typeParameters == null ? undefined : transform.TypeParameterDeclaration(node.typeParameters);
1428
- const params = transform.ComponentTypeParameters(node.params, node.rest); // TS cannot support `renderType` so we always use ReactNode as the return type.
1429
-
1277
+ const params = transform.ComponentTypeParameters(node.params, node.rest);
1430
1278
  const hasReactImport = isReactImport(node, 'React');
1431
1279
  const returnType = {
1432
1280
  type: 'TSTypeAnnotation',
1433
1281
  loc: DUMMY_LOC,
1434
- // If no rendersType we assume its ReactNode type.
1435
1282
  typeAnnotation: {
1436
1283
  type: 'TSTypeReference',
1437
1284
  loc: DUMMY_LOC,
@@ -1445,7 +1292,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1445
1292
  name: `ReactNode`
1446
1293
  }
1447
1294
  },
1448
- typeParameters: undefined
1295
+ typeArguments: undefined
1449
1296
  }
1450
1297
  };
1451
1298
  return {
@@ -1540,7 +1387,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1540
1387
  },
1541
1388
 
1542
1389
  DeclareHook(node) {
1543
- // the hook params/returnType are stored as an annotation on the ID...
1544
1390
  const id = transform.Identifier(node.id, false);
1545
1391
  const functionInfo = transform.FunctionTypeAnnotation(node.id.typeAnnotation.typeAnnotation);
1546
1392
  return {
@@ -1563,7 +1409,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1563
1409
  },
1564
1410
 
1565
1411
  DeclareFunction(node) {
1566
- // the function information is stored as an annotation on the ID...
1567
1412
  const id = transform.Identifier(node.id, false);
1568
1413
  const functionInfo = transform.FunctionTypeAnnotation(node.id.typeAnnotation.typeAnnotation);
1569
1414
  return {
@@ -1619,9 +1464,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1619
1464
  },
1620
1465
 
1621
1466
  DeclareOpaqueType(node) {
1622
- // TS doesn't currently have nominal types - https://github.com/Microsoft/Typescript/issues/202
1623
- // TODO - we could simulate this in a variety of ways
1624
- // Examples - https://basarat.gitbook.io/typescript/main-1/nominaltyping
1625
1467
  if (node.supertype == null && node.typeParameters == null) {
1626
1468
  const name = `__${node.id.name}__`;
1627
1469
  return {
@@ -1695,10 +1537,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1695
1537
  },
1696
1538
 
1697
1539
  EmptyTypeAnnotation(node) {
1698
- // Flow's `empty` type doesn't map well to any types in TS.
1699
- // The closest is `never`, but `never` has a number of different semantics
1700
- // In reality no human code should ever directly use the `empty` type in flow
1701
- // So let's put a pin in it for now
1702
1540
  return unsupportedAnnotation(node, 'empty type');
1703
1541
  },
1704
1542
 
@@ -1711,8 +1549,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1711
1549
  },
1712
1550
 
1713
1551
  ExistsTypeAnnotation(node) {
1714
- // The existential type does not map to any types in TS
1715
- // It's also super deprecated - so let's not ever worry
1716
1552
  return unsupportedAnnotation(node, 'existential type');
1717
1553
  },
1718
1554
 
@@ -1720,7 +1556,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1720
1556
  return {
1721
1557
  type: 'ExportAllDeclaration',
1722
1558
  loc: DUMMY_LOC,
1723
- // flow does not currently support import/export attributes
1724
1559
  assertions: [],
1725
1560
  exportKind: node.exportKind,
1726
1561
  source: transform.StringLiteral(node.source),
@@ -1730,11 +1565,9 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1730
1565
 
1731
1566
  ExportNamedDeclaration(node) {
1732
1567
  if (node.source != null || node.specifiers.length > 0) {
1733
- // can never have a declaration with a source
1734
1568
  return {
1735
1569
  type: 'ExportNamedDeclaration',
1736
1570
  loc: DUMMY_LOC,
1737
- // flow does not currently support import/export attributes
1738
1571
  assertions: [],
1739
1572
  declaration: null,
1740
1573
  exportKind: node.exportKind,
@@ -1755,8 +1588,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1755
1588
  case 'HookDeclaration':
1756
1589
  case 'FunctionDeclaration':
1757
1590
  case 'VariableDeclaration':
1758
- // These cases shouldn't happen in flow defs because they have their own special
1759
- // AST node (DeclareClass, DeclareFunction, DeclareVariable)
1760
1591
  throw unexpectedTranslationError(node.declaration, `Unexpected named declaration found ${node.declaration.type}`);
1761
1592
 
1762
1593
  case 'EnumDeclaration':
@@ -1787,7 +1618,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1787
1618
  };
1788
1619
 
1789
1620
  if (mergedDeclaration != null) {
1790
- // for cases where there is a merged declaration, TS enforces BOTH are exported
1791
1621
  return [mainExport, {
1792
1622
  type: 'ExportNamedDeclaration',
1793
1623
  loc: DUMMY_LOC,
@@ -1808,7 +1638,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1808
1638
  loc: DUMMY_LOC,
1809
1639
  exported: transform.Identifier(node.exported, false),
1810
1640
  local: transform.Identifier(node.local, false),
1811
- // flow does not support inline exportKind for named exports
1812
1641
  exportKind: 'value'
1813
1642
  };
1814
1643
  },
@@ -1950,31 +1779,11 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1950
1779
  case '$ObjMapi':
1951
1780
  case '$TupleMap':
1952
1781
  {
1953
- /*
1954
- TODO - I don't think it's possible to make these types work in the generic case.
1955
- TS has no utility types that allow you to generically mimic this functionality.
1956
- You really need intimiate knowledge of the user's intent in order to correctly
1957
- transform the code.
1958
- For example the simple example for $Call from the flow docs:
1959
- ```
1960
- type ExtractPropType = <T>({prop: T}) => T;
1961
- type Obj = {prop: number};
1962
- type PropType = $Call<ExtractPropType, Obj>;
1963
- // expected -- typeof PropType === number
1964
- ```
1965
- The equivalent in TS would be:
1966
- ```
1967
- type ExtractPropType<T extends { prop: any }> = (arg: T) => T['prop'];
1968
- type Obj = { prop: number };
1969
- type PropType = ReturnType<ExtractPropType<Obj>>; // number
1970
- ```
1971
- */
1972
1782
  return unsupportedAnnotation(node, fullTypeName);
1973
1783
  }
1974
1784
 
1975
1785
  case '$ArrayBufferView':
1976
1786
  {
1977
- // `$ArrayBufferView` => `ArrayBufferView`
1978
1787
  return {
1979
1788
  type: 'TSTypeReference',
1980
1789
  loc: DUMMY_LOC,
@@ -1988,7 +1797,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1988
1797
 
1989
1798
  case '$ArrayLike':
1990
1799
  {
1991
- // `$ArrayLike<T>` => `ArrayLike<T>`
1992
1800
  return {
1993
1801
  type: 'TSTypeReference',
1994
1802
  loc: DUMMY_LOC,
@@ -1997,7 +1805,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
1997
1805
  loc: DUMMY_LOC,
1998
1806
  name: 'ArrayLike'
1999
1807
  },
2000
- typeParameters: {
1808
+ typeArguments: {
2001
1809
  type: 'TSTypeParameterInstantiation',
2002
1810
  loc: DUMMY_LOC,
2003
1811
  params: assertHasExactlyNTypeParameters(1)
@@ -2008,7 +1816,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2008
1816
  case '$Diff':
2009
1817
  case '$Rest':
2010
1818
  {
2011
- // `$Diff<A, B>` => `Pick<A, Exclude<keyof A, keyof B>>`
2012
1819
  const params = assertHasExactlyNTypeParameters(2);
2013
1820
  return {
2014
1821
  type: 'TSTypeReference',
@@ -2018,7 +1825,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2018
1825
  loc: DUMMY_LOC,
2019
1826
  name: 'Pick'
2020
1827
  },
2021
- typeParameters: {
1828
+ typeArguments: {
2022
1829
  type: 'TSTypeParameterInstantiation',
2023
1830
  loc: DUMMY_LOC,
2024
1831
  params: [params[0], {
@@ -2029,7 +1836,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2029
1836
  loc: DUMMY_LOC,
2030
1837
  name: 'Exclude'
2031
1838
  },
2032
- typeParameters: {
1839
+ typeArguments: {
2033
1840
  type: 'TSTypeParameterInstantiation',
2034
1841
  loc: DUMMY_LOC,
2035
1842
  params: [{
@@ -2052,7 +1859,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2052
1859
  case '$ElementType':
2053
1860
  case '$PropertyType':
2054
1861
  {
2055
- // `$ElementType<T, K>` => `T[K]`
2056
1862
  const params = assertHasExactlyNTypeParameters(2);
2057
1863
  return {
2058
1864
  type: 'TSIndexedAccessType',
@@ -2064,20 +1870,16 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2064
1870
 
2065
1871
  case '$Exact':
2066
1872
  {
2067
- // `$Exact<T>` => `T`
2068
- // TS has no concept of exact vs inexact types
2069
1873
  return assertHasExactlyNTypeParameters(1)[0];
2070
1874
  }
2071
1875
 
2072
1876
  case '$Exports':
2073
1877
  {
2074
- // `$Exports<'module'>` => `typeof import('module')`
2075
1878
  const moduleName = assertHasExactlyNTypeParameters(1)[0];
2076
1879
 
2077
1880
  if (moduleName.type !== 'TSLiteralType' || moduleName.literal.type !== 'Literal' || typeof moduleName.literal.value !== 'string') {
2078
1881
  throw translationError(node, '$Exports must have a string literal argument');
2079
- } // New AST format for `typeof import('module')`
2080
-
1882
+ }
2081
1883
 
2082
1884
  return {
2083
1885
  type: 'TSTypeQuery',
@@ -2087,14 +1889,15 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2087
1889
  loc: DUMMY_LOC,
2088
1890
  argument: moduleName,
2089
1891
  qualifier: null,
2090
- typeParameters: null
1892
+ options: null,
1893
+ source: moduleName.literal,
1894
+ typeArguments: null
2091
1895
  }
2092
1896
  };
2093
1897
  }
2094
1898
 
2095
1899
  case '$FlowFixMe':
2096
1900
  {
2097
- // `$FlowFixMe` => `any`
2098
1901
  return {
2099
1902
  type: 'TSAnyKeyword',
2100
1903
  loc: DUMMY_LOC
@@ -2103,7 +1906,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2103
1906
 
2104
1907
  case '$KeyMirror':
2105
1908
  {
2106
- // `$KeyMirror<T>` => `{[K in keyof T]: K}`
2107
1909
  return {
2108
1910
  type: 'TSMappedType',
2109
1911
  loc: DUMMY_LOC,
@@ -2150,7 +1952,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2150
1952
 
2151
1953
  case '$Keys':
2152
1954
  {
2153
- // `$Keys<T>` => `keyof T`
2154
1955
  return {
2155
1956
  type: 'TSTypeOperator',
2156
1957
  loc: DUMMY_LOC,
@@ -2161,8 +1962,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2161
1962
 
2162
1963
  case '$NonMaybeType':
2163
1964
  {
2164
- // `$NonMaybeType<T>` => `NonNullable<T>`
2165
- // Not a great name because `NonNullable` also excludes `undefined`
2166
1965
  return {
2167
1966
  type: 'TSTypeReference',
2168
1967
  loc: DUMMY_LOC,
@@ -2171,7 +1970,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2171
1970
  loc: DUMMY_LOC,
2172
1971
  name: 'NonNullable'
2173
1972
  },
2174
- typeParameters: {
1973
+ typeArguments: {
2175
1974
  type: 'TSTypeParameterInstantiation',
2176
1975
  loc: DUMMY_LOC,
2177
1976
  params: assertHasExactlyNTypeParameters(1)
@@ -2181,7 +1980,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2181
1980
 
2182
1981
  case '$ReadOnly':
2183
1982
  {
2184
- // `$ReadOnly<T>` => `Readonly<T>`
2185
1983
  return {
2186
1984
  type: 'TSTypeReference',
2187
1985
  loc: DUMMY_LOC,
@@ -2190,7 +1988,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2190
1988
  loc: DUMMY_LOC,
2191
1989
  name: 'Readonly'
2192
1990
  },
2193
- typeParameters: {
1991
+ typeArguments: {
2194
1992
  type: 'TSTypeParameterInstantiation',
2195
1993
  loc: DUMMY_LOC,
2196
1994
  params: assertHasExactlyNTypeParameters(1)
@@ -2200,10 +1998,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2200
1998
 
2201
1999
  case '$ReadOnlyArray':
2202
2000
  {
2203
- // `$ReadOnlyArray<T>` => `ReadonlyArray<T>`
2204
- //
2205
- // we could also do => `readonly T[]`
2206
- // TODO - maybe a config option?
2207
2001
  return {
2208
2002
  type: 'TSTypeReference',
2209
2003
  loc: DUMMY_LOC,
@@ -2212,7 +2006,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2212
2006
  loc: DUMMY_LOC,
2213
2007
  name: 'ReadonlyArray'
2214
2008
  },
2215
- typeParameters: {
2009
+ typeArguments: {
2216
2010
  type: 'TSTypeParameterInstantiation',
2217
2011
  loc: DUMMY_LOC,
2218
2012
  params: assertHasExactlyNTypeParameters(1)
@@ -2230,7 +2024,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2230
2024
  loc: DUMMY_LOC,
2231
2025
  name: 'ReadonlyMap'
2232
2026
  },
2233
- typeParameters: {
2027
+ typeArguments: {
2234
2028
  type: 'TSTypeParameterInstantiation',
2235
2029
  loc: DUMMY_LOC,
2236
2030
  params: assertHasExactlyNTypeParameters(2)
@@ -2248,7 +2042,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2248
2042
  loc: DUMMY_LOC,
2249
2043
  name: 'ReadonlySet'
2250
2044
  },
2251
- typeParameters: {
2045
+ typeArguments: {
2252
2046
  type: 'TSTypeParameterInstantiation',
2253
2047
  loc: DUMMY_LOC,
2254
2048
  params: assertHasExactlyNTypeParameters(1)
@@ -2259,7 +2053,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2259
2053
  case '$Values':
2260
2054
  case 'Values':
2261
2055
  {
2262
- // `$Values<T>` / `Values<T>` => `T[keyof T]`
2263
2056
  const transformedType = assertHasExactlyNTypeParameters(1)[0];
2264
2057
  return {
2265
2058
  type: 'TSIndexedAccessType',
@@ -2276,7 +2069,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2276
2069
 
2277
2070
  case 'Class':
2278
2071
  {
2279
- // `Class<T>` => `new (...args: any[]) => T`
2280
2072
  const param = assertHasExactlyNTypeParameters(1)[0];
2281
2073
 
2282
2074
  if (param.type !== 'TSTypeReference') {
@@ -2320,8 +2112,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2320
2112
  {
2321
2113
  var _params$;
2322
2114
 
2323
- // `StringPrefix<foo>` => `foo${string}`
2324
- // `StringPrefix<foo, T>` => `foo${T}`
2325
2115
  const params = assertHasTypeParametersInRange(1, 2);
2326
2116
  const prefix = params[0];
2327
2117
 
@@ -2362,8 +2152,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2362
2152
  {
2363
2153
  var _params$2;
2364
2154
 
2365
- // `StringSuffix<foo>` => `${string}foo`
2366
- // `StringSuffix<foo, T>` => `${T}foo`
2367
2155
  const params = assertHasTypeParametersInRange(1, 2);
2368
2156
  const suffix = params[0];
2369
2157
 
@@ -2399,20 +2187,13 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2399
2187
  types: [remainder]
2400
2188
  };
2401
2189
  }
2402
- } // React special conversion:
2403
-
2190
+ }
2404
2191
 
2405
2192
  const validReactImportOrGlobal = isValidReactImportOrGlobal(baseId);
2406
2193
  const hasReactImport = isReactImport(baseId, baseId.name);
2407
2194
 
2408
2195
  if (validReactImportOrGlobal || hasReactImport) {
2409
2196
  switch (fullTypeName) {
2410
- // TODO: In flow this is `ChildrenArray<T> = T | $ReadOnlyArray<ChildrenArray<T>>`.
2411
- // The recursive nature of it is rarely needed, so we're simplifying this for now
2412
- // but omitting that aspect. Once we're able to provide utility types for our translations,
2413
- // we should update this.
2414
- // React.ChildrenArray<T> -> T | ReadonlyArray<T>
2415
- // React$ChildrenArray<T> -> T | ReadonlyArray<T>
2416
2197
  case 'React.ChildrenArray':
2417
2198
  case 'React$ChildrenArray':
2418
2199
  {
@@ -2428,7 +2209,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2428
2209
  loc: DUMMY_LOC,
2429
2210
  name: 'ReadonlyArray'
2430
2211
  },
2431
- typeParameters: {
2212
+ typeArguments: {
2432
2213
  type: 'TSTypeParameterInstantiation',
2433
2214
  loc: DUMMY_LOC,
2434
2215
  params: [param]
@@ -2436,8 +2217,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2436
2217
  }]
2437
2218
  };
2438
2219
  }
2439
- // React.Component<A,B> -> React.Component<A,B>
2440
- // React$Component<A,B> -> React.Component<A,B>
2441
2220
 
2442
2221
  case 'React.Component':
2443
2222
  case 'React$Component':
@@ -2467,15 +2246,13 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2467
2246
  name: 'Component'
2468
2247
  }
2469
2248
  },
2470
- typeParameters: {
2249
+ typeArguments: {
2471
2250
  type: 'TSTypeParameterInstantiation',
2472
2251
  loc: DUMMY_LOC,
2473
2252
  params: params.map(param => transformTypeAnnotationType(param))
2474
2253
  }
2475
2254
  };
2476
2255
  }
2477
- // React.Context<A> -> React.Context<A>
2478
- // React$Context<A> -> React.Context<A>
2479
2256
 
2480
2257
  case 'React$Context':
2481
2258
  case 'React.Context':
@@ -2492,14 +2269,12 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2492
2269
  name: `Context`
2493
2270
  }
2494
2271
  },
2495
- typeParameters: {
2272
+ typeArguments: {
2496
2273
  type: 'TSTypeParameterInstantiation',
2497
2274
  loc: DUMMY_LOC,
2498
2275
  params: assertHasExactlyNTypeParameters(1)
2499
2276
  }
2500
2277
  };
2501
- // React.Key -> React.Key
2502
- // React$Key -> React.Key
2503
2278
 
2504
2279
  case 'React.Key':
2505
2280
  case 'React$Key':
@@ -2518,8 +2293,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2518
2293
  }
2519
2294
  }
2520
2295
  };
2521
- // React.ElementType -> React.ElementType
2522
- // React$ElementType -> React.ElementType
2523
2296
 
2524
2297
  case 'React$ElementType':
2525
2298
  case 'React.ElementType':
@@ -2538,10 +2311,9 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2538
2311
  name: `ElementType`
2539
2312
  }
2540
2313
  },
2541
- typeParameters: undefined
2314
+ typeArguments: undefined
2542
2315
  };
2543
2316
  }
2544
- // React.Node -> React.ReactNode
2545
2317
 
2546
2318
  case 'React$Node':
2547
2319
  case 'React.Node':
@@ -2560,10 +2332,9 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2560
2332
  name: `ReactNode`
2561
2333
  }
2562
2334
  },
2563
- typeParameters: undefined
2335
+ typeArguments: undefined
2564
2336
  };
2565
2337
  }
2566
- // React.Element<typeof Component> -> React.ReactElement<typeof Component>
2567
2338
 
2568
2339
  case 'React$Element':
2569
2340
  case 'React.Element':
@@ -2581,15 +2352,13 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2581
2352
  name: `ReactElement`
2582
2353
  }
2583
2354
  },
2584
- typeParameters: {
2355
+ typeArguments: {
2585
2356
  type: 'TSTypeParameterInstantiation',
2586
2357
  loc: DUMMY_LOC,
2587
2358
  params: assertHasExactlyNTypeParameters(1)
2588
2359
  }
2589
2360
  };
2590
2361
  }
2591
- // React.ElementRef<typeof Component> -> React.ComponentRef<typeof Component>
2592
- // React$ElementRef<typeof Component> -> React.ComponentRef<typeof Component>
2593
2362
 
2594
2363
  case 'React$ElementRef':
2595
2364
  case 'React.ElementRef':
@@ -2606,14 +2375,12 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2606
2375
  name: `ComponentRef`
2607
2376
  }
2608
2377
  },
2609
- typeParameters: {
2378
+ typeArguments: {
2610
2379
  type: 'TSTypeParameterInstantiation',
2611
2380
  loc: DUMMY_LOC,
2612
2381
  params: assertHasExactlyNTypeParameters(1)
2613
2382
  }
2614
2383
  };
2615
- // React$Fragment -> React.Fragment
2616
- // React.Fragment -> React.Fragment
2617
2384
 
2618
2385
  case 'React$FragmentType':
2619
2386
  case 'React.Fragment':
@@ -2632,7 +2399,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2632
2399
  }
2633
2400
  }
2634
2401
  };
2635
- // React.MixedElement -> React.JSX.Element
2636
2402
 
2637
2403
  case 'React$MixedElement':
2638
2404
  case 'React.MixedElement':
@@ -2664,11 +2430,9 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2664
2430
  name: 'Element'
2665
2431
  }
2666
2432
  },
2667
- typeParameters: undefined
2433
+ typeArguments: undefined
2668
2434
  };
2669
2435
  }
2670
- // React.ComponentType<Config> -> React.ComponentType<Config>
2671
- // React$ComponentType<Config> -> React.ComponentType<Config>
2672
2436
 
2673
2437
  case 'React.ComponentType':
2674
2438
  case 'React$ComponentType':
@@ -2686,17 +2450,13 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2686
2450
  name: 'ComponentType'
2687
2451
  }
2688
2452
  },
2689
- typeParameters: {
2453
+ typeArguments: {
2690
2454
  type: 'TSTypeParameterInstantiation',
2691
2455
  loc: DUMMY_LOC,
2692
2456
  params: assertHasExactlyNTypeParameters(1)
2693
2457
  }
2694
2458
  };
2695
2459
  }
2696
- // React.AbstractComponent<Config> -> React.ComponentType<Config>
2697
- // React$AbstractComponent<Config> -> React.ComponentType<Config>
2698
- // React.AbstractComponent<Config, Instance> -> React.ComponentType<Config & React.RefAttributes<Instance>>
2699
- // React$AbstractComponent<Config, Instance> -> React.ComponentType<Config & React.RefAttributes<Instance>>
2700
2460
 
2701
2461
  case 'React.AbstractComponent':
2702
2462
  case 'React$AbstractComponent':
@@ -2740,7 +2500,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2740
2500
  name: 'RefAttributes'
2741
2501
  }
2742
2502
  },
2743
- typeParameters: {
2503
+ typeArguments: {
2744
2504
  type: 'TSTypeParameterInstantiation',
2745
2505
  loc: DUMMY_LOC,
2746
2506
  params: [ref]
@@ -2762,15 +2522,13 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2762
2522
  name: 'ComponentType'
2763
2523
  }
2764
2524
  },
2765
- typeParameters: {
2525
+ typeArguments: {
2766
2526
  type: 'TSTypeParameterInstantiation',
2767
2527
  loc: DUMMY_LOC,
2768
2528
  params: newParams
2769
2529
  }
2770
2530
  };
2771
2531
  }
2772
- // React.ElementProps<A> -> React.ComponentProps<A>
2773
- // React$ElementProps<A> -> React.ComponentProps<A>
2774
2532
 
2775
2533
  case 'React.ElementProps':
2776
2534
  case 'React$ElementProps':
@@ -2788,15 +2546,13 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2788
2546
  name: 'ComponentProps'
2789
2547
  }
2790
2548
  },
2791
- typeParameters: {
2549
+ typeArguments: {
2792
2550
  type: 'TSTypeParameterInstantiation',
2793
2551
  loc: DUMMY_LOC,
2794
2552
  params: assertHasExactlyNTypeParameters(1)
2795
2553
  }
2796
2554
  };
2797
2555
  }
2798
- // React.ElementConfig<A> -> React.JSX.LibraryManagedAttributes<A, React.ComponentProps<A>>
2799
- // React$ElementConfig<A> -> React.JSX.LibraryManagedAttributes<A, React.ComponentProps<A>>
2800
2556
 
2801
2557
  case 'React.ElementConfig':
2802
2558
  case 'React$ElementConfig':
@@ -2828,7 +2584,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2828
2584
  name: 'LibraryManagedAttributes'
2829
2585
  }
2830
2586
  },
2831
- typeParameters: {
2587
+ typeArguments: {
2832
2588
  type: 'TSTypeParameterInstantiation',
2833
2589
  loc: DUMMY_LOC,
2834
2590
  params: [param, {
@@ -2844,7 +2600,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2844
2600
  name: `ComponentProps`
2845
2601
  }
2846
2602
  },
2847
- typeParameters: {
2603
+ typeArguments: {
2848
2604
  type: 'TSTypeParameterInstantiation',
2849
2605
  loc: DUMMY_LOC,
2850
2606
  params: [param]
@@ -2853,8 +2609,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2853
2609
  }
2854
2610
  };
2855
2611
  }
2856
- // React.RefSetter<C> -> React.Ref<C>
2857
- // React$RefSetter<C> -> React.Ref<C>
2858
2612
 
2859
2613
  case 'React.RefSetter':
2860
2614
  case 'React$RefSetter':
@@ -2871,7 +2625,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2871
2625
  name: 'Ref'
2872
2626
  }
2873
2627
  },
2874
- typeParameters: {
2628
+ typeArguments: {
2875
2629
  type: 'TSTypeParameterInstantiation',
2876
2630
  loc: DUMMY_LOC,
2877
2631
  params: assertHasExactlyNTypeParameters(1)
@@ -2887,7 +2641,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2887
2641
  type: 'TSTypeReference',
2888
2642
  loc: DUMMY_LOC,
2889
2643
  typeName: node.id.type === 'Identifier' ? transform.Identifier(node.id, false) : transform.QualifiedTypeIdentifier(node.id),
2890
- typeParameters: transform.TypeParameterInstantiation(node.typeParameters)
2644
+ typeArguments: transform.TypeParameterInstantiation(node.typeParameters)
2891
2645
  };
2892
2646
  },
2893
2647
 
@@ -2996,24 +2750,20 @@ const getTransforms = (originalCode, scopeManager, opts) => {
2996
2750
  type: 'TSInterfaceHeritage',
2997
2751
  loc: DUMMY_LOC,
2998
2752
  expression: node.id.type === 'QualifiedTypeIdentifier' ? transform.QualifiedTypeIdentifier(node.id) : transform.Identifier(node.id, false),
2999
- typeParameters: transform.TypeParameterInstantiation(node.typeParameters)
2753
+ typeArguments: transform.TypeParameterInstantiation(node.typeParameters)
3000
2754
  };
3001
2755
  },
3002
2756
 
3003
2757
  InterfaceTypeAnnotation(node) {
3004
2758
  if (node.extends) {
3005
- // type T = interface extends U, V { ... }
3006
- // to
3007
- // type T = U & V & { ... }
3008
2759
  return {
3009
2760
  type: 'TSIntersectionType',
3010
2761
  loc: DUMMY_LOC,
3011
2762
  types: [...node.extends.map(ex => ({
3012
2763
  type: 'TSTypeReference',
3013
2764
  loc: DUMMY_LOC,
3014
- // Bug: ex.id can be qualified
3015
2765
  typeName: transform.Identifier(ex.id, false),
3016
- typeParameters: transform.TypeParameterInstantiation(ex.typeParameters)
2766
+ typeArguments: transform.TypeParameterInstantiation(ex.typeParameters)
3017
2767
  })), transform.ObjectTypeAnnotation(node.body)]
3018
2768
  };
3019
2769
  }
@@ -3075,8 +2825,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3075
2825
  },
3076
2826
 
3077
2827
  NullableTypeAnnotation(node) {
3078
- // TS doesn't support the maybe type, so have to explicitly union in `null | undefined`
3079
- // `?T` becomes `null | undefined | T`
3080
2828
  return {
3081
2829
  type: 'TSUnionType',
3082
2830
  loc: DUMMY_LOC,
@@ -3123,7 +2871,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3123
2871
  if (node.properties.length === 1 && node.properties[0].type === 'ObjectTypeMappedTypeProperty') {
3124
2872
  var _prop$variance, _prop$variance2;
3125
2873
 
3126
- // Mapped Object Object types must not have other object properties.
3127
2874
  const prop = node.properties[0];
3128
2875
  const tsProp = {
3129
2876
  type: 'TSMappedType',
@@ -3152,11 +2899,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3152
2899
  nameType: null
3153
2900
  };
3154
2901
  return tsProp;
3155
- } // we want to preserve the source order of the members
3156
- // unfortunately flow has unordered properties storing things
3157
- // so store all elements with their start index and sort the
3158
- // list afterward
3159
-
2902
+ }
3160
2903
 
3161
2904
  const members = [];
3162
2905
 
@@ -3173,12 +2916,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3173
2916
  node: transform.ObjectTypeIndexer(indexer)
3174
2917
  });
3175
2918
  }
3176
- /*
3177
- TODO - internalSlots
3178
- I don't think there's anything analogous in TS.
3179
- They're really rarely used (if ever) - so let's just ignore them for now
3180
- */
3181
-
3182
2919
 
3183
2920
  if (node.internalSlots.length > 0) {
3184
2921
  return unsupportedAnnotation(node.internalSlots[0], 'internal slots');
@@ -3187,8 +2924,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3187
2924
  if (!node.properties.find(FlowESTree.isObjectTypeSpreadProperty)) {
3188
2925
  for (const property of node.properties) {
3189
2926
  if (property.type === 'ObjectTypeSpreadProperty') {
3190
- // this is imposible due to the above find condition
3191
- // this check is purely to satisfy flow
3192
2927
  throw unexpectedTranslationError(property, 'Impossible state');
3193
2928
  }
3194
2929
 
@@ -3211,67 +2946,8 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3211
2946
  members: tsBody
3212
2947
  };
3213
2948
  } else {
3214
- /*
3215
- spreads are a complicate thing for us to handle, sadly.
3216
- in flow type spreads are modelled after object spreads; meaning that for
3217
- { ...A, ...B } - all properties in B will explicitly replace any properties
3218
- in A of the same name.
3219
- ```
3220
- type T1 = { a: string };
3221
- type T2 = { a: number };
3222
- type T3 = { ...T1, ...T2 };
3223
- type A = T3['a'] // === number
3224
- ```
3225
- however in TS there are no object type spreads - you can only merge
3226
- objects either via the intersection operator or via interface extends.
3227
- For an interface extends - `interface B extends A { ... }` - TS enforces
3228
- that the properties of B are all covariantly related to the same named
3229
- properties in A.
3230
- So we can't use an interface extends.
3231
- For a type intersection - `type T = A & B;` - TS will (essentially) merge
3232
- the types by intersecting each same named property in each type to calculate
3233
- the resulting type. This has the effect of enforcing the same constraint
3234
- as the interface case, however instead of an error it causes properties to
3235
- become `never`:
3236
- ```
3237
- type T1 = { a: string };
3238
- type T2 = { a: number };
3239
- type T3 = T1 & T2;
3240
- type A = T3['a'] // === string & number === never
3241
- ```
3242
- So in order for us to model flow's spreads we have to explicitly omit the keys
3243
- from the proceeding type that might clash. We can do this pretty easily using
3244
- TS's utility types:
3245
- ```
3246
- type T1 = { a: string };
3247
- type T2 = { a: number };
3248
- type T3 = Omit<T1, keyof T2> & T2;
3249
- type A = T3['a'] // === number
3250
- ```
3251
- Unfortunately because we need to solve for the general case object type usage,
3252
- it's going to be a bit ugly and complicated, sadly.
3253
- If we had access to type information we would be able to skip some ugliness by
3254
- checking to see if there is any overlap and skipping the omit step if there isn't.
3255
- But alas - we're working purely syntactically.
3256
- ```
3257
- type T = { ...T1, b: string };
3258
- // becomes
3259
- type T = Omit<T1, keyof { b: string }> & { b: string };
3260
- ```
3261
- ```
3262
- type T = { ...T1, ...T2, ...T3, b: string };
3263
- // becomes
3264
- type T =
3265
- & Omit<T1, keyof T2 | keyof T3 | keyof { b: string }>
3266
- & Omit<T2, keyof T3 | keyof { b: string }>
3267
- & Omit<T3, keyof { b: string }>
3268
- & { b: string };
3269
- ```
3270
- Note that because it's going to be super ugly and complicated - for now we're going to disallow:
3271
- - spreads in the middle
3272
- - spreads at the end
3273
- - spreads of things that aren't "Identifiers"
3274
- */
2949
+ var _extractPropertyKeyLi;
2950
+
3275
2951
  if (members.length > 0) {
3276
2952
  return unsupportedAnnotation(node, 'object types with spreads, indexers and/or call properties at the same time');
3277
2953
  }
@@ -3292,7 +2968,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3292
2968
 
3293
2969
  typesToIntersect.push(spreadType);
3294
2970
  } else if (property.type === 'ObjectTypeMappedTypeProperty') {
3295
- // TODO - Support mapped types
3296
2971
  return unsupportedAnnotation(property, 'object type with mapped type property');
3297
2972
  } else {
3298
2973
  members.push({
@@ -3310,11 +2985,23 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3310
2985
  loc: DUMMY_LOC,
3311
2986
  members: tsBody
3312
2987
  };
2988
+ const objectKeyTypes = (_extractPropertyKeyLi = (0, _TSNodeUtils.extractPropertyKeyLiterals)(tsBody)) != null ? _extractPropertyKeyLi : [{
2989
+ type: 'TSTypeOperator',
2990
+ loc: DUMMY_LOC,
2991
+ operator: 'keyof',
2992
+ typeAnnotation: objectType
2993
+ }];
3313
2994
  const intersectionMembers = [];
3314
2995
 
3315
2996
  for (let i = 0; i < typesToIntersect.length; i += 1) {
3316
2997
  const currentType = typesToIntersect[i];
3317
2998
  const remainingTypes = typesToIntersect.slice(i + 1);
2999
+ const omitKeyTypes = [...remainingTypes.map(t => ({
3000
+ type: 'TSTypeOperator',
3001
+ loc: DUMMY_LOC,
3002
+ operator: 'keyof',
3003
+ typeAnnotation: t
3004
+ })), ...objectKeyTypes];
3318
3005
  intersectionMembers.push({
3319
3006
  type: 'TSTypeReference',
3320
3007
  loc: DUMMY_LOC,
@@ -3323,23 +3010,13 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3323
3010
  loc: DUMMY_LOC,
3324
3011
  name: 'Omit'
3325
3012
  },
3326
- typeParameters: {
3013
+ typeArguments: {
3327
3014
  type: 'TSTypeParameterInstantiation',
3328
3015
  loc: DUMMY_LOC,
3329
- params: [currentType, {
3016
+ params: [currentType, omitKeyTypes.length === 1 ? omitKeyTypes[0] : {
3330
3017
  type: 'TSUnionType',
3331
3018
  loc: DUMMY_LOC,
3332
- types: [...remainingTypes.map(t => ({
3333
- type: 'TSTypeOperator',
3334
- loc: DUMMY_LOC,
3335
- operator: 'keyof',
3336
- typeAnnotation: t
3337
- })), {
3338
- type: 'TSTypeOperator',
3339
- loc: DUMMY_LOC,
3340
- operator: 'keyof',
3341
- typeAnnotation: objectType
3342
- }]
3019
+ types: omitKeyTypes
3343
3020
  }]
3344
3021
  }
3345
3022
  });
@@ -3355,7 +3032,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3355
3032
  },
3356
3033
 
3357
3034
  ObjectTypeCallProperty(node) {
3358
- // the info is stored on the "value"
3359
3035
  const func = transform.FunctionTypeAnnotation(node.value);
3360
3036
  return {
3361
3037
  type: 'TSCallSignatureDeclaration',
@@ -3464,10 +3140,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3464
3140
  })();
3465
3141
 
3466
3142
  if (node.method === true) {
3467
- // flow has just one node for all object properties and relies upon the method flag
3468
- // TS has separate nodes for methods and properties
3469
- const func = transform.FunctionTypeAnnotation(node.value); // $FlowFixMe[incompatible-type] `computed` is set dynamically
3470
-
3143
+ const func = transform.FunctionTypeAnnotation(node.value);
3471
3144
  return {
3472
3145
  type: 'TSMethodSignature',
3473
3146
  loc: DUMMY_LOC,
@@ -3483,10 +3156,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3483
3156
  }
3484
3157
 
3485
3158
  if (node.kind === 'get' || node.kind === 'set') {
3486
- // flow treats getters/setters as true property signatures (method === false)
3487
- // TS treats them as method signatures
3488
- const func = transform.FunctionTypeAnnotation(node.value); // $FlowFixMe[incompatible-type] `computed` is set dynamically
3489
-
3159
+ const func = transform.FunctionTypeAnnotation(node.value);
3490
3160
  return {
3491
3161
  type: 'TSMethodSignature',
3492
3162
  loc: DUMMY_LOC,
@@ -3495,14 +3165,11 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3495
3165
  kind: node.kind,
3496
3166
  optional: false,
3497
3167
  params: func.params,
3498
- // TS setters must not have a return type
3499
3168
  returnType: node.kind === 'set' ? undefined : func.returnType,
3500
3169
  static: node.static,
3501
- // TS accessors cannot have type parameters
3502
3170
  typeParameters: undefined
3503
3171
  };
3504
- } // $FlowFixMe[incompatible-type] `computed` is set dynamically
3505
-
3172
+ }
3506
3173
 
3507
3174
  return {
3508
3175
  type: 'TSPropertySignature',
@@ -3525,14 +3192,9 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3525
3192
  },
3526
3193
 
3527
3194
  OptionalIndexedAccessType(node) {
3528
- // Foo?.[A][B]
3529
- // ^^^^^^^^ optional = true
3530
- // ^^^^^^^^^^^ optional = false
3531
3195
  if (node.optional === false) {
3532
3196
  return transform.IndexedAccessType(node);
3533
- } // TS doesn't support optional index access so we have to wrap the object:
3534
- // `T?.[K]` becomes `NonNullable<T>[K]`
3535
-
3197
+ }
3536
3198
 
3537
3199
  return {
3538
3200
  type: 'TSIndexedAccessType',
@@ -3545,7 +3207,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3545
3207
  loc: DUMMY_LOC,
3546
3208
  name: 'NonNullable'
3547
3209
  },
3548
- typeParameters: {
3210
+ typeArguments: {
3549
3211
  type: 'TSTypeParameterInstantiation',
3550
3212
  loc: DUMMY_LOC,
3551
3213
  params: [transformTypeAnnotationType(node.objectType)]
@@ -3712,7 +3374,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3712
3374
  type: 'TSTypeQuery',
3713
3375
  loc: DUMMY_LOC,
3714
3376
  exprName: transform.Identifier(node.argument),
3715
- typeParameters: undefined
3377
+ typeArguments: undefined
3716
3378
  };
3717
3379
 
3718
3380
  case 'QualifiedTypeofIdentifier':
@@ -3720,31 +3382,12 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3720
3382
  type: 'TSTypeQuery',
3721
3383
  loc: DUMMY_LOC,
3722
3384
  exprName: transform.QualifiedTypeofIdentifier(node.argument),
3723
- typeParameters: undefined
3385
+ typeArguments: undefined
3724
3386
  };
3725
3387
  }
3726
3388
  },
3727
3389
 
3728
3390
  TypeParameter(node) {
3729
- /*
3730
- TODO - flow models variance as explicit syntax, but but TS resolves it automatically
3731
- TS does have syntax for explicit variance, but you can introduce a TS error if the
3732
- marked parameter isn't used in the location that TS expects them to be in.
3733
- To make it easier for now let's just rely on TS's auto-resolution.
3734
- ```
3735
- const variance =
3736
- new Set(
3737
- node.variance == null
3738
- ? // by default flow generics act invariantly
3739
- ['in', 'out']
3740
- : node.variance.kind === 'plus'
3741
- ? // covariant
3742
- ['out']
3743
- : // contravariant
3744
- ['in'],
3745
- );
3746
- ```
3747
- */
3748
3391
  return {
3749
3392
  type: 'TSTypeParameter',
3750
3393
  loc: DUMMY_LOC,
@@ -3756,9 +3399,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3756
3399
  constraint: node.bound == null ? undefined : transformTypeAnnotationType(node.bound.typeAnnotation),
3757
3400
  default: node.default == null ? undefined : transformTypeAnnotationType(node.default),
3758
3401
  in: false,
3759
- out: false // in: variance.has('in'),
3760
- // out: variance.has('out'),
3761
-
3402
+ out: false
3762
3403
  };
3763
3404
  },
3764
3405
 
@@ -3771,8 +3412,6 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3771
3412
  },
3772
3413
 
3773
3414
  TypeParameterInstantiation(node) {
3774
- // Empty parameters in Flow are valid, but TS requires at least one parameter.
3775
- // This ensures empty type parameters are not created in TS
3776
3415
  if (node == null || node.params.length === 0) {
3777
3416
  return undefined;
3778
3417
  }
@@ -3882,7 +3521,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3882
3521
  name: `ReactNode`
3883
3522
  }
3884
3523
  },
3885
- typeParameters: undefined
3524
+ typeArguments: undefined
3886
3525
  };
3887
3526
  }
3888
3527
  }
@@ -3890,13 +3529,11 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3890
3529
 
3891
3530
  ComponentTypeAnnotation(node) {
3892
3531
  const typeParameters = node.typeParameters == null ? undefined : transform.TypeParameterDeclaration(node.typeParameters);
3893
- const params = transform.ComponentTypeParameters(node.params, node.rest); // TS cannot support `renderType` so we always use ReactNode as the return type.
3894
-
3532
+ const params = transform.ComponentTypeParameters(node.params, node.rest);
3895
3533
  const hasReactImport = isReactImport(node, 'React');
3896
3534
  const returnType = {
3897
3535
  type: 'TSTypeAnnotation',
3898
3536
  loc: DUMMY_LOC,
3899
- // If no rendersType we assume its ReactNode type.
3900
3537
  typeAnnotation: {
3901
3538
  type: 'TSTypeReference',
3902
3539
  loc: DUMMY_LOC,
@@ -3910,7 +3547,7 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3910
3547
  name: `ReactNode`
3911
3548
  }
3912
3549
  },
3913
- typeParameters: undefined
3550
+ typeArguments: undefined
3914
3551
  }
3915
3552
  };
3916
3553
  return {
@@ -3922,12 +3559,10 @@ const getTransforms = (originalCode, scopeManager, opts) => {
3922
3559
  };
3923
3560
  }
3924
3561
 
3925
- }; // wrap each transform so that we automatically preserve jsdoc comments
3926
- // this just saves us manually wiring up every single case
3562
+ };
3927
3563
 
3928
3564
  for (const key of Object.keys(transform)) {
3929
- const originalFn = transform[key]; // $FlowExpectedError[cannot-write]
3930
- // $FlowExpectedError[missing-local-annot]
3565
+ const originalFn = transform[key];
3931
3566
 
3932
3567
  transform[key] = (node, ...args) => {
3933
3568
  const result = originalFn(node, ...args);