mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Enable EventEmitter parsing for TypeScript TM Specs (#45118)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/45118 ## Changelog: [General] [Fixed] - Enable EventEmitter parsing for TypeScript TM Specs Reviewed By: rshest Differential Revision: D58929364 fbshipit-source-id: 0f95aee2f387edf0a148b368d71b0325c805f724
This commit is contained in:
committed by
Facebook GitHub Bot
parent
af04eb773c
commit
6daccf75da
+20
-2
@@ -60,7 +60,7 @@ export interface MixedTypeAnnotation {
|
||||
|
||||
export interface EventEmitterTypeAnnotation {
|
||||
readonly type: 'EventEmitterTypeAnnotation';
|
||||
readonly typeAnnotation: NativeModuleBaseTypeAnnotation;
|
||||
readonly typeAnnotation: NativeModuleEventEmitterTypeAnnotation;
|
||||
}
|
||||
|
||||
export interface FunctionTypeAnnotation<P, R> {
|
||||
@@ -360,6 +360,23 @@ export interface NativeModuleMixedTypeAnnotation {
|
||||
readonly type: 'MixedTypeAnnotation';
|
||||
}
|
||||
|
||||
export type NativeModuleEventEmitterBaseTypeAnnotation =
|
||||
| NativeModuleBooleanTypeAnnotation
|
||||
| NativeModuleDoubleTypeAnnotation
|
||||
| NativeModuleFloatTypeAnnotation
|
||||
| NativeModuleInt32TypeAnnotation
|
||||
| NativeModuleNumberTypeAnnotation
|
||||
| NativeModuleStringTypeAnnotation
|
||||
| NativeModuleTypeAliasTypeAnnotation
|
||||
| VoidTypeAnnotation;
|
||||
|
||||
export type NativeModuleEventEmitterTypeAnnotation =
|
||||
| NativeModuleEventEmitterBaseTypeAnnotation
|
||||
| {
|
||||
readonly type: 'ArrayTypeAnnotation';
|
||||
readonly elementType: NativeModuleEventEmitterBaseTypeAnnotation | {type: string};
|
||||
};
|
||||
|
||||
export type NativeModuleBaseTypeAnnotation =
|
||||
| NativeModuleStringTypeAnnotation
|
||||
| NativeModuleNumberTypeAnnotation
|
||||
@@ -387,7 +404,8 @@ export type NativeModuleReturnTypeAnnotation =
|
||||
export type NativeModuleTypeAnnotation =
|
||||
| NativeModuleBaseTypeAnnotation
|
||||
| NativeModuleParamOnlyTypeAnnotation
|
||||
| NativeModuleReturnOnlyTypeAnnotation;
|
||||
| NativeModuleReturnOnlyTypeAnnotation
|
||||
| NativeModuleEventEmitterTypeAnnotation;
|
||||
|
||||
type NativeModuleParamOnlyTypeAnnotation = NativeModuleFunctionTypeAnnotation;
|
||||
|
||||
|
||||
+20
-2
@@ -63,7 +63,7 @@ export type MixedTypeAnnotation = $ReadOnly<{
|
||||
|
||||
type EventEmitterTypeAnnotation = $ReadOnly<{
|
||||
type: 'EventEmitterTypeAnnotation',
|
||||
typeAnnotation: NativeModuleBaseTypeAnnotation,
|
||||
typeAnnotation: NativeModuleEventEmitterTypeAnnotation | $FlowFixMe,
|
||||
}>;
|
||||
|
||||
type FunctionTypeAnnotation<+P, +R> = $ReadOnly<{
|
||||
@@ -366,6 +366,23 @@ export type NativeModuleMixedTypeAnnotation = $ReadOnly<{
|
||||
type: 'MixedTypeAnnotation',
|
||||
}>;
|
||||
|
||||
type NativeModuleEventEmitterBaseTypeAnnotation =
|
||||
| NativeModuleBooleanTypeAnnotation
|
||||
| NativeModuleDoubleTypeAnnotation
|
||||
| NativeModuleFloatTypeAnnotation
|
||||
| NativeModuleInt32TypeAnnotation
|
||||
| NativeModuleNumberTypeAnnotation
|
||||
| NativeModuleStringTypeAnnotation
|
||||
| NativeModuleTypeAliasTypeAnnotation
|
||||
| VoidTypeAnnotation;
|
||||
|
||||
export type NativeModuleEventEmitterTypeAnnotation =
|
||||
| NativeModuleEventEmitterBaseTypeAnnotation
|
||||
| {
|
||||
type: 'ArrayTypeAnnotation',
|
||||
elementType: NativeModuleEventEmitterBaseTypeAnnotation | {type: string},
|
||||
};
|
||||
|
||||
export type NativeModuleBaseTypeAnnotation =
|
||||
| NativeModuleStringTypeAnnotation
|
||||
| NativeModuleNumberTypeAnnotation
|
||||
@@ -393,7 +410,8 @@ export type NativeModuleReturnTypeAnnotation =
|
||||
export type NativeModuleTypeAnnotation =
|
||||
| NativeModuleBaseTypeAnnotation
|
||||
| NativeModuleParamOnlyTypeAnnotation
|
||||
| NativeModuleReturnOnlyTypeAnnotation;
|
||||
| NativeModuleReturnOnlyTypeAnnotation
|
||||
| NativeModuleEventEmitterTypeAnnotation;
|
||||
|
||||
type NativeModuleParamOnlyTypeAnnotation = NativeModuleFunctionTypeAnnotation;
|
||||
|
||||
|
||||
+1
-1
@@ -107,7 +107,7 @@ class UnsupportedModuleEventEmitterPropertyParserError extends ParserError {
|
||||
message += `'${propertyValue}' must non nullable.`;
|
||||
} else if (untyped) {
|
||||
message += `'${propertyValue}' must have a concrete or void eventType.`;
|
||||
} else if (cxxOnly) {
|
||||
} else if (!cxxOnly) {
|
||||
message += `'${propertyValue}' is only supported in C++ Turbo Modules.`;
|
||||
}
|
||||
super(nativeModuleName, propertyValue, message);
|
||||
|
||||
+37
@@ -620,6 +620,42 @@ export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
|
||||
|
||||
`;
|
||||
|
||||
const NATIVE_MODULE_WITH_EVENT_EMITTERS = `
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {TurboModule} from '../RCTExport';
|
||||
import type {EventEmitter} from '../CodegenTypes';
|
||||
import * as TurboModuleRegistry from '../TurboModuleRegistry';
|
||||
|
||||
export type ObjectStruct = {
|
||||
a: number,
|
||||
b: string,
|
||||
c?: ?string,
|
||||
};
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
+onEvent1: EventEmitter<void>;
|
||||
+onEvent2: EventEmitter<string>;
|
||||
+onEvent3: EventEmitter<number>;
|
||||
+onEvent4: EventEmitter<boolean>;
|
||||
+onEvent5: EventEmitter<ObjectStruct>;
|
||||
+onEvent6: EventEmitter<ObjectStruct[]>;
|
||||
}
|
||||
|
||||
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModuleCxx');
|
||||
|
||||
`;
|
||||
|
||||
const ANDROID_ONLY_NATIVE_MODULE = `
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
@@ -813,6 +849,7 @@ module.exports = {
|
||||
NATIVE_MODULE_WITH_BASIC_PARAM_TYPES,
|
||||
NATIVE_MODULE_WITH_CALLBACK,
|
||||
NATIVE_MODULE_WITH_UNION,
|
||||
NATIVE_MODULE_WITH_EVENT_EMITTERS,
|
||||
EMPTY_NATIVE_MODULE,
|
||||
ANDROID_ONLY_NATIVE_MODULE,
|
||||
IOS_ONLY_NATIVE_MODULE,
|
||||
|
||||
+117
@@ -1424,6 +1424,123 @@ exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_COMPLEX_
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_EVENT_EMITTERS 1`] = `
|
||||
"{
|
||||
'modules': {
|
||||
'NativeSampleTurboModule': {
|
||||
'type': 'NativeModule',
|
||||
'aliasMap': {
|
||||
'ObjectStruct': {
|
||||
'type': 'ObjectTypeAnnotation',
|
||||
'properties': [
|
||||
{
|
||||
'name': 'a',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'NumberTypeAnnotation'
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'b',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'StringTypeAnnotation'
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'c',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'NullableTypeAnnotation',
|
||||
'typeAnnotation': {
|
||||
'type': 'StringTypeAnnotation'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
'enumMap': {},
|
||||
'spec': {
|
||||
'eventEmitters': [
|
||||
{
|
||||
'name': 'onEvent1',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'EventEmitterTypeAnnotation',
|
||||
'typeAnnotation': {
|
||||
'type': 'VoidTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'onEvent2',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'EventEmitterTypeAnnotation',
|
||||
'typeAnnotation': {
|
||||
'type': 'StringTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'onEvent3',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'EventEmitterTypeAnnotation',
|
||||
'typeAnnotation': {
|
||||
'type': 'NumberTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'onEvent4',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'EventEmitterTypeAnnotation',
|
||||
'typeAnnotation': {
|
||||
'type': 'BooleanTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'onEvent5',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'EventEmitterTypeAnnotation',
|
||||
'typeAnnotation': {
|
||||
'type': 'TypeAliasTypeAnnotation',
|
||||
'name': 'ObjectStruct'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'onEvent6',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'EventEmitterTypeAnnotation',
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'TypeAliasTypeAnnotation',
|
||||
'name': 'ObjectStruct'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
'methods': []
|
||||
},
|
||||
'moduleName': 'SampleTurboModuleCxx',
|
||||
'excludedPlatforms': [
|
||||
'iOS',
|
||||
'android'
|
||||
]
|
||||
}
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`RN Codegen Flow Parser can generate fixture NATIVE_MODULE_WITH_FLOAT_AND_INT32 1`] = `
|
||||
"{
|
||||
'modules': {
|
||||
|
||||
@@ -40,6 +40,7 @@ const {
|
||||
emitPromise,
|
||||
emitRootTag,
|
||||
emitUnion,
|
||||
translateArrayTypeAnnotation,
|
||||
typeAliasResolution,
|
||||
typeEnumResolution,
|
||||
} = require('../../parsers-primitives');
|
||||
@@ -62,6 +63,20 @@ function translateTypeAnnotation(
|
||||
resolveTypeAnnotationFN(flowTypeAnnotation, types, parser);
|
||||
|
||||
switch (typeAnnotation.type) {
|
||||
case 'ArrayTypeAnnotation': {
|
||||
return translateArrayTypeAnnotation(
|
||||
hasteModuleName,
|
||||
types,
|
||||
aliasMap,
|
||||
enumMap,
|
||||
cxxOnly,
|
||||
'Array',
|
||||
typeAnnotation.elementType,
|
||||
nullable,
|
||||
translateTypeAnnotation,
|
||||
parser,
|
||||
);
|
||||
}
|
||||
case 'GenericTypeAnnotation': {
|
||||
switch (parser.getTypeAnnotationName(typeAnnotation)) {
|
||||
case 'RootTag': {
|
||||
|
||||
@@ -489,15 +489,22 @@ function buildEventEmitterSchema(
|
||||
translateTypeAnnotation: $FlowFixMe,
|
||||
parser: Parser,
|
||||
): NativeModuleEventEmitterShape {
|
||||
let {key, value} = property;
|
||||
const eventemitterName: string = key.name;
|
||||
const {key} = property;
|
||||
const value =
|
||||
parser.language() === 'TypeScript'
|
||||
? property.typeAnnotation.typeAnnotation
|
||||
: property.value;
|
||||
|
||||
const eventemitterName: string = key.name;
|
||||
const resolveTypeAnnotationFN = parser.getResolveTypeAnnotationFN();
|
||||
const [typeAnnotation, typeAnnotationNullable] = unwrapNullable(value);
|
||||
const typeAnnotationUntyped =
|
||||
value.typeParameters.params.length === 1 &&
|
||||
value.typeParameters.params[0].type === 'ObjectTypeAnnotation' &&
|
||||
value.typeParameters.params[0].properties.length === 0;
|
||||
parser.language() === 'TypeScript'
|
||||
? value.typeParameters.params[0].type === 'TSTypeLiteral' &&
|
||||
value.typeParameters.params[0].members.length === 0
|
||||
: value.typeParameters.params[0].type === 'ObjectTypeAnnotation' &&
|
||||
value.typeParameters.params[0].properties.length === 0;
|
||||
|
||||
throwIfEventEmitterTypeIsUnsupported(
|
||||
hasteModuleName,
|
||||
@@ -520,12 +527,24 @@ function buildEventEmitterSchema(
|
||||
parser,
|
||||
eventTypeResolutionStatus.nullable,
|
||||
);
|
||||
|
||||
const eventTypeAnnotation = translateTypeAnnotation(
|
||||
hasteModuleName,
|
||||
typeAnnotation.typeParameters.params[0],
|
||||
types,
|
||||
aliasMap,
|
||||
enumMap,
|
||||
tryParse,
|
||||
cxxOnly,
|
||||
parser,
|
||||
);
|
||||
|
||||
return {
|
||||
name: eventemitterName,
|
||||
optional: false,
|
||||
typeAnnotation: {
|
||||
type: 'EventEmitterTypeAnnotation',
|
||||
typeAnnotation: {type: eventTypeResolutionStatus.typeAnnotation.type},
|
||||
typeAnnotation: eventTypeAnnotation,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -775,7 +794,6 @@ const buildModuleSchema = (
|
||||
parser,
|
||||
)
|
||||
: {};
|
||||
|
||||
const properties: $ReadOnlyArray<$FlowFixMe> =
|
||||
language === 'Flow' ? moduleSpec.body.properties : moduleSpec.body.body;
|
||||
|
||||
@@ -798,8 +816,12 @@ const buildModuleSchema = (
|
||||
}>(property => {
|
||||
const enumMap: {...NativeModuleEnumMap} = {};
|
||||
const isEventEmitter =
|
||||
property?.value?.type === 'GenericTypeAnnotation' &&
|
||||
property?.value?.id?.name === 'EventEmitter';
|
||||
language === 'TypeScript'
|
||||
? property?.type === 'TSPropertySignature' &&
|
||||
property?.typeAnnotation?.typeAnnotation?.typeName?.name ===
|
||||
'EventEmitter'
|
||||
: property?.value?.type === 'GenericTypeAnnotation' &&
|
||||
property?.value?.id?.name === 'EventEmitter';
|
||||
return tryParse(() => ({
|
||||
aliasMap,
|
||||
enumMap,
|
||||
|
||||
+33
@@ -723,6 +723,38 @@ export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModule');
|
||||
|
||||
`;
|
||||
|
||||
const NATIVE_MODULE_WITH_EVENT_EMITTERS = `
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
|
||||
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
|
||||
|
||||
export type ObjectStruct = {
|
||||
a: number;
|
||||
b: string;
|
||||
c?: string | null;
|
||||
};
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
readonly onEvent1: EventEmitter<void>;
|
||||
readonly onEvent2: EventEmitter<string>;
|
||||
readonly onEvent3: EventEmitter<number>;
|
||||
readonly onEvent4: EventEmitter<boolean>;
|
||||
readonly onEvent5: EventEmitter<ObjectStruct>;
|
||||
readonly onEvent6: EventEmitter<ObjectStruct[]>;
|
||||
}
|
||||
|
||||
export default TurboModuleRegistry.getEnforcing<Spec>('SampleTurboModuleCxx');
|
||||
|
||||
`;
|
||||
|
||||
const ANDROID_ONLY_NATIVE_MODULE = `
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
@@ -875,6 +907,7 @@ module.exports = {
|
||||
NATIVE_MODULE_WITH_BASIC_PARAM_TYPES,
|
||||
NATIVE_MODULE_WITH_CALLBACK,
|
||||
NATIVE_MODULE_WITH_UNION,
|
||||
NATIVE_MODULE_WITH_EVENT_EMITTERS,
|
||||
EMPTY_NATIVE_MODULE,
|
||||
ANDROID_ONLY_NATIVE_MODULE,
|
||||
IOS_ONLY_NATIVE_MODULE,
|
||||
|
||||
+117
@@ -1624,6 +1624,123 @@ exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_CO
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_EVENT_EMITTERS 1`] = `
|
||||
"{
|
||||
'modules': {
|
||||
'NativeSampleTurboModule': {
|
||||
'type': 'NativeModule',
|
||||
'aliasMap': {
|
||||
'ObjectStruct': {
|
||||
'type': 'ObjectTypeAnnotation',
|
||||
'properties': [
|
||||
{
|
||||
'name': 'a',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'NumberTypeAnnotation'
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'b',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'StringTypeAnnotation'
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'c',
|
||||
'optional': true,
|
||||
'typeAnnotation': {
|
||||
'type': 'NullableTypeAnnotation',
|
||||
'typeAnnotation': {
|
||||
'type': 'StringTypeAnnotation'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
'enumMap': {},
|
||||
'spec': {
|
||||
'eventEmitters': [
|
||||
{
|
||||
'name': 'onEvent1',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'EventEmitterTypeAnnotation',
|
||||
'typeAnnotation': {
|
||||
'type': 'VoidTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'onEvent2',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'EventEmitterTypeAnnotation',
|
||||
'typeAnnotation': {
|
||||
'type': 'StringTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'onEvent3',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'EventEmitterTypeAnnotation',
|
||||
'typeAnnotation': {
|
||||
'type': 'NumberTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'onEvent4',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'EventEmitterTypeAnnotation',
|
||||
'typeAnnotation': {
|
||||
'type': 'BooleanTypeAnnotation'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'onEvent5',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'EventEmitterTypeAnnotation',
|
||||
'typeAnnotation': {
|
||||
'type': 'TypeAliasTypeAnnotation',
|
||||
'name': 'ObjectStruct'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'onEvent6',
|
||||
'optional': false,
|
||||
'typeAnnotation': {
|
||||
'type': 'EventEmitterTypeAnnotation',
|
||||
'typeAnnotation': {
|
||||
'type': 'ArrayTypeAnnotation',
|
||||
'elementType': {
|
||||
'type': 'TypeAliasTypeAnnotation',
|
||||
'name': 'ObjectStruct'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
'methods': []
|
||||
},
|
||||
'moduleName': 'SampleTurboModuleCxx',
|
||||
'excludedPlatforms': [
|
||||
'iOS',
|
||||
'android'
|
||||
]
|
||||
}
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`RN Codegen TypeScript Parser can generate fixture NATIVE_MODULE_WITH_FLOAT_AND_INT32 1`] = `
|
||||
"{
|
||||
'modules': {
|
||||
|
||||
@@ -337,6 +337,8 @@ class TypeScriptParser implements Parser {
|
||||
|
||||
convertKeywordToTypeAnnotation(keyword: string): string {
|
||||
switch (keyword) {
|
||||
case 'TSArrayType':
|
||||
return 'ArrayTypeAnnotation';
|
||||
case 'TSBooleanKeyword':
|
||||
return 'BooleanTypeAnnotation';
|
||||
case 'TSNumberKeyword':
|
||||
@@ -345,6 +347,8 @@ class TypeScriptParser implements Parser {
|
||||
return 'VoidTypeAnnotation';
|
||||
case 'TSStringKeyword':
|
||||
return 'StringTypeAnnotation';
|
||||
case 'TSTypeLiteral':
|
||||
return 'ObjectTypeAnnotation';
|
||||
case 'TSUnknownKeyword':
|
||||
return 'MixedTypeAnnotation';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user