@react-native/compatibility-check 0.0.0 → 0.0.1

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.
package/README.md CHANGED
@@ -1 +1,245 @@
1
- Placeholder
1
+ # **React Native compatibility-check**
2
+
3
+ Status: Experimental (stage 1)
4
+
5
+ Work In Progress. Documentation is lacking, and intended to be used by power
6
+ users at this point.
7
+
8
+ This tool enables checking the boundary between JavaScript and Native for
9
+ backwards incompatible changes to protect against crashes.
10
+
11
+ This is useful for:
12
+
13
+ - Local Development
14
+ - Over the Air updates on platforms that support it
15
+ - Theoretically: Server Components with React Native
16
+
17
+ ## **Motivating Problems**
18
+
19
+ Let’s look at some motivating examples for this project.
20
+
21
+ > [!NOTE]
22
+ > The examples below are written with Flow, but the compatibility-check
23
+ > tool is agnostic to the types you write. The compatibility-check runs on JSON
24
+ > schema files, most commonly generated by the
25
+ > [@react-native/codegen](https://www.npmjs.com/package/@react-native/codegen)
26
+ > tool which supports both TypeScript and Flow.
27
+
28
+ ### **Adding new methods**
29
+
30
+ You might have an Analytics Native Module in your app, and you last built the
31
+ native client a couple of days ago:
32
+
33
+ ```javascript
34
+ export interface Spec extends TurboModule {
35
+ log: (eventName: string, content: string) => void;
36
+ }
37
+ ```
38
+
39
+ And you are working on a change to add a new method to this Native Module:
40
+
41
+ ```javascript
42
+ export interface Spec extends TurboModule {
43
+ log: (eventName: string, content: string) => void;
44
+ logError: (message: string) => void;
45
+ }
46
+ ```
47
+
48
+ ```
49
+ NativeAnalytics.logError('Oh No! We hit a crash')
50
+ ```
51
+
52
+ Since you are working on this, you’ve built a new native client and tested the
53
+ change on your computer and everything works.
54
+
55
+ However, when your colleague pulls your latest changes and tries to run it,
56
+ they’ll get a crash `logError is not a function`. They need to rebuild their
57
+ native client\!
58
+
59
+ Using this tool, you can detect this incompatibility at build time, getting an
60
+ error that looks like:
61
+
62
+ ```
63
+ NativeAnalytics: Object added required properties, which native will not provide
64
+ -- logError
65
+ ```
66
+
67
+ Errors like this can occur for much more nuanced reasons than adding a method.
68
+ For example:
69
+
70
+ ### **Sending native new union values**
71
+
72
+ ```javascript
73
+ export interface Spec extends TurboModule {
74
+ // You add 'system' to this union
75
+ +setColorScheme: (color: 'light' | 'dark') => void;
76
+ }
77
+ ```
78
+
79
+ If you add a new option of `system` and add native support for that option, when
80
+ you call this method with `system` on your commit it would work but on an older
81
+ build not expecting `system` it will crash. This tool will give you the error
82
+ message:
83
+
84
+ ```
85
+ ColorManager.setColorScheme parameter 0: Union added items, but native will not expect/support them
86
+ -- position 3 system
87
+ ```
88
+
89
+ ### **Changing an enum value sent from native**
90
+
91
+ As another example, say you are getting the color scheme from the system as an
92
+ integer value, used in JavaScript as an enum:
93
+
94
+ ```javascript
95
+ enum TestEnum {
96
+ LIGHT = 1,
97
+ DARK = 2,
98
+ SYSTEM = 3,
99
+ }
100
+
101
+ export interface Spec extends TurboModule {
102
+ getColorScheme: () => TestEnum;
103
+ }
104
+ ```
105
+
106
+ And you realize you actually need native to send `-1` for System instead of 3\.
107
+
108
+ ```javascript
109
+ enum TestEnum {
110
+ LIGHT = 1,
111
+ DARK = 2,
112
+ SYSTEM = -1,
113
+ }
114
+ ```
115
+
116
+ If you make this change and run the JavaScript on an old build, it might still
117
+ send JavaScript the value 3, which your JavaScript isn’t handling anymore\!
118
+
119
+ This tool gives an error:
120
+
121
+ ```javascript
122
+ ColorManager: Object contained a property with a type mismatch
123
+ -- getColorScheme: has conflicting type changes
124
+ --new: ()=>Enum<number>
125
+ --old: ()=>Enum<number>
126
+ Function return types do not match
127
+ --new: ()=>Enum<number>
128
+ --old: ()=>Enum<number>
129
+ Enum types do not match
130
+ --new: Enum<number> {LIGHT = 1, DARK = 2, SYSTEM = -1}
131
+ --old: Enum<number> {LIGHT = 1, DARK = 2, SYSTEM = 3}
132
+ Enum contained a member with a type mismatch
133
+ -- Member SYSTEM: has conflicting changes
134
+ --new: -1
135
+ --old: 3
136
+ Numeric literals are not equal
137
+ --new: -1
138
+ --old: 3
139
+
140
+ ```
141
+
142
+ ## **Avoiding Breaking Changes**
143
+
144
+ You can use this tool to either detect changes locally to warn that you need to
145
+ install a new native build, or when doing OTA you might need to guarantee that
146
+ the changes in your PR are compatible with the native client they’ll be running
147
+ in.
148
+
149
+ ### **Example 1**
150
+
151
+ In example 1, when adding logError, it needs to be optional to be safe:
152
+
153
+ ```javascript
154
+ export interface Spec extends TurboModule {
155
+ log: (eventName: string, content: string) => void;
156
+ logError?: (message: string) => void;
157
+ }
158
+ ```
159
+
160
+ That will enforce if you are using TypeScript or Flow that you check if the
161
+ native client supports logError before calling it:
162
+
163
+ ```javascript
164
+ if (NativeAnalytics.logError) {
165
+ NativeAnalytics.logError('Oh No! We hit a crash');
166
+ }
167
+ ```
168
+
169
+ ### **Example 2**
170
+
171
+ When you want to add '`system'` as a value to the union, modifying the existing
172
+ union is not safe. You would need to add a new optional method that has that
173
+ change. You can clean up the old method when you know that all of the builds you
174
+ ever want to run this JavaScript on have native support.
175
+
176
+ ```javascript
177
+ export interface Spec extends TurboModule {
178
+ +setColorScheme: (color: 'light' | 'dark') => void
179
+ +setColorSchemeWithSystem?: (color: 'light' | 'dark' | 'system') => void
180
+ }
181
+ ```
182
+
183
+ ### **Example 3**
184
+
185
+ Changing a union case is similar to Example 2, you would either need a new
186
+ method, or support the existing value and the new `-1`.
187
+
188
+ ```
189
+ enum TestEnum {
190
+ LIGHT = 1,
191
+ DARK = 2,
192
+ SYSTEM = 3,
193
+ SYSTEM_ALSO = -1,
194
+ }
195
+ ```
196
+
197
+ ## **Installation**
198
+
199
+ ```
200
+ yarn add @react-native/compatibility-check
201
+ ```
202
+
203
+ ## **Usage**
204
+
205
+ To use this package, you’ll need a script that works something like this:
206
+
207
+ This script checks the compatibility of a React Native app's schema between two
208
+ versions. It takes into account the changes made to the schema and determines
209
+ whether they are compatible or not.
210
+
211
+ ```javascript
212
+ import {compareSchemas} from '@react-native/compatibility-check';
213
+ const util = require('util');
214
+
215
+ async function run(argv: Argv, STDERR: string) {
216
+ const debug = (log: mixed) => {
217
+ argv.debug &&
218
+ console.info(util.inspect(log, {showHidden: false, depth: null}));
219
+ };
220
+
221
+ const currentSchema =
222
+ JSON.parse(/*you'll read the file generated by codegen wherever it is in your app*/);
223
+ const previousSchema =
224
+ JSON.parse(/*you'll read the schema file that you persisted from when your native app was built*/);
225
+
226
+ const safetyResult = compareSchemas(currentSchema, previousSchema);
227
+
228
+ const summary = safetyResult.getSummary();
229
+ switch (summary.status) {
230
+ case 'ok':
231
+ debug('No changes in boundary');
232
+ console.log(JSON.stringify(summary));
233
+ break;
234
+ case 'patchable':
235
+ debug('Changes in boundary, but are compatible');
236
+ debug(result.getDebugInfo());
237
+ console.log(JSON.stringify(summary));
238
+ break;
239
+ default:
240
+ debug(result.getDebugInfo());
241
+ console.error(JSON.stringify(result.getErrors()));
242
+ throw new Error(`Incompatible changes in boundary`);
243
+ }
244
+ }
245
+ ```
@@ -0,0 +1,135 @@
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
+
11
+ import type {
12
+ CompleteTypeAnnotation,
13
+ NamedShape,
14
+ NativeModuleEnumMember,
15
+ } from "@react-native/codegen/src/CodegenSchema";
16
+ type TypeAnnotationComparisonError = {
17
+ type: "TypeAnnotationComparisonError";
18
+ message: string;
19
+ newerAnnotation: CompleteTypeAnnotation;
20
+ olderAnnotation: CompleteTypeAnnotation;
21
+ previousError?: TypeComparisonError;
22
+ };
23
+ type TypeInformationComparisonError = {
24
+ type: "TypeInformationComparisonError";
25
+ message: string;
26
+ newerType: CompleteTypeAnnotation;
27
+ olderType: CompleteTypeAnnotation;
28
+ previousError?: TypeComparisonError;
29
+ };
30
+ type PropertyComparisonError = {
31
+ type: "PropertyComparisonError";
32
+ message: string;
33
+ mismatchedProperties: Array<{
34
+ property: string;
35
+ fault?: TypeComparisonError;
36
+ }>;
37
+ previousError?: TypeComparisonError;
38
+ };
39
+ type PositionalComparisonError = {
40
+ type: "PositionalComparisonError";
41
+ message: string;
42
+ erroneousItems: Array<[number, CompleteTypeAnnotation]>;
43
+ previousError?: TypeComparisonError;
44
+ };
45
+ type MemberComparisonError = {
46
+ type: "MemberComparisonError";
47
+ message: string;
48
+ mismatchedMembers: Array<{ member: string; fault?: TypeComparisonError }>;
49
+ previousError?: TypeComparisonError;
50
+ };
51
+ export type TypeComparisonError =
52
+ | TypeAnnotationComparisonError
53
+ | TypeInformationComparisonError
54
+ | PropertyComparisonError
55
+ | PositionalComparisonError
56
+ | MemberComparisonError;
57
+ export type PositionalComparisonResult = {
58
+ typeKind: "stringUnion" | "union" | "intersection" | "parameter" | "tuple";
59
+ nestedChanges: Array<[number, number, ComparisonResult]>;
60
+ addedElements?: Array<[number, CompleteTypeAnnotation]>;
61
+ removedElements?: Array<[number, CompleteTypeAnnotation]>;
62
+ };
63
+ export type FunctionComparisonResult = {
64
+ returnType?: ComparisonResult;
65
+ parameterTypes?: PositionalComparisonResult;
66
+ };
67
+ export type PropertiesComparisonResult = {
68
+ addedProperties?: ReadonlyArray<NamedShape<CompleteTypeAnnotation>>;
69
+ missingProperties?: ReadonlyArray<NamedShape<CompleteTypeAnnotation>>;
70
+ errorProperties?: Array<{ property: string; fault?: TypeComparisonError }>;
71
+ madeStrict?: Array<{ property: string; furtherChanges?: ComparisonResult }>;
72
+ madeOptional?: Array<{ property: string; furtherChanges?: ComparisonResult }>;
73
+ nestedPropertyChanges?: Array<[string, ComparisonResult]>;
74
+ };
75
+ export type MembersComparisonResult = {
76
+ addedMembers?: Array<NativeModuleEnumMember>;
77
+ missingMembers?: Array<NativeModuleEnumMember>;
78
+ errorMembers?: Array<{ member: string; fault?: TypeComparisonError }>;
79
+ };
80
+ export type NullableComparisonResult = {
81
+ typeRefined: boolean;
82
+ optionsReduced: boolean;
83
+ interiorLog: null | undefined | ComparisonResult;
84
+ newType: null | undefined | CompleteTypeAnnotation;
85
+ oldType: null | undefined | CompleteTypeAnnotation;
86
+ };
87
+ export type ComparisonResult =
88
+ | { status: "matching" }
89
+ | { status: "skipped" }
90
+ | { status: "nullableChange"; nullableLog: NullableComparisonResult }
91
+ | { status: "properties"; propertyLog: PropertiesComparisonResult }
92
+ | { status: "members"; memberLog: MembersComparisonResult }
93
+ | { status: "functionChange"; functionChangeLog: FunctionComparisonResult }
94
+ | { status: "positionalTypeChange"; changeLog: PositionalComparisonResult }
95
+ | { status: "error"; errorLog: TypeComparisonError };
96
+ export declare function isPropertyLogEmpty(
97
+ result: PropertiesComparisonResult
98
+ ): boolean;
99
+ export declare function isMemberLogEmpty(
100
+ result: MembersComparisonResult
101
+ ): boolean;
102
+ export declare function isFunctionLogEmpty(
103
+ result: FunctionComparisonResult
104
+ ): boolean;
105
+ export declare function makeError(error: TypeComparisonError): ComparisonResult;
106
+ export declare function typeInformationComparisonError(
107
+ message: string,
108
+ newerType: CompleteTypeAnnotation,
109
+ olderType: CompleteTypeAnnotation,
110
+ previousError?: TypeComparisonError
111
+ ): TypeComparisonError;
112
+ export declare function typeAnnotationComparisonError(
113
+ message: string,
114
+ newerAnnotation: CompleteTypeAnnotation,
115
+ olderAnnotation: CompleteTypeAnnotation,
116
+ previousError?: TypeComparisonError
117
+ ): TypeComparisonError;
118
+ export declare function propertyComparisonError(
119
+ message: string,
120
+ mismatchedProperties: Array<{
121
+ property: string;
122
+ fault?: TypeComparisonError;
123
+ }>,
124
+ previousError?: TypeComparisonError
125
+ ): TypeComparisonError;
126
+ export declare function memberComparisonError(
127
+ message: string,
128
+ mismatchedMembers: Array<{ member: string; fault?: TypeComparisonError }>,
129
+ previousError?: TypeComparisonError
130
+ ): TypeComparisonError;
131
+ export declare function positionalComparisonError(
132
+ message: string,
133
+ erroneousItems: Array<[number, CompleteTypeAnnotation]>,
134
+ previousError?: TypeComparisonError
135
+ ): TypeComparisonError;
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true,
5
+ });
6
+ exports.isFunctionLogEmpty = isFunctionLogEmpty;
7
+ exports.isMemberLogEmpty = isMemberLogEmpty;
8
+ exports.isPropertyLogEmpty = isPropertyLogEmpty;
9
+ exports.makeError = makeError;
10
+ exports.memberComparisonError = memberComparisonError;
11
+ exports.positionalComparisonError = positionalComparisonError;
12
+ exports.propertyComparisonError = propertyComparisonError;
13
+ exports.typeAnnotationComparisonError = typeAnnotationComparisonError;
14
+ exports.typeInformationComparisonError = typeInformationComparisonError;
15
+ function isPropertyLogEmpty(result) {
16
+ return !(
17
+ result.addedProperties ||
18
+ result.missingProperties ||
19
+ result.nestedPropertyChanges ||
20
+ result.madeStrict ||
21
+ result.madeOptional ||
22
+ result.errorProperties
23
+ );
24
+ }
25
+ function isMemberLogEmpty(result) {
26
+ return !(result.addedMembers || result.missingMembers || result.errorMembers);
27
+ }
28
+ function isFunctionLogEmpty(result) {
29
+ return !(result.returnType || result.parameterTypes);
30
+ }
31
+ function makeError(error) {
32
+ return {
33
+ status: "error",
34
+ errorLog: error,
35
+ };
36
+ }
37
+ function typeInformationComparisonError(
38
+ message,
39
+ newerType,
40
+ olderType,
41
+ previousError
42
+ ) {
43
+ return {
44
+ type: "TypeInformationComparisonError",
45
+ message,
46
+ newerType,
47
+ olderType,
48
+ previousError,
49
+ };
50
+ }
51
+ function typeAnnotationComparisonError(
52
+ message,
53
+ newerAnnotation,
54
+ olderAnnotation,
55
+ previousError
56
+ ) {
57
+ return {
58
+ type: "TypeAnnotationComparisonError",
59
+ message,
60
+ newerAnnotation,
61
+ olderAnnotation,
62
+ previousError,
63
+ };
64
+ }
65
+ function propertyComparisonError(message, mismatchedProperties, previousError) {
66
+ return {
67
+ type: "PropertyComparisonError",
68
+ message,
69
+ mismatchedProperties,
70
+ previousError,
71
+ };
72
+ }
73
+ function memberComparisonError(message, mismatchedMembers, previousError) {
74
+ return {
75
+ type: "MemberComparisonError",
76
+ message,
77
+ mismatchedMembers,
78
+ previousError,
79
+ };
80
+ }
81
+ function positionalComparisonError(message, erroneousItems, previousError) {
82
+ return {
83
+ type: "PositionalComparisonError",
84
+ message,
85
+ erroneousItems,
86
+ previousError,
87
+ };
88
+ }
@@ -0,0 +1,188 @@
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
+ * @flow strict
8
+ * @format
9
+ */
10
+
11
+ import type {
12
+ CompleteTypeAnnotation,
13
+ NamedShape,
14
+ NativeModuleEnumMember,
15
+ } from "@react-native/codegen/src/CodegenSchema";
16
+
17
+ type TypeAnnotationComparisonError = {
18
+ type: "TypeAnnotationComparisonError",
19
+ message: string,
20
+ newerAnnotation: CompleteTypeAnnotation,
21
+ olderAnnotation: CompleteTypeAnnotation,
22
+ previousError?: TypeComparisonError,
23
+ };
24
+ type TypeInformationComparisonError = {
25
+ type: "TypeInformationComparisonError",
26
+ message: string,
27
+ newerType: CompleteTypeAnnotation,
28
+ olderType: CompleteTypeAnnotation,
29
+ previousError?: TypeComparisonError,
30
+ };
31
+ type PropertyComparisonError = {
32
+ type: "PropertyComparisonError",
33
+ message: string,
34
+ mismatchedProperties: Array<{
35
+ property: string,
36
+ fault?: TypeComparisonError,
37
+ ...
38
+ }>,
39
+ previousError?: TypeComparisonError,
40
+ };
41
+ type PositionalComparisonError = {
42
+ type: "PositionalComparisonError",
43
+ message: string,
44
+ erroneousItems: Array<[number, CompleteTypeAnnotation]>,
45
+ previousError?: TypeComparisonError,
46
+ };
47
+ type MemberComparisonError = {
48
+ type: "MemberComparisonError",
49
+ message: string,
50
+ mismatchedMembers: Array<{
51
+ member: string,
52
+ fault?: TypeComparisonError,
53
+ }>,
54
+ previousError?: TypeComparisonError,
55
+ };
56
+ export type TypeComparisonError =
57
+ | TypeAnnotationComparisonError
58
+ | TypeInformationComparisonError
59
+ | PropertyComparisonError
60
+ | PositionalComparisonError
61
+ | MemberComparisonError;
62
+
63
+ // Collects changes that may be type safe within parameters, unions, intersections, and tuples
64
+ export type PositionalComparisonResult = {
65
+ typeKind: "stringUnion" | "union" | "intersection" | "parameter" | "tuple",
66
+ // Nested changes stores the position of the old type followed by new
67
+ // Except for union and intersection, new position === old position
68
+ nestedChanges: Array<[number, number, ComparisonResult]>,
69
+ // These properties should never occur for a tuple
70
+ addedElements?: Array<[number, CompleteTypeAnnotation]>,
71
+ removedElements?: Array<[number, CompleteTypeAnnotation]>,
72
+ ...
73
+ };
74
+ export type FunctionComparisonResult = {
75
+ returnType?: ComparisonResult,
76
+ // The following should always have typeKind 'parameter'
77
+ parameterTypes?: PositionalComparisonResult,
78
+ ...
79
+ };
80
+
81
+ // Array<NamedShape<Nullable<NativeModuleBaseTypeAnnotation>>>
82
+
83
+ export type PropertiesComparisonResult = {
84
+ addedProperties?: $ReadOnlyArray<NamedShape<CompleteTypeAnnotation>>,
85
+ missingProperties?: $ReadOnlyArray<NamedShape<CompleteTypeAnnotation>>,
86
+ errorProperties?: Array<{
87
+ property: string,
88
+ fault?: TypeComparisonError,
89
+ ...
90
+ }>,
91
+ madeStrict?: Array<{
92
+ property: string,
93
+ furtherChanges?: ComparisonResult,
94
+ ...
95
+ }>,
96
+ madeOptional?: Array<{
97
+ property: string,
98
+ furtherChanges?: ComparisonResult,
99
+ ...
100
+ }>,
101
+ nestedPropertyChanges?: Array<[string, ComparisonResult]>,
102
+ ...
103
+ };
104
+ export type MembersComparisonResult = {
105
+ addedMembers?: Array<NativeModuleEnumMember>,
106
+ missingMembers?: Array<NativeModuleEnumMember>,
107
+ errorMembers?: Array<{
108
+ member: string,
109
+ fault?: TypeComparisonError,
110
+ }>,
111
+ };
112
+ export type NullableComparisonResult = {
113
+ /* Four possible cases of change:
114
+ void goes to T? :: typeRefined !optionsReduced
115
+ T? goes to void :: typeRefined optionsReduced
116
+ T goes to T? :: !typeRefined !optionsReduced
117
+ T? goes to T :: !typeRefined optionsReduced
118
+ */
119
+ typeRefined: boolean,
120
+ optionsReduced: boolean,
121
+ // interiorLog not available if either type is void
122
+ interiorLog: ?ComparisonResult,
123
+ newType: ?CompleteTypeAnnotation,
124
+ oldType: ?CompleteTypeAnnotation,
125
+ ...
126
+ };
127
+ export type ComparisonResult =
128
+ | { status: "matching" }
129
+ | { status: "skipped" }
130
+ | { status: "nullableChange", nullableLog: NullableComparisonResult }
131
+ | { status: "properties", propertyLog: PropertiesComparisonResult }
132
+ | { status: "members", memberLog: MembersComparisonResult }
133
+ | { status: "functionChange", functionChangeLog: FunctionComparisonResult }
134
+ | { status: "positionalTypeChange", changeLog: PositionalComparisonResult }
135
+ | { status: "error", errorLog: TypeComparisonError };
136
+
137
+ declare export function isPropertyLogEmpty(
138
+ result: PropertiesComparisonResult
139
+ ): boolean;
140
+
141
+ declare export function isMemberLogEmpty(
142
+ result: MembersComparisonResult
143
+ ): boolean;
144
+
145
+ declare export function isFunctionLogEmpty(
146
+ result: FunctionComparisonResult
147
+ ): boolean;
148
+
149
+ declare export function makeError(error: TypeComparisonError): ComparisonResult;
150
+
151
+ declare export function typeInformationComparisonError(
152
+ message: string,
153
+ newerType: CompleteTypeAnnotation,
154
+ olderType: CompleteTypeAnnotation,
155
+ previousError?: TypeComparisonError
156
+ ): TypeComparisonError;
157
+
158
+ declare export function typeAnnotationComparisonError(
159
+ message: string,
160
+ newerAnnotation: CompleteTypeAnnotation,
161
+ olderAnnotation: CompleteTypeAnnotation,
162
+ previousError?: TypeComparisonError
163
+ ): TypeComparisonError;
164
+
165
+ declare export function propertyComparisonError(
166
+ message: string,
167
+ mismatchedProperties: Array<{
168
+ property: string,
169
+ fault?: TypeComparisonError,
170
+ ...
171
+ }>,
172
+ previousError?: TypeComparisonError
173
+ ): TypeComparisonError;
174
+
175
+ declare export function memberComparisonError(
176
+ message: string,
177
+ mismatchedMembers: Array<{
178
+ member: string,
179
+ fault?: TypeComparisonError,
180
+ }>,
181
+ previousError?: TypeComparisonError
182
+ ): TypeComparisonError;
183
+
184
+ declare export function positionalComparisonError(
185
+ message: string,
186
+ erroneousItems: Array<[number, CompleteTypeAnnotation]>,
187
+ previousError?: TypeComparisonError
188
+ ): TypeComparisonError;