flow-api-translator 0.36.1 → 0.327.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.
Files changed (37) hide show
  1. package/dist/TSDefToFlowDef.js +66 -327
  2. package/dist/TSDefToFlowDef.js.flow +70 -35
  3. package/dist/flowDefToTSDef.js +134 -825
  4. package/dist/flowDefToTSDef.js.flow +196 -100
  5. package/dist/flowImportTo.js +5 -25
  6. package/dist/flowImportTo.js.flow +4 -4
  7. package/dist/flowToFlowDef.js +190 -379
  8. package/dist/flowToFlowDef.js.flow +109 -27
  9. package/dist/flowToJS.js +3 -19
  10. package/dist/flowToJS.js.flow +5 -5
  11. package/dist/index.js +12 -50
  12. package/dist/index.js.flow +1 -1
  13. package/dist/src/TSDefToFlowDef.js +66 -327
  14. package/dist/src/flowDefToTSDef.js +134 -825
  15. package/dist/src/flowImportTo.js +5 -25
  16. package/dist/src/flowToFlowDef.js +190 -379
  17. package/dist/src/flowToJS.js +3 -19
  18. package/dist/src/index.js +12 -50
  19. package/dist/src/utils/DocblockUtils.js +4 -14
  20. package/dist/src/utils/ErrorUtils.js +4 -40
  21. package/dist/src/utils/FlowAnalyze.js +8 -28
  22. package/dist/src/utils/TSNodeUtils.js +83 -0
  23. package/dist/src/utils/TranslationUtils.js +0 -13
  24. package/dist/src/utils/ts-estree-ast-types.js +0 -29
  25. package/dist/utils/DocblockUtils.js +4 -14
  26. package/dist/utils/DocblockUtils.js.flow +1 -1
  27. package/dist/utils/ErrorUtils.js +4 -40
  28. package/dist/utils/ErrorUtils.js.flow +6 -6
  29. package/dist/utils/FlowAnalyze.js +8 -28
  30. package/dist/utils/FlowAnalyze.js.flow +9 -4
  31. package/dist/utils/TSNodeUtils.js +83 -0
  32. package/dist/utils/TSNodeUtils.js.flow +108 -0
  33. package/dist/utils/TranslationUtils.js +0 -13
  34. package/dist/utils/TranslationUtils.js.flow +2 -2
  35. package/dist/utils/ts-estree-ast-types.js +0 -29
  36. package/dist/utils/ts-estree-ast-types.js.flow +697 -740
  37. package/package.json +10 -9
@@ -10,22 +10,26 @@
10
10
 
11
11
  'use strict';
12
12
 
13
- import type {ObjectWithLoc} from 'hermes-estree';
13
+ import type {ObjectWithLoc} from 'flow-estree';
14
14
  import type {TranslationOptions} from './utils/TranslationUtils';
15
- import type {ScopeManager} from 'hermes-eslint';
15
+ import type {ScopeManager} from 'flow-eslint';
16
16
 
17
- import * as FlowESTree from 'hermes-estree';
17
+ import * as FlowESTree from 'flow-estree';
18
18
  import * as TSESTree from './utils/ts-estree-ast-types';
19
19
  import {
20
20
  cloneJSDocCommentsToNewNode as cloneJSDocCommentsToNewNodeOriginal,
21
21
  makeCommentOwnLine as makeCommentOwnLineOriginal,
22
- } from 'hermes-transform';
22
+ } from 'flow-transform';
23
23
  import {
24
24
  buildCodeFrame,
25
25
  translationError as translationErrorBase,
26
26
  unexpectedTranslationError as unexpectedTranslationErrorBase,
27
27
  } from './utils/ErrorUtils';
28
28
  import {removeAtFlowFromDocblock} from './utils/DocblockUtils';
29
+ import {
30
+ ensureTypeIncludesUndefined,
31
+ extractPropertyKeyLiterals,
32
+ } from './utils/TSNodeUtils';
29
33
  import {EOL} from 'os';
30
34
 
31
35
  type DeclarationOrUnsupported<T> = T | TSESTree.TSTypeAliasDeclaration;
@@ -35,23 +39,82 @@ const DUMMY_LOC: FlowESTree.SourceLocation = {
35
39
  end: {line: 1, column: 0},
36
40
  };
37
41
 
38
- type LooseOmit<O: interface {}, K: $Keys<$FlowFixMe>> = Pick<
42
+ type LooseOmit<O extends interface {}, K extends keyof $FlowFixMe> = Pick<
39
43
  O,
40
- Exclude<$Keys<O>, K>,
44
+ Exclude<keyof O, K>,
41
45
  >;
42
- function constructFlowNode<T: FlowESTree.BaseNode>(
46
+ function constructFlowNode<T extends FlowESTree.BaseNode>(
43
47
  node: LooseOmit<NoInfer<T>, 'parent'>,
44
48
  ): T {
45
- return (node: $FlowFixMe);
49
+ return node as $FlowFixMe;
46
50
  }
47
51
 
48
52
  const cloneJSDocCommentsToNewNode =
49
53
  // $FlowExpectedError[incompatible-type] - trust me this re-type is 100% safe
50
- (cloneJSDocCommentsToNewNodeOriginal: (mixed, mixed) => void);
54
+ cloneJSDocCommentsToNewNodeOriginal as (unknown, unknown) => void;
51
55
 
52
56
  const makeCommentOwnLine =
53
57
  // $FlowExpectedError[incompatible-type] - trust me this re-type is 100% safe
54
- (makeCommentOwnLineOriginal: (string, mixed) => string);
58
+ makeCommentOwnLineOriginal as (string, unknown) => string;
59
+
60
+ /**
61
+ * `DeclareComponent` reaches us in one of two shapes: parsed nodes carry
62
+ * `ComponentParameter`/`RestElement` in `params` with a null `rest` (the
63
+ * `ComponentDeclaration` shape the Flow parser reuses here), while detached
64
+ * nodes built with `flow-transform` use `ComponentTypeParameter` + `rest`.
65
+ * Normalize both onto the latter so the shared `ComponentTypeParameters`
66
+ * translation — which `ComponentTypeAnnotation` also uses — sees one shape.
67
+ */
68
+ function normalizeDeclareComponentParams(
69
+ params: FlowESTree.DeclareComponent['params'],
70
+ rest: FlowESTree.DeclareComponent['rest'],
71
+ onUnexpected: (node: ObjectWithLoc, message: string) => Error,
72
+ ): [
73
+ ReadonlyArray<FlowESTree.ComponentTypeParameter>,
74
+ FlowESTree.ComponentTypeParameter | null,
75
+ ] {
76
+ const normalizedParams: Array<FlowESTree.ComponentTypeParameter> = [];
77
+ let normalizedRest: FlowESTree.ComponentTypeParameter | null = rest;
78
+
79
+ const toComponentTypeParameter = (
80
+ name: FlowESTree.ComponentTypeParameter['name'],
81
+ local: FlowESTree.ESNode,
82
+ source: FlowESTree.BaseToken,
83
+ ): FlowESTree.ComponentTypeParameter => {
84
+ if (local.type !== 'Identifier' || local.typeAnnotation == null) {
85
+ throw onUnexpected(
86
+ source,
87
+ `DeclareComponent: expected an annotated identifier parameter, got "${local.type}"`,
88
+ );
89
+ }
90
+ return constructFlowNode<FlowESTree.ComponentTypeParameter>({
91
+ type: 'ComponentTypeParameter',
92
+ name,
93
+ typeAnnotation: local.typeAnnotation.typeAnnotation,
94
+ optional: local.optional,
95
+ loc: source.loc,
96
+ range: source.range,
97
+ });
98
+ };
99
+
100
+ for (const param of params) {
101
+ switch (param.type) {
102
+ case 'ComponentTypeParameter':
103
+ normalizedParams.push(param);
104
+ break;
105
+ case 'ComponentParameter':
106
+ normalizedParams.push(
107
+ toComponentTypeParameter(param.name, param.local, param),
108
+ );
109
+ break;
110
+ case 'RestElement':
111
+ normalizedRest = toComponentTypeParameter(null, param.argument, param);
112
+ break;
113
+ }
114
+ }
115
+
116
+ return [normalizedParams, normalizedRest];
117
+ }
55
118
 
56
119
  const VALID_REACT_IMPORTS = new Set<string>(['React', 'react']);
57
120
 
@@ -180,7 +243,7 @@ const getTransforms = (
180
243
  // $FlowExpectedError[cannot-write]
181
244
  node.comments ??= [];
182
245
  // $FlowExpectedError[incompatible-type]
183
- (node.comments: Array<TSESTree.Comment>).push(comment);
246
+ (node.comments as Array<TSESTree.Comment>).push(comment);
184
247
  }
185
248
  function unsupportedAnnotation(
186
249
  node: ObjectWithLoc,
@@ -385,12 +448,12 @@ const getTransforms = (
385
448
  loc: DUMMY_LOC,
386
449
  computed: false,
387
450
  id: transform.Identifier(member.id, false),
388
- initializer: ({
451
+ initializer: {
389
452
  type: 'Literal',
390
453
  loc: DUMMY_LOC,
391
454
  raw: `"${member.id.name}"`,
392
455
  value: member.id.name,
393
- }: TSESTree.StringLiteral),
456
+ } as TSESTree.StringLiteral,
394
457
  });
395
458
  break;
396
459
  }
@@ -607,7 +670,7 @@ const getTransforms = (
607
670
  loc: DUMMY_LOC,
608
671
  name: 'IterableIterator',
609
672
  },
610
- typeParameters: {
673
+ typeArguments: {
611
674
  type: 'TSTypeParameterInstantiation',
612
675
  loc: DUMMY_LOC,
613
676
  params: [
@@ -818,13 +881,13 @@ const getTransforms = (
818
881
  return {
819
882
  type: 'TSLiteralType',
820
883
  loc: DUMMY_LOC,
821
- literal: ({
884
+ literal: {
822
885
  type: 'Literal',
823
886
  loc: DUMMY_LOC,
824
887
  value: node.value,
825
888
  raw: node.raw,
826
889
  bigint,
827
- }: TSESTree.BigIntLiteral),
890
+ } as TSESTree.BigIntLiteral,
828
891
  };
829
892
  },
830
893
  BigIntTypeAnnotation(
@@ -849,12 +912,12 @@ const getTransforms = (
849
912
  return {
850
913
  type: 'TSLiteralType',
851
914
  loc: DUMMY_LOC,
852
- literal: ({
915
+ literal: {
853
916
  type: 'Literal',
854
917
  loc: DUMMY_LOC,
855
918
  value: node.value,
856
919
  raw: node.raw,
857
- }: TSESTree.BooleanLiteral),
920
+ } as TSESTree.BooleanLiteral,
858
921
  };
859
922
  },
860
923
  BooleanTypeAnnotation(
@@ -872,7 +935,7 @@ const getTransforms = (
872
935
  type: 'TSClassImplements',
873
936
  loc: DUMMY_LOC,
874
937
  expression: transform.Identifier(node.id, false),
875
- typeParameters: transform.TypeParameterInstantiation(
938
+ typeArguments: transform.TypeParameterInstantiation(
876
939
  node.typeParameters,
877
940
  ),
878
941
  };
@@ -1084,8 +1147,8 @@ const getTransforms = (
1084
1147
  ? null
1085
1148
  : superClass.id.type === 'QualifiedTypeIdentifier'
1086
1149
  ? transform.QualifiedTypeIdentifier(superClass.id)
1087
- : transform.Identifier((superClass.id: $FlowFixMe), false),
1088
- superTypeParameters: transform.TypeParameterInstantiation(
1150
+ : transform.Identifier(superClass.id as $FlowFixMe, false),
1151
+ superTypeArguments: transform.TypeParameterInstantiation(
1089
1152
  superClass?.typeParameters,
1090
1153
  ),
1091
1154
  typeParameters:
@@ -1378,7 +1441,7 @@ const getTransforms = (
1378
1441
  if (node.source === null) {
1379
1442
  // eslint-disable-next-line eqeqeq
1380
1443
  if (node.declaration === null) {
1381
- return ({
1444
+ return {
1382
1445
  type: 'ExportNamedDeclaration',
1383
1446
  loc: DUMMY_LOC,
1384
1447
  // flow does not currently support attributes
@@ -1388,7 +1451,7 @@ const getTransforms = (
1388
1451
  exportKind: 'value',
1389
1452
  source: null,
1390
1453
  specifiers: node.specifiers.map(transform.ExportSpecifier),
1391
- }: TSESTree.ExportNamedDeclarationWithoutSourceWithMultiple);
1454
+ } as TSESTree.ExportNamedDeclarationWithoutSourceWithMultiple;
1392
1455
  }
1393
1456
 
1394
1457
  const declarations = ((): Array<{
@@ -1537,7 +1600,7 @@ const getTransforms = (
1537
1600
 
1538
1601
  return mappedDeclarations.flat();
1539
1602
  } else {
1540
- return ({
1603
+ return {
1541
1604
  type: 'ExportNamedDeclaration',
1542
1605
  loc: DUMMY_LOC,
1543
1606
  // flow does not currently support attributes
@@ -1547,7 +1610,7 @@ const getTransforms = (
1547
1610
  exportKind: 'value',
1548
1611
  source: transform.StringLiteral(node.source),
1549
1612
  specifiers: node.specifiers.map(transform.ExportSpecifier),
1550
- }: TSESTree.ExportNamedDeclarationWithSource);
1613
+ } as TSESTree.ExportNamedDeclarationWithSource;
1551
1614
  }
1552
1615
  }
1553
1616
  },
@@ -1561,7 +1624,15 @@ const getTransforms = (
1561
1624
  ? undefined
1562
1625
  : transform.TypeParameterDeclaration(node.typeParameters);
1563
1626
 
1564
- const params = transform.ComponentTypeParameters(node.params, node.rest);
1627
+ const [declaredParams, declaredRest] = normalizeDeclareComponentParams(
1628
+ node.params,
1629
+ node.rest,
1630
+ unexpectedTranslationError,
1631
+ );
1632
+ const params = transform.ComponentTypeParameters(
1633
+ declaredParams,
1634
+ declaredRest,
1635
+ );
1565
1636
 
1566
1637
  // TS cannot support `renderType` so we always use ReactNode as the return type.
1567
1638
  const hasReactImport = isReactImport(node, 'React');
@@ -1582,7 +1653,7 @@ const getTransforms = (
1582
1653
  name: `ReactNode`,
1583
1654
  },
1584
1655
  },
1585
- typeParameters: undefined,
1656
+ typeArguments: undefined,
1586
1657
  },
1587
1658
  };
1588
1659
 
@@ -1605,9 +1676,9 @@ const getTransforms = (
1605
1676
  };
1606
1677
  },
1607
1678
  ComponentTypeParameters(
1608
- params: $ReadOnlyArray<FlowESTree.ComponentTypeParameter>,
1679
+ params: ReadonlyArray<FlowESTree.ComponentTypeParameter>,
1609
1680
  rest: FlowESTree.ComponentTypeParameter | null,
1610
- ): $ReadOnlyArray<TSESTree.Parameter> {
1681
+ ): ReadonlyArray<TSESTree.Parameter> {
1611
1682
  if (params.length === 0 && rest != null) {
1612
1683
  return [
1613
1684
  {
@@ -1860,15 +1931,21 @@ const getTransforms = (
1860
1931
  type: 'VariableDeclaration',
1861
1932
  loc: DUMMY_LOC,
1862
1933
  declare: true,
1863
- declarations: [
1864
- {
1934
+ declarations: node.declarations.map(declaration => {
1935
+ if (declaration.id.type !== 'Identifier') {
1936
+ throw translationError(
1937
+ declaration.id,
1938
+ `DeclareVariable: unsupported declarator of type "${declaration.id.type}"`,
1939
+ );
1940
+ }
1941
+ return {
1865
1942
  type: 'VariableDeclarator',
1866
1943
  loc: DUMMY_LOC,
1867
1944
  declare: true,
1868
- id: transform.Identifier(node.id, true),
1945
+ id: transform.Identifier(declaration.id, true),
1869
1946
  init: null,
1870
- },
1871
- ],
1947
+ };
1948
+ }),
1872
1949
  kind: node.kind,
1873
1950
  };
1874
1951
  },
@@ -1974,7 +2051,7 @@ const getTransforms = (
1974
2051
  })();
1975
2052
 
1976
2053
  const mainExport = {
1977
- type: ('ExportNamedDeclaration': 'ExportNamedDeclaration'),
2054
+ type: 'ExportNamedDeclaration' as 'ExportNamedDeclaration',
1978
2055
  loc: DUMMY_LOC,
1979
2056
  assertions: [],
1980
2057
  declaration: exportedDeclaration,
@@ -2112,7 +2189,7 @@ const getTransforms = (
2112
2189
 
2113
2190
  const assertHasExactlyNTypeParameters = (
2114
2191
  count: number,
2115
- ): $ReadOnlyArray<TSESTree.TypeNode> => {
2192
+ ): ReadonlyArray<TSESTree.TypeNode> => {
2116
2193
  if (node.typeParameters != null) {
2117
2194
  if (node.typeParameters.params.length !== count) {
2118
2195
  throw translationError(
@@ -2143,7 +2220,7 @@ const getTransforms = (
2143
2220
  function assertHasTypeParametersInRange(
2144
2221
  min: number,
2145
2222
  max: number,
2146
- ): $ReadOnlyArray<TSESTree.TypeNode> {
2223
+ ): ReadonlyArray<TSESTree.TypeNode> {
2147
2224
  const {typeParameters} = node;
2148
2225
  if (typeParameters == null) {
2149
2226
  if (min > 0) {
@@ -2219,7 +2296,7 @@ const getTransforms = (
2219
2296
  loc: DUMMY_LOC,
2220
2297
  name: 'ArrayLike',
2221
2298
  },
2222
- typeParameters: {
2299
+ typeArguments: {
2223
2300
  type: 'TSTypeParameterInstantiation',
2224
2301
  loc: DUMMY_LOC,
2225
2302
  params: assertHasExactlyNTypeParameters(1),
@@ -2239,7 +2316,7 @@ const getTransforms = (
2239
2316
  loc: DUMMY_LOC,
2240
2317
  name: 'Pick',
2241
2318
  },
2242
- typeParameters: {
2319
+ typeArguments: {
2243
2320
  type: 'TSTypeParameterInstantiation',
2244
2321
  loc: DUMMY_LOC,
2245
2322
  params: [
@@ -2252,7 +2329,7 @@ const getTransforms = (
2252
2329
  loc: DUMMY_LOC,
2253
2330
  name: 'Exclude',
2254
2331
  },
2255
- typeParameters: {
2332
+ typeArguments: {
2256
2333
  type: 'TSTypeParameterInstantiation',
2257
2334
  loc: DUMMY_LOC,
2258
2335
  params: [
@@ -2309,7 +2386,7 @@ const getTransforms = (
2309
2386
  }
2310
2387
 
2311
2388
  // New AST format for `typeof import('module')`
2312
- return ({
2389
+ return {
2313
2390
  type: 'TSTypeQuery',
2314
2391
  loc: DUMMY_LOC,
2315
2392
  exprName: {
@@ -2317,9 +2394,11 @@ const getTransforms = (
2317
2394
  loc: DUMMY_LOC,
2318
2395
  argument: moduleName,
2319
2396
  qualifier: null,
2320
- typeParameters: null,
2397
+ options: null,
2398
+ source: moduleName.literal,
2399
+ typeArguments: null,
2321
2400
  },
2322
- }: $FlowFixMe);
2401
+ } as $FlowFixMe;
2323
2402
  }
2324
2403
 
2325
2404
  case '$FlowFixMe': {
@@ -2397,7 +2476,7 @@ const getTransforms = (
2397
2476
  loc: DUMMY_LOC,
2398
2477
  name: 'NonNullable',
2399
2478
  },
2400
- typeParameters: {
2479
+ typeArguments: {
2401
2480
  type: 'TSTypeParameterInstantiation',
2402
2481
  loc: DUMMY_LOC,
2403
2482
  params: assertHasExactlyNTypeParameters(1),
@@ -2415,7 +2494,7 @@ const getTransforms = (
2415
2494
  loc: DUMMY_LOC,
2416
2495
  name: 'Readonly',
2417
2496
  },
2418
- typeParameters: {
2497
+ typeArguments: {
2419
2498
  type: 'TSTypeParameterInstantiation',
2420
2499
  loc: DUMMY_LOC,
2421
2500
  params: assertHasExactlyNTypeParameters(1),
@@ -2436,7 +2515,7 @@ const getTransforms = (
2436
2515
  loc: DUMMY_LOC,
2437
2516
  name: 'ReadonlyArray',
2438
2517
  },
2439
- typeParameters: {
2518
+ typeArguments: {
2440
2519
  type: 'TSTypeParameterInstantiation',
2441
2520
  loc: DUMMY_LOC,
2442
2521
  params: assertHasExactlyNTypeParameters(1),
@@ -2453,7 +2532,7 @@ const getTransforms = (
2453
2532
  loc: DUMMY_LOC,
2454
2533
  name: 'ReadonlyMap',
2455
2534
  },
2456
- typeParameters: {
2535
+ typeArguments: {
2457
2536
  type: 'TSTypeParameterInstantiation',
2458
2537
  loc: DUMMY_LOC,
2459
2538
  params: assertHasExactlyNTypeParameters(2),
@@ -2470,7 +2549,7 @@ const getTransforms = (
2470
2549
  loc: DUMMY_LOC,
2471
2550
  name: 'ReadonlySet',
2472
2551
  },
2473
- typeParameters: {
2552
+ typeArguments: {
2474
2553
  type: 'TSTypeParameterInstantiation',
2475
2554
  loc: DUMMY_LOC,
2476
2555
  params: assertHasExactlyNTypeParameters(1),
@@ -2640,7 +2719,7 @@ const getTransforms = (
2640
2719
  const hasReactImport = isReactImport(baseId, baseId.name);
2641
2720
  if (validReactImportOrGlobal || hasReactImport) {
2642
2721
  switch (fullTypeName) {
2643
- // TODO: In flow this is `ChildrenArray<T> = T | $ReadOnlyArray<ChildrenArray<T>>`.
2722
+ // TODO: In flow this is `ChildrenArray<T> = T | ReadonlyArray<ChildrenArray<T>>`.
2644
2723
  // The recursive nature of it is rarely needed, so we're simplifying this for now
2645
2724
  // but omitting that aspect. Once we're able to provide utility types for our translations,
2646
2725
  // we should update this.
@@ -2662,7 +2741,7 @@ const getTransforms = (
2662
2741
  loc: DUMMY_LOC,
2663
2742
  name: 'ReadonlyArray',
2664
2743
  },
2665
- typeParameters: {
2744
+ typeArguments: {
2666
2745
  type: 'TSTypeParameterInstantiation',
2667
2746
  loc: DUMMY_LOC,
2668
2747
  params: [param],
@@ -2703,7 +2782,7 @@ const getTransforms = (
2703
2782
  name: 'Component',
2704
2783
  },
2705
2784
  },
2706
- typeParameters: {
2785
+ typeArguments: {
2707
2786
  type: 'TSTypeParameterInstantiation',
2708
2787
  loc: DUMMY_LOC,
2709
2788
  params: params.map(param => transformTypeAnnotationType(param)),
@@ -2728,7 +2807,7 @@ const getTransforms = (
2728
2807
  name: `Context`,
2729
2808
  },
2730
2809
  },
2731
- typeParameters: {
2810
+ typeArguments: {
2732
2811
  type: 'TSTypeParameterInstantiation',
2733
2812
  loc: DUMMY_LOC,
2734
2813
  params: assertHasExactlyNTypeParameters(1),
@@ -2771,7 +2850,7 @@ const getTransforms = (
2771
2850
  name: `ElementType`,
2772
2851
  },
2773
2852
  },
2774
- typeParameters: undefined,
2853
+ typeArguments: undefined,
2775
2854
  };
2776
2855
  }
2777
2856
  // React.Node -> React.ReactNode
@@ -2791,7 +2870,7 @@ const getTransforms = (
2791
2870
  name: `ReactNode`,
2792
2871
  },
2793
2872
  },
2794
- typeParameters: undefined,
2873
+ typeArguments: undefined,
2795
2874
  };
2796
2875
  }
2797
2876
  // React.Element<typeof Component> -> React.ReactElement<typeof Component>
@@ -2810,7 +2889,7 @@ const getTransforms = (
2810
2889
  name: `ReactElement`,
2811
2890
  },
2812
2891
  },
2813
- typeParameters: {
2892
+ typeArguments: {
2814
2893
  type: 'TSTypeParameterInstantiation',
2815
2894
  loc: DUMMY_LOC,
2816
2895
  params: assertHasExactlyNTypeParameters(1),
@@ -2834,7 +2913,7 @@ const getTransforms = (
2834
2913
  name: `ComponentRef`,
2835
2914
  },
2836
2915
  },
2837
- typeParameters: {
2916
+ typeArguments: {
2838
2917
  type: 'TSTypeParameterInstantiation',
2839
2918
  loc: DUMMY_LOC,
2840
2919
  params: assertHasExactlyNTypeParameters(1),
@@ -2889,7 +2968,7 @@ const getTransforms = (
2889
2968
  name: 'Element',
2890
2969
  },
2891
2970
  },
2892
- typeParameters: undefined,
2971
+ typeArguments: undefined,
2893
2972
  };
2894
2973
  }
2895
2974
  // React.ComponentType<Config> -> React.ComponentType<Config>
@@ -2909,7 +2988,7 @@ const getTransforms = (
2909
2988
  name: 'ComponentType',
2910
2989
  },
2911
2990
  },
2912
- typeParameters: {
2991
+ typeArguments: {
2913
2992
  type: 'TSTypeParameterInstantiation',
2914
2993
  loc: DUMMY_LOC,
2915
2994
  params: assertHasExactlyNTypeParameters(1),
@@ -2937,7 +3016,7 @@ const getTransforms = (
2937
3016
  );
2938
3017
  }
2939
3018
 
2940
- const newParams = ((): $ReadOnlyArray<TSESTree.TypeNode> => {
3019
+ const newParams = ((): ReadonlyArray<TSESTree.TypeNode> => {
2941
3020
  if (params.length === 1) {
2942
3021
  return assertHasExactlyNTypeParameters(1);
2943
3022
  }
@@ -2968,7 +3047,7 @@ const getTransforms = (
2968
3047
  name: 'RefAttributes',
2969
3048
  },
2970
3049
  },
2971
- typeParameters: {
3050
+ typeArguments: {
2972
3051
  type: 'TSTypeParameterInstantiation',
2973
3052
  loc: DUMMY_LOC,
2974
3053
  params: [ref],
@@ -2992,7 +3071,7 @@ const getTransforms = (
2992
3071
  name: 'ComponentType',
2993
3072
  },
2994
3073
  },
2995
- typeParameters: {
3074
+ typeArguments: {
2996
3075
  type: 'TSTypeParameterInstantiation',
2997
3076
  loc: DUMMY_LOC,
2998
3077
  params: newParams,
@@ -3016,7 +3095,7 @@ const getTransforms = (
3016
3095
  name: 'ComponentProps',
3017
3096
  },
3018
3097
  },
3019
- typeParameters: {
3098
+ typeArguments: {
3020
3099
  type: 'TSTypeParameterInstantiation',
3021
3100
  loc: DUMMY_LOC,
3022
3101
  params: assertHasExactlyNTypeParameters(1),
@@ -3054,7 +3133,7 @@ const getTransforms = (
3054
3133
  name: 'LibraryManagedAttributes',
3055
3134
  },
3056
3135
  },
3057
- typeParameters: {
3136
+ typeArguments: {
3058
3137
  type: 'TSTypeParameterInstantiation',
3059
3138
  loc: DUMMY_LOC,
3060
3139
  params: [
@@ -3072,7 +3151,7 @@ const getTransforms = (
3072
3151
  name: `ComponentProps`,
3073
3152
  },
3074
3153
  },
3075
- typeParameters: {
3154
+ typeArguments: {
3076
3155
  type: 'TSTypeParameterInstantiation',
3077
3156
  loc: DUMMY_LOC,
3078
3157
  params: [param],
@@ -3099,7 +3178,7 @@ const getTransforms = (
3099
3178
  name: 'Ref',
3100
3179
  },
3101
3180
  },
3102
- typeParameters: {
3181
+ typeArguments: {
3103
3182
  type: 'TSTypeParameterInstantiation',
3104
3183
  loc: DUMMY_LOC,
3105
3184
  params: assertHasExactlyNTypeParameters(1),
@@ -3117,7 +3196,7 @@ const getTransforms = (
3117
3196
  node.id.type === 'Identifier'
3118
3197
  ? transform.Identifier(node.id, false)
3119
3198
  : transform.QualifiedTypeIdentifier(node.id),
3120
- typeParameters: transform.TypeParameterInstantiation(
3199
+ typeArguments: transform.TypeParameterInstantiation(
3121
3200
  node.typeParameters,
3122
3201
  ),
3123
3202
  };
@@ -3256,7 +3335,7 @@ const getTransforms = (
3256
3335
  node.id.type === 'QualifiedTypeIdentifier'
3257
3336
  ? transform.QualifiedTypeIdentifier(node.id)
3258
3337
  : transform.Identifier(node.id, false),
3259
- typeParameters: transform.TypeParameterInstantiation(
3338
+ typeArguments: transform.TypeParameterInstantiation(
3260
3339
  node.typeParameters,
3261
3340
  ),
3262
3341
  };
@@ -3276,8 +3355,8 @@ const getTransforms = (
3276
3355
  type: 'TSTypeReference',
3277
3356
  loc: DUMMY_LOC,
3278
3357
  // Bug: ex.id can be qualified
3279
- typeName: transform.Identifier((ex.id: $FlowFixMe), false),
3280
- typeParameters: transform.TypeParameterInstantiation(
3358
+ typeName: transform.Identifier(ex.id as $FlowFixMe, false),
3359
+ typeArguments: transform.TypeParameterInstantiation(
3281
3360
  ex.typeParameters,
3282
3361
  ),
3283
3362
  })),
@@ -3364,12 +3443,12 @@ const getTransforms = (
3364
3443
  return {
3365
3444
  type: 'TSLiteralType',
3366
3445
  loc: DUMMY_LOC,
3367
- literal: ({
3446
+ literal: {
3368
3447
  type: 'Literal',
3369
3448
  loc: DUMMY_LOC,
3370
3449
  value: node.value,
3371
3450
  raw: node.raw,
3372
- }: TSESTree.NumberLiteral),
3451
+ } as TSESTree.NumberLiteral,
3373
3452
  };
3374
3453
  },
3375
3454
  NumberTypeAnnotation(
@@ -3546,15 +3625,15 @@ const getTransforms = (
3546
3625
  ```
3547
3626
  type T = { ...T1, b: string };
3548
3627
  // becomes
3549
- type T = Omit<T1, keyof { b: string }> & { b: string };
3628
+ type T = Omit<T1, 'b'> & { b: string };
3550
3629
  ```
3551
3630
  ```
3552
3631
  type T = { ...T1, ...T2, ...T3, b: string };
3553
3632
  // becomes
3554
3633
  type T =
3555
- & Omit<T1, keyof T2 | keyof T3 | keyof { b: string }>
3556
- & Omit<T2, keyof T3 | keyof { b: string }>
3557
- & Omit<T3, keyof { b: string }>
3634
+ & Omit<T1, keyof T2 | keyof T3 | 'b'>
3635
+ & Omit<T2, keyof T3 | 'b'>
3636
+ & Omit<T3, 'b'>
3558
3637
  & { b: string };
3559
3638
  ```
3560
3639
 
@@ -3616,10 +3695,33 @@ const getTransforms = (
3616
3695
  members: tsBody,
3617
3696
  };
3618
3697
 
3698
+ // When the non-spread properties have statically known key
3699
+ // names, emit them as string literal types directly instead of
3700
+ // wrapping in `keyof`. Falls back to `keyof objectType` when
3701
+ // any key is computed or otherwise non-extractable.
3702
+ const objectKeyTypes: ReadonlyArray<TSESTree.TypeNode> =
3703
+ extractPropertyKeyLiterals(tsBody) ?? [
3704
+ {
3705
+ type: 'TSTypeOperator',
3706
+ loc: DUMMY_LOC,
3707
+ operator: 'keyof',
3708
+ typeAnnotation: objectType,
3709
+ },
3710
+ ];
3711
+
3619
3712
  const intersectionMembers: Array<TSESTree.TypeNode> = [];
3620
3713
  for (let i = 0; i < typesToIntersect.length; i += 1) {
3621
3714
  const currentType = typesToIntersect[i];
3622
3715
  const remainingTypes = typesToIntersect.slice(i + 1);
3716
+ const omitKeyTypes: Array<TSESTree.TypeNode> = [
3717
+ ...remainingTypes.map(t => ({
3718
+ type: 'TSTypeOperator',
3719
+ loc: DUMMY_LOC,
3720
+ operator: 'keyof',
3721
+ typeAnnotation: t,
3722
+ })),
3723
+ ...objectKeyTypes,
3724
+ ];
3623
3725
  intersectionMembers.push({
3624
3726
  type: 'TSTypeReference',
3625
3727
  loc: DUMMY_LOC,
@@ -3628,29 +3730,18 @@ const getTransforms = (
3628
3730
  loc: DUMMY_LOC,
3629
3731
  name: 'Omit',
3630
3732
  },
3631
- typeParameters: {
3733
+ typeArguments: {
3632
3734
  type: 'TSTypeParameterInstantiation',
3633
3735
  loc: DUMMY_LOC,
3634
3736
  params: [
3635
3737
  currentType,
3636
- {
3637
- type: 'TSUnionType',
3638
- loc: DUMMY_LOC,
3639
- types: [
3640
- ...remainingTypes.map(t => ({
3641
- type: 'TSTypeOperator',
3738
+ omitKeyTypes.length === 1
3739
+ ? omitKeyTypes[0]
3740
+ : {
3741
+ type: 'TSUnionType',
3642
3742
  loc: DUMMY_LOC,
3643
- operator: 'keyof',
3644
- typeAnnotation: t,
3645
- })),
3646
- {
3647
- type: 'TSTypeOperator',
3648
- loc: DUMMY_LOC,
3649
- operator: 'keyof',
3650
- typeAnnotation: objectType,
3743
+ types: omitKeyTypes,
3651
3744
  },
3652
- ],
3653
- },
3654
3745
  ],
3655
3746
  },
3656
3747
  });
@@ -3836,7 +3927,12 @@ const getTransforms = (
3836
3927
  typeAnnotation: {
3837
3928
  type: 'TSTypeAnnotation',
3838
3929
  loc: DUMMY_LOC,
3839
- typeAnnotation: transformTypeAnnotationType(node.value),
3930
+ typeAnnotation:
3931
+ node.optional === true
3932
+ ? ensureTypeIncludesUndefined(
3933
+ transformTypeAnnotationType(node.value),
3934
+ )
3935
+ : transformTypeAnnotationType(node.value),
3840
3936
  },
3841
3937
  };
3842
3938
  },
@@ -3866,7 +3962,7 @@ const getTransforms = (
3866
3962
  loc: DUMMY_LOC,
3867
3963
  name: 'NonNullable',
3868
3964
  },
3869
- typeParameters: {
3965
+ typeArguments: {
3870
3966
  type: 'TSTypeParameterInstantiation',
3871
3967
  loc: DUMMY_LOC,
3872
3968
  params: [transformTypeAnnotationType(node.objectType)],
@@ -3931,12 +4027,12 @@ const getTransforms = (
3931
4027
  return {
3932
4028
  type: 'TSLiteralType',
3933
4029
  loc: DUMMY_LOC,
3934
- literal: ({
4030
+ literal: {
3935
4031
  type: 'Literal',
3936
4032
  loc: DUMMY_LOC,
3937
4033
  value: node.value,
3938
4034
  raw: node.raw,
3939
- }: TSESTree.StringLiteral),
4035
+ } as TSESTree.StringLiteral,
3940
4036
  };
3941
4037
  },
3942
4038
  StringTypeAnnotation(
@@ -4064,14 +4160,14 @@ const getTransforms = (
4064
4160
  type: 'TSTypeQuery',
4065
4161
  loc: DUMMY_LOC,
4066
4162
  exprName: transform.Identifier(node.argument),
4067
- typeParameters: undefined,
4163
+ typeArguments: undefined,
4068
4164
  };
4069
4165
  case 'QualifiedTypeofIdentifier':
4070
4166
  return {
4071
4167
  type: 'TSTypeQuery',
4072
4168
  loc: DUMMY_LOC,
4073
4169
  exprName: transform.QualifiedTypeofIdentifier(node.argument),
4074
- typeParameters: undefined,
4170
+ typeArguments: undefined,
4075
4171
  };
4076
4172
  }
4077
4173
  },
@@ -4249,7 +4345,7 @@ const getTransforms = (
4249
4345
  name: `ReactNode`,
4250
4346
  },
4251
4347
  },
4252
- typeParameters: undefined,
4348
+ typeArguments: undefined,
4253
4349
  };
4254
4350
  }
4255
4351
  }
@@ -4283,7 +4379,7 @@ const getTransforms = (
4283
4379
  name: `ReactNode`,
4284
4380
  },
4285
4381
  },
4286
- typeParameters: undefined,
4382
+ typeArguments: undefined,
4287
4383
  },
4288
4384
  };
4289
4385