diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d2a30c0c87..04dc876c45 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -940,6 +940,7 @@ namespace ts { if (jsxPragma) { const chosenpragma = isArray(jsxPragma) ? jsxPragma[0] : jsxPragma; file.localJsxFactory = parseIsolatedEntityName(chosenpragma.arguments.factory, languageVersion); + visitNode(file.localJsxFactory, markAsSynthetic); if (file.localJsxFactory) { return file.localJsxNamespace = getFirstIdentifier(file.localJsxFactory).escapedText; } @@ -950,6 +951,7 @@ namespace ts { _jsxNamespace = "React" as __String; if (compilerOptions.jsxFactory) { _jsxFactoryEntity = parseIsolatedEntityName(compilerOptions.jsxFactory, languageVersion); + visitNode(_jsxFactoryEntity, markAsSynthetic); if (_jsxFactoryEntity) { _jsxNamespace = getFirstIdentifier(_jsxFactoryEntity).escapedText; } @@ -958,7 +960,16 @@ namespace ts { _jsxNamespace = escapeLeadingUnderscores(compilerOptions.reactNamespace); } } + if (!_jsxFactoryEntity) { + _jsxFactoryEntity = createQualifiedName(createIdentifier(unescapeLeadingUnderscores(_jsxNamespace)), "createElement"); + } return _jsxNamespace; + + function markAsSynthetic(node: Node): VisitResult { + node.pos = -1; + node.end = -1; + return visitEachChild(node, markAsSynthetic, nullTransformationContext); + } } function getEmitResolver(sourceFile: SourceFile, cancellationToken: CancellationToken) { @@ -2802,8 +2813,8 @@ namespace ts { const namespaceMeaning = SymbolFlags.Namespace | (isInJSFile(name) ? meaning & SymbolFlags.Value : 0); let symbol: Symbol | undefined; if (name.kind === SyntaxKind.Identifier) { - const message = meaning === namespaceMeaning ? Diagnostics.Cannot_find_namespace_0 : getCannotFindNameDiagnosticForName(getFirstIdentifier(name)); - const symbolFromJSPrototype = isInJSFile(name) ? resolveEntityNameFromAssignmentDeclaration(name, meaning) : undefined; + const message = meaning === namespaceMeaning || nodeIsSynthesized(name) ? Diagnostics.Cannot_find_namespace_0 : getCannotFindNameDiagnosticForName(getFirstIdentifier(name)); + const symbolFromJSPrototype = isInJSFile(name) && !nodeIsSynthesized(name) ? resolveEntityNameFromAssignmentDeclaration(name, meaning) : undefined; symbol = resolveName(location || name, name.escapedText, meaning, ignoreErrors || symbolFromJSPrototype ? undefined : message, name, /*isUse*/ true); if (!symbol) { return symbolFromJSPrototype; @@ -2846,7 +2857,7 @@ namespace ts { throw Debug.assertNever(name, "Unknown entity name kind."); } Debug.assert((getCheckFlags(symbol) & CheckFlags.Instantiated) === 0, "Should never get an instantiated symbol here."); - if (isEntityName(name) && (symbol.flags & SymbolFlags.Alias || name.parent.kind === SyntaxKind.ExportAssignment)) { + if (!nodeIsSynthesized(name) && isEntityName(name) && (symbol.flags & SymbolFlags.Alias || name.parent.kind === SyntaxKind.ExportAssignment)) { markSymbolOfAliasDeclarationIfTypeOnly(getAliasDeclarationFromName(name), symbol, /*finalTarget*/ undefined, /*overwriteEmpty*/ true); } return (symbol.flags & meaning) || dontResolveAlias ? symbol : resolveAlias(symbol); @@ -24391,7 +24402,7 @@ namespace ts { // can be specified by users through attributes property. const paramType = getEffectiveFirstArgumentForJsxSignature(signature, node); const attributesType = checkExpressionWithContextualType(node.attributes, paramType, /*inferenceContext*/ undefined, checkMode); - return checkTypeRelatedToAndOptionallyElaborate( + return checkTagNameDoesNotExpectTooManyArguments() && checkTypeRelatedToAndOptionallyElaborate( attributesType, paramType, relation, @@ -24400,6 +24411,80 @@ namespace ts { /*headMessage*/ undefined, containingMessageChain, errorOutputContainer); + + function checkTagNameDoesNotExpectTooManyArguments(): boolean { + const tagType = isJsxOpeningElement(node) || isJsxSelfClosingElement(node) && !isJsxIntrinsicIdentifier(node.tagName) ? checkExpression(node.tagName) : undefined; + if (!tagType) { + return true; + } + const tagCallSignatures = getSignaturesOfType(tagType, SignatureKind.Call); + if (!length(tagCallSignatures)) { + return true; + } + const factory = getJsxFactoryEntity(node); + if (!factory) { + return true; + } + const factorySymbol = resolveEntityName(factory, SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ false, node); + if (!factorySymbol) { + return true; + } + + const factoryType = getTypeOfSymbol(factorySymbol); + const callSignatures = getSignaturesOfType(factoryType, SignatureKind.Call); + if (!length(callSignatures)) { + return true; + } + + let hasFirstParamSignatures = false; + let maxParamCount = 0; + // Check that _some_ first parameter expects a FC-like thing, and that some overload of the SFC expects an acceptable number of arguments + for (const sig of callSignatures) { + const firstparam = getTypeAtPosition(sig, 0); + const signaturesOfParam = getSignaturesOfType(firstparam, SignatureKind.Call); + if (!length(signaturesOfParam)) continue; + for (const paramSig of signaturesOfParam) { + hasFirstParamSignatures = true; + if (hasEffectiveRestParameter(paramSig)) { + return true; // some signature has a rest param, so function components can have an arbitrary number of arguments + } + const paramCount = getParameterCount(paramSig); + if (paramCount > maxParamCount) { + maxParamCount = paramCount; + } + } + } + if (!hasFirstParamSignatures) { + // Not a single signature had a first parameter which expected a signature - for back compat, and + // to guard against generic factories which won't have signatures directly, do not error + return true; + } + let absoluteMinArgCount = Infinity; + for (const tagSig of tagCallSignatures) { + const tagRequiredArgCount = getMinArgumentCount(tagSig); + if (tagRequiredArgCount < absoluteMinArgCount) { + absoluteMinArgCount = tagRequiredArgCount; + } + } + if (absoluteMinArgCount <= maxParamCount) { + return true; // some signature accepts the number of arguments the function component provides + } + + if (reportErrors) { + const diag = createDiagnosticForNode(node.tagName, Diagnostics.Tag_0_expects_at_least_1_arguments_but_the_JSX_factory_2_provides_at_most_3, entityNameToString(node.tagName), absoluteMinArgCount, entityNameToString(factory), maxParamCount); + const tagNameDeclaration = getSymbolAtLocation(node.tagName)?.valueDeclaration; + if (tagNameDeclaration) { + addRelatedInfo(diag, createDiagnosticForNode(tagNameDeclaration, Diagnostics._0_is_declared_here, entityNameToString(node.tagName))); + } + if (errorOutputContainer && errorOutputContainer.skipLogging) { + (errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag); + } + if (!errorOutputContainer.skipLogging) { + diagnostics.add(diag); + } + } + return false; + } } function getSignatureApplicabilityError( @@ -35282,6 +35367,10 @@ namespace ts { return literalTypeToNode(type, node, tracker); } + function getJsxFactoryEntity(location: Node) { + return location ? (getJsxNamespace(location), (getSourceFileOfNode(location).localJsxFactory || _jsxFactoryEntity)) : _jsxFactoryEntity; + } + function createResolver(): EmitResolver { // this variable and functions that use it are deliberately moved here from the outer scope // to avoid scope pollution @@ -35353,7 +35442,7 @@ namespace ts { const symbol = node && getSymbolOfNode(node); return !!(symbol && getCheckFlags(symbol) & CheckFlags.Late); }, - getJsxFactoryEntity: location => location ? (getJsxNamespace(location), (getSourceFileOfNode(location).localJsxFactory || _jsxFactoryEntity)) : _jsxFactoryEntity, + getJsxFactoryEntity, getAllAccessorDeclarations(accessor: AccessorDeclaration): AllAccessorDeclarations { accessor = getParseTreeNode(accessor, isGetOrSetAccessorDeclaration)!; // TODO: GH#18217 const otherKind = accessor.kind === SyntaxKind.SetAccessor ? SyntaxKind.GetAccessor : SyntaxKind.SetAccessor; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 988c87e9b4..4ee407ce1c 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -4292,6 +4292,10 @@ "category": "Message", "code": 6228 }, + "Tag '{0}' expects at least '{1}' arguments, but the JSX factory '{2}' provides at most '{3}'.": { + "category": "Error", + "code": 6229 + }, "Projects to reference": { "category": "Message", diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 55ceab7941..7badd3af99 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -864,14 +864,17 @@ namespace ts { } } - export function entityNameToString(name: EntityNameOrEntityNameExpression): string { + export function entityNameToString(name: EntityNameOrEntityNameExpression | JsxTagNameExpression | PrivateIdentifier): string { switch (name.kind) { + case SyntaxKind.ThisKeyword: + return "this"; + case SyntaxKind.PrivateIdentifier: case SyntaxKind.Identifier: return getFullWidth(name) === 0 ? idText(name) : getTextOfNode(name); case SyntaxKind.QualifiedName: return entityNameToString(name.left) + "." + entityNameToString(name.right); case SyntaxKind.PropertyAccessExpression: - if (isIdentifier(name.name)) { + if (isIdentifier(name.name) || isPrivateIdentifier(name.name)) { return entityNameToString(name.expression) + "." + entityNameToString(name.name); } else { diff --git a/tests/baselines/reference/jsxIssuesErrorWhenTagExpectsTooManyArguments.errors.txt b/tests/baselines/reference/jsxIssuesErrorWhenTagExpectsTooManyArguments.errors.txt new file mode 100644 index 0000000000..f94c39ce5f --- /dev/null +++ b/tests/baselines/reference/jsxIssuesErrorWhenTagExpectsTooManyArguments.errors.txt @@ -0,0 +1,35 @@ +tests/cases/compiler/jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx(19,12): error TS6229: Tag 'MyComp4' expects at least '4' arguments, but the JSX factory 'React.createElement' provides at most '2'. +tests/cases/compiler/jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx(20,12): error TS6229: Tag 'MyComp3' expects at least '3' arguments, but the JSX factory 'React.createElement' provides at most '2'. + + +==== tests/cases/compiler/jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx (2 errors) ==== + /// + + import * as React from "react"; + + interface MyProps { + x: number; + } + + function MyComp4(props: MyProps, context: any, bad: any, verybad: any) { + return
; + } + function MyComp3(props: MyProps, context: any, bad: any) { + return
; + } + function MyComp2(props: MyProps, context: any) { + return
+ } + + const a = ; // using `MyComp` as a component should error - it expects more arguments than react provides + ~~~~~~~ +!!! error TS6229: Tag 'MyComp4' expects at least '4' arguments, but the JSX factory 'React.createElement' provides at most '2'. +!!! related TS2728 tests/cases/compiler/jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx:9:10: 'MyComp4' is declared here. + const b = ; // using `MyComp` as a component should error - it expects more arguments than react provides + ~~~~~~~ +!!! error TS6229: Tag 'MyComp3' expects at least '3' arguments, but the JSX factory 'React.createElement' provides at most '2'. +!!! related TS2728 tests/cases/compiler/jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx:12:10: 'MyComp3' is declared here. + const c = ; // Should be OK, `context` is allowed, per react rules + + declare function MyTagWithOptionalNonJSXBits(props: MyProps, context: any, nonReactArg?: string): JSX.Element; + const d = ; // Technically OK, but probably questionable \ No newline at end of file diff --git a/tests/baselines/reference/jsxIssuesErrorWhenTagExpectsTooManyArguments.js b/tests/baselines/reference/jsxIssuesErrorWhenTagExpectsTooManyArguments.js new file mode 100644 index 0000000000..f00c2f3795 --- /dev/null +++ b/tests/baselines/reference/jsxIssuesErrorWhenTagExpectsTooManyArguments.js @@ -0,0 +1,44 @@ +//// [jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx] +/// + +import * as React from "react"; + +interface MyProps { + x: number; +} + +function MyComp4(props: MyProps, context: any, bad: any, verybad: any) { + return
; +} +function MyComp3(props: MyProps, context: any, bad: any) { + return
; +} +function MyComp2(props: MyProps, context: any) { + return
+} + +const a = ; // using `MyComp` as a component should error - it expects more arguments than react provides +const b = ; // using `MyComp` as a component should error - it expects more arguments than react provides +const c = ; // Should be OK, `context` is allowed, per react rules + +declare function MyTagWithOptionalNonJSXBits(props: MyProps, context: any, nonReactArg?: string): JSX.Element; +const d = ; // Technically OK, but probably questionable + +//// [jsxIssuesErrorWhenTagExpectsTooManyArguments.js] +"use strict"; +/// +exports.__esModule = true; +var React = require("react"); +function MyComp4(props, context, bad, verybad) { + return React.createElement("div", null); +} +function MyComp3(props, context, bad) { + return React.createElement("div", null); +} +function MyComp2(props, context) { + return React.createElement("div", null); +} +var a = React.createElement(MyComp4, { x: 2 }); // using `MyComp` as a component should error - it expects more arguments than react provides +var b = React.createElement(MyComp3, { x: 2 }); // using `MyComp` as a component should error - it expects more arguments than react provides +var c = React.createElement(MyComp2, { x: 2 }); // Should be OK, `context` is allowed, per react rules +var d = React.createElement(MyTagWithOptionalNonJSXBits, { x: 2 }); // Technically OK, but probably questionable diff --git a/tests/baselines/reference/jsxIssuesErrorWhenTagExpectsTooManyArguments.symbols b/tests/baselines/reference/jsxIssuesErrorWhenTagExpectsTooManyArguments.symbols new file mode 100644 index 0000000000..ce2ae27e6e --- /dev/null +++ b/tests/baselines/reference/jsxIssuesErrorWhenTagExpectsTooManyArguments.symbols @@ -0,0 +1,76 @@ +=== tests/cases/compiler/jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx === +/// + +import * as React from "react"; +>React : Symbol(React, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 2, 6)) + +interface MyProps { +>MyProps : Symbol(MyProps, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 2, 31)) + + x: number; +>x : Symbol(MyProps.x, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 4, 19)) +} + +function MyComp4(props: MyProps, context: any, bad: any, verybad: any) { +>MyComp4 : Symbol(MyComp4, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 6, 1)) +>props : Symbol(props, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 8, 17)) +>MyProps : Symbol(MyProps, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 2, 31)) +>context : Symbol(context, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 8, 32)) +>bad : Symbol(bad, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 8, 46)) +>verybad : Symbol(verybad, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 8, 56)) + + return
; +>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2420, 114)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2420, 114)) +} +function MyComp3(props: MyProps, context: any, bad: any) { +>MyComp3 : Symbol(MyComp3, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 10, 1)) +>props : Symbol(props, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 11, 17)) +>MyProps : Symbol(MyProps, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 2, 31)) +>context : Symbol(context, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 11, 32)) +>bad : Symbol(bad, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 11, 46)) + + return
; +>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2420, 114)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2420, 114)) +} +function MyComp2(props: MyProps, context: any) { +>MyComp2 : Symbol(MyComp2, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 13, 1)) +>props : Symbol(props, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 14, 17)) +>MyProps : Symbol(MyProps, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 2, 31)) +>context : Symbol(context, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 14, 32)) + + return
+>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2420, 114)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react16.d.ts, 2420, 114)) +} + +const a = ; // using `MyComp` as a component should error - it expects more arguments than react provides +>a : Symbol(a, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 18, 5)) +>MyComp4 : Symbol(MyComp4, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 6, 1)) +>x : Symbol(x, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 18, 18)) + +const b = ; // using `MyComp` as a component should error - it expects more arguments than react provides +>b : Symbol(b, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 19, 5)) +>MyComp3 : Symbol(MyComp3, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 10, 1)) +>x : Symbol(x, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 19, 18)) + +const c = ; // Should be OK, `context` is allowed, per react rules +>c : Symbol(c, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 20, 5)) +>MyComp2 : Symbol(MyComp2, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 13, 1)) +>x : Symbol(x, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 20, 19)) + +declare function MyTagWithOptionalNonJSXBits(props: MyProps, context: any, nonReactArg?: string): JSX.Element; +>MyTagWithOptionalNonJSXBits : Symbol(MyTagWithOptionalNonJSXBits, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 20, 28)) +>props : Symbol(props, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 22, 45)) +>MyProps : Symbol(MyProps, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 2, 31)) +>context : Symbol(context, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 22, 60)) +>nonReactArg : Symbol(nonReactArg, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 22, 74)) +>JSX : Symbol(JSX, Decl(react16.d.ts, 2367, 12)) +>Element : Symbol(JSX.Element, Decl(react16.d.ts, 2368, 23)) + +const d = ; // Technically OK, but probably questionable +>d : Symbol(d, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 23, 5)) +>MyTagWithOptionalNonJSXBits : Symbol(MyTagWithOptionalNonJSXBits, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 20, 28)) +>x : Symbol(x, Decl(jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx, 23, 38)) + diff --git a/tests/baselines/reference/jsxIssuesErrorWhenTagExpectsTooManyArguments.types b/tests/baselines/reference/jsxIssuesErrorWhenTagExpectsTooManyArguments.types new file mode 100644 index 0000000000..a126895506 --- /dev/null +++ b/tests/baselines/reference/jsxIssuesErrorWhenTagExpectsTooManyArguments.types @@ -0,0 +1,80 @@ +=== tests/cases/compiler/jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx === +/// + +import * as React from "react"; +>React : typeof React + +interface MyProps { + x: number; +>x : number +} + +function MyComp4(props: MyProps, context: any, bad: any, verybad: any) { +>MyComp4 : (props: MyProps, context: any, bad: any, verybad: any) => JSX.Element +>props : MyProps +>context : any +>bad : any +>verybad : any + + return
; +>
: JSX.Element +>div : any +>div : any +} +function MyComp3(props: MyProps, context: any, bad: any) { +>MyComp3 : (props: MyProps, context: any, bad: any) => JSX.Element +>props : MyProps +>context : any +>bad : any + + return
; +>
: JSX.Element +>div : any +>div : any +} +function MyComp2(props: MyProps, context: any) { +>MyComp2 : (props: MyProps, context: any) => JSX.Element +>props : MyProps +>context : any + + return
+>
: JSX.Element +>div : any +>div : any +} + +const a = ; // using `MyComp` as a component should error - it expects more arguments than react provides +>a : JSX.Element +> : JSX.Element +>MyComp4 : (props: MyProps, context: any, bad: any, verybad: any) => JSX.Element +>x : number +>2 : 2 + +const b = ; // using `MyComp` as a component should error - it expects more arguments than react provides +>b : JSX.Element +> : JSX.Element +>MyComp3 : (props: MyProps, context: any, bad: any) => JSX.Element +>x : number +>2 : 2 + +const c = ; // Should be OK, `context` is allowed, per react rules +>c : JSX.Element +> : JSX.Element +>MyComp2 : (props: MyProps, context: any) => JSX.Element +>x : number +>2 : 2 + +declare function MyTagWithOptionalNonJSXBits(props: MyProps, context: any, nonReactArg?: string): JSX.Element; +>MyTagWithOptionalNonJSXBits : (props: MyProps, context: any, nonReactArg?: string) => JSX.Element +>props : MyProps +>context : any +>nonReactArg : string +>JSX : any + +const d = ; // Technically OK, but probably questionable +>d : JSX.Element +> : JSX.Element +>MyTagWithOptionalNonJSXBits : (props: MyProps, context: any, nonReactArg?: string) => JSX.Element +>x : number +>2 : 2 + diff --git a/tests/cases/compiler/jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx b/tests/cases/compiler/jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx new file mode 100644 index 0000000000..dd39d304f5 --- /dev/null +++ b/tests/cases/compiler/jsxIssuesErrorWhenTagExpectsTooManyArguments.tsx @@ -0,0 +1,25 @@ +// @jsx: react +/// + +import * as React from "react"; + +interface MyProps { + x: number; +} + +function MyComp4(props: MyProps, context: any, bad: any, verybad: any) { + return
; +} +function MyComp3(props: MyProps, context: any, bad: any) { + return
; +} +function MyComp2(props: MyProps, context: any) { + return
+} + +const a = ; // using `MyComp` as a component should error - it expects more arguments than react provides +const b = ; // using `MyComp` as a component should error - it expects more arguments than react provides +const c = ; // Should be OK, `context` is allowed, per react rules + +declare function MyTagWithOptionalNonJSXBits(props: MyProps, context: any, nonReactArg?: string): JSX.Element; +const d = ; // Technically OK, but probably questionable \ No newline at end of file