From 23f1e8ddeec78f1cf093289b90a4b8e3f46ff04d Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 8 Mar 2018 13:38:17 -0800 Subject: [PATCH 1/2] Parse and check type arguments on JSX opening like elements --- src/compiler/checker.ts | 86 ++++-- src/compiler/factory.ts | 16 +- src/compiler/parser.ts | 3 + src/compiler/program.ts | 4 +- src/compiler/types.ts | 2 + src/compiler/visitor.ts | 2 + .../reference/api/tsserverlibrary.d.ts | 10 +- tests/baselines/reference/api/typescript.d.ts | 10 +- ...xCheckJsxNoTypeArgumentsAllowed.errors.txt | 22 ++ .../jsxCheckJsxNoTypeArgumentsAllowed.js | 26 ++ .../jsxCheckJsxNoTypeArgumentsAllowed.symbols | 42 +++ .../jsxCheckJsxNoTypeArgumentsAllowed.types | 44 ++++ .../tsxTypeArgumentResolution.errors.txt | 145 ++++++++++ .../reference/tsxTypeArgumentResolution.js | 80 ++++++ .../tsxTypeArgumentResolution.symbols | 197 ++++++++++++++ .../reference/tsxTypeArgumentResolution.types | 248 ++++++++++++++++++ .../jsx/jsxCheckJsxNoTypeArgumentsAllowed.tsx | 23 ++ .../jsx/tsxTypeArgumentResolution.tsx | 59 +++++ 18 files changed, 985 insertions(+), 34 deletions(-) create mode 100644 tests/baselines/reference/jsxCheckJsxNoTypeArgumentsAllowed.errors.txt create mode 100644 tests/baselines/reference/jsxCheckJsxNoTypeArgumentsAllowed.js create mode 100644 tests/baselines/reference/jsxCheckJsxNoTypeArgumentsAllowed.symbols create mode 100644 tests/baselines/reference/jsxCheckJsxNoTypeArgumentsAllowed.types create mode 100644 tests/baselines/reference/tsxTypeArgumentResolution.errors.txt create mode 100644 tests/baselines/reference/tsxTypeArgumentResolution.js create mode 100644 tests/baselines/reference/tsxTypeArgumentResolution.symbols create mode 100644 tests/baselines/reference/tsxTypeArgumentResolution.types create mode 100644 tests/cases/conformance/jsx/jsxCheckJsxNoTypeArgumentsAllowed.tsx create mode 100644 tests/cases/conformance/jsx/tsxTypeArgumentResolution.tsx diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 28c2fc89b3792..5c82ad9f6ec25 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14636,7 +14636,7 @@ namespace ts { return mapType(valueType, t => getJsxSignaturesParameterTypes(t, isJs, node)); } - function getJsxSignaturesParameterTypes(valueType: Type, isJs: boolean, context: Node) { + function getJsxSignaturesParameterTypes(valueType: Type, isJs: boolean, context: JsxOpeningLikeElement) { // If the elemType is a string type, we have to return anyType to prevent an error downstream as we will try to find construct or call signature of the type if (valueType.flags & TypeFlags.String) { return anyType; @@ -14674,6 +14674,10 @@ namespace ts { } } + if (context.typeArguments) { + signatures = mapDefined(signatures, s => getJsxSignatureTypeArgumentInstantiation(s, context, isJs)); + } + return getUnionType(map(signatures, ctor ? t => getJsxPropsTypeFromConstructSignature(t, isJs, context) : t => getJsxPropsTypeFromCallSignature(t, context)), UnionReduction.None); } @@ -15475,21 +15479,57 @@ namespace ts { // Instantiate in context of source type const instantiatedSignatures = []; + let candidateForTypeArgumentError: Signature; + let hasTypeArgumentError: boolean = !!node.typeArguments; for (const signature of signatures) { if (signature.typeParameters) { const isJavascript = isInJavaScriptFile(node); - const inferenceContext = createInferenceContext(signature.typeParameters, signature, /*flags*/ isJavascript ? InferenceFlags.AnyDefault : InferenceFlags.None); - const typeArguments = inferJsxTypeArguments(signature, node, inferenceContext); - instantiatedSignatures.push(getSignatureInstantiation(signature, typeArguments, isJavascript)); + const typeArgumentInstantiated = getJsxSignatureTypeArgumentInstantiation(signature, node, isJavascript, /*reportErrors*/ false); + if (typeArgumentInstantiated) { + hasTypeArgumentError = false; + instantiatedSignatures.push(typeArgumentInstantiated); + } + else { + if (node.typeArguments && hasCorrectTypeArgumentArity(signature, node.typeArguments)) { + candidateForTypeArgumentError = signature; + } + const inferenceContext = createInferenceContext(signature.typeParameters, signature, /*flags*/ isJavascript ? InferenceFlags.AnyDefault : InferenceFlags.None); + const typeArguments = inferJsxTypeArguments(signature, node, inferenceContext); + instantiatedSignatures.push(getSignatureInstantiation(signature, typeArguments, isJavascript)); + } } else { instantiatedSignatures.push(signature); } } + if (node.typeArguments && hasTypeArgumentError) { + if (candidateForTypeArgumentError) { + checkTypeArguments(candidateForTypeArgumentError, node.typeArguments, /*reportErrors*/ true); + } + // Length check to avoid issuing an arity error on length=0, the "Type argument list cannot be empty" grammar error alone is fine + else if (node.typeArguments.length !== 0) { + diagnostics.add(getTypeArgumentArityError(node, signatures, node.typeArguments)); + } + } + return getUnionType(map(instantiatedSignatures, getReturnTypeOfSignature), UnionReduction.Subtype); } + function getJsxSignatureTypeArgumentInstantiation(signature: Signature, node: JsxOpeningLikeElement, isJavascript: boolean, reportErrors?: boolean) { + if (!node.typeArguments) { + return; + } + if (!hasCorrectTypeArgumentArity(signature, node.typeArguments)) { + return; + } + const args = checkTypeArguments(signature, node.typeArguments, reportErrors); + if (!args) { + return; + } + return getSignatureInstantiation(signature, args, isJavascript); + } + function getJsxNamespaceAt(location: Node) { const namespaceName = getJsxNamespace(location); const resolvedNamespace = resolveName(location, namespaceName, SymbolFlags.Namespace, /*diagnosticMessage*/ undefined, namespaceName, /*isUse*/ false); @@ -16750,13 +16790,7 @@ namespace ts { spreadArgIndex = getSpreadArgumentIndex(args); } - // If the user supplied type arguments, but the number of type arguments does not match - // the declared number of type parameters, the call has an incorrect arity. - const numTypeParameters = length(signature.typeParameters); - const minTypeArgumentCount = getMinTypeArgumentCount(signature.typeParameters); - const hasRightNumberOfTypeArgs = !typeArguments || - (typeArguments.length >= minTypeArgumentCount && typeArguments.length <= numTypeParameters); - if (!hasRightNumberOfTypeArgs) { + if (!hasCorrectTypeArgumentArity(signature, typeArguments)) { return false; } @@ -16776,6 +16810,15 @@ namespace ts { return callIsIncomplete || hasEnoughArguments; } + function hasCorrectTypeArgumentArity(signature: Signature, typeArguments: NodeArray | undefined) { + // If the user supplied type arguments, but the number of type arguments does not match + // the declared number of type parameters, the call has an incorrect arity. + const numTypeParameters = length(signature.typeParameters); + const minTypeArgumentCount = getMinTypeArgumentCount(signature.typeParameters); + return !typeArguments || + (typeArguments.length >= minTypeArgumentCount && typeArguments.length <= numTypeParameters); + } + // If type has a single call signature and no other members, return that signature. Otherwise, return undefined. function getSingleCallSignature(type: Type): Signature { if (type.flags & TypeFlags.Object) { @@ -17337,6 +17380,17 @@ namespace ts { } } + function getTypeArgumentArityError(node: Node, signatures: Signature[], typeArguments: NodeArray) { + let min = Number.POSITIVE_INFINITY; + let max = Number.NEGATIVE_INFINITY; + for (const sig of signatures) { + min = Math.min(min, getMinTypeArgumentCount(sig.typeParameters)); + max = Math.max(max, length(sig.typeParameters)); + } + const paramCount = min < max ? min + "-" + max : min; + return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, paramCount, typeArguments.length); + } + function resolveCall(node: CallLikeExpression, signatures: Signature[], candidatesOutArray: Signature[], fallbackError?: DiagnosticMessage): Signature { const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression; const isDecorator = node.kind === SyntaxKind.Decorator; @@ -17464,14 +17518,7 @@ namespace ts { checkTypeArguments(candidateForTypeArgumentError, (node as CallExpression).typeArguments, /*reportErrors*/ true, fallbackError); } else if (typeArguments && every(signatures, sig => length(sig.typeParameters) !== typeArguments.length)) { - let min = Number.POSITIVE_INFINITY; - let max = Number.NEGATIVE_INFINITY; - for (const sig of signatures) { - min = Math.min(min, getMinTypeArgumentCount(sig.typeParameters)); - max = Math.max(max, length(sig.typeParameters)); - } - const paramCount = min < max ? min + "-" + max : min; - diagnostics.add(createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, paramCount, typeArguments.length)); + diagnostics.add(getTypeArgumentArityError(node, signatures, typeArguments)); } else if (args) { let min = Number.POSITIVE_INFINITY; @@ -26678,6 +26725,7 @@ namespace ts { } function checkGrammarJsxElement(node: JsxOpeningLikeElement) { + checkGrammarTypeArguments(node, node.typeArguments); const seen = createUnderscoreEscapedMap(); for (const attr of node.attributes.properties) { diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 56d132fc925b4..5bb5da9ccbd36 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -2126,31 +2126,35 @@ namespace ts { : node; } - export function createJsxSelfClosingElement(tagName: JsxTagNameExpression, attributes: JsxAttributes) { + export function createJsxSelfClosingElement(tagName: JsxTagNameExpression, typeArguments: ReadonlyArray | undefined, attributes: JsxAttributes) { const node = createSynthesizedNode(SyntaxKind.JsxSelfClosingElement); node.tagName = tagName; + node.typeArguments = typeArguments && createNodeArray(typeArguments); node.attributes = attributes; return node; } - export function updateJsxSelfClosingElement(node: JsxSelfClosingElement, tagName: JsxTagNameExpression, attributes: JsxAttributes) { + export function updateJsxSelfClosingElement(node: JsxSelfClosingElement, tagName: JsxTagNameExpression, typeArguments: ReadonlyArray | undefined, attributes: JsxAttributes) { return node.tagName !== tagName + || node.typeArguments !== typeArguments || node.attributes !== attributes - ? updateNode(createJsxSelfClosingElement(tagName, attributes), node) + ? updateNode(createJsxSelfClosingElement(tagName, typeArguments, attributes), node) : node; } - export function createJsxOpeningElement(tagName: JsxTagNameExpression, attributes: JsxAttributes) { + export function createJsxOpeningElement(tagName: JsxTagNameExpression, typeArguments: ReadonlyArray | undefined, attributes: JsxAttributes) { const node = createSynthesizedNode(SyntaxKind.JsxOpeningElement); node.tagName = tagName; + node.typeArguments = typeArguments && createNodeArray(typeArguments); node.attributes = attributes; return node; } - export function updateJsxOpeningElement(node: JsxOpeningElement, tagName: JsxTagNameExpression, attributes: JsxAttributes) { + export function updateJsxOpeningElement(node: JsxOpeningElement, tagName: JsxTagNameExpression, typeArguments: ReadonlyArray | undefined, attributes: JsxAttributes) { return node.tagName !== tagName + || node.typeArguments !== typeArguments || node.attributes !== attributes - ? updateNode(createJsxOpeningElement(tagName, attributes), node) + ? updateNode(createJsxOpeningElement(tagName, typeArguments, attributes), node) : node; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 5619d3db66d42..b49a837619623 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -422,6 +422,7 @@ namespace ts { case SyntaxKind.JsxSelfClosingElement: case SyntaxKind.JsxOpeningElement: return visitNode(cbNode, (node).tagName) || + visitNodes(cbNode, cbNodes, (node).typeArguments) || visitNode(cbNode, (node).attributes); case SyntaxKind.JsxAttributes: return visitNodes(cbNode, cbNodes, (node).properties); @@ -4189,6 +4190,7 @@ namespace ts { } const tagName = parseJsxElementName(); + const typeArguments = tryParseTypeArguments(); const attributes = parseJsxAttributes(); let node: JsxOpeningLikeElement; @@ -4213,6 +4215,7 @@ namespace ts { } node.tagName = tagName; + node.typeArguments = typeArguments; node.attributes = attributes; return finishNode(node); diff --git a/src/compiler/program.ts b/src/compiler/program.ts index aff5154abe000..304ea468cae8c 100755 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1458,8 +1458,10 @@ namespace ts { case SyntaxKind.CallExpression: case SyntaxKind.NewExpression: case SyntaxKind.ExpressionWithTypeArguments: + case SyntaxKind.JsxSelfClosingElement: + case SyntaxKind.JsxOpeningElement: // Check type arguments - if (nodes === (parent).typeArguments) { + if (nodes === (parent).typeArguments) { diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.type_arguments_can_only_be_used_in_a_ts_file)); return; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 8aa700c437f31..2ff2b33da60af 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1763,6 +1763,7 @@ namespace ts { kind: SyntaxKind.JsxOpeningElement; parent?: JsxElement; tagName: JsxTagNameExpression; + typeArguments?: NodeArray; attributes: JsxAttributes; } @@ -1770,6 +1771,7 @@ namespace ts { export interface JsxSelfClosingElement extends PrimaryExpression { kind: SyntaxKind.JsxSelfClosingElement; tagName: JsxTagNameExpression; + typeArguments?: NodeArray; attributes: JsxAttributes; } diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index dbaf28a23aad7..9fccb9ea996e0 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -821,11 +821,13 @@ namespace ts { case SyntaxKind.JsxSelfClosingElement: return updateJsxSelfClosingElement(node, visitNode((node).tagName, visitor, isJsxTagNameExpression), + nodesVisitor((node).typeArguments, visitor, isTypeNode), visitNode((node).attributes, visitor, isJsxAttributes)); case SyntaxKind.JsxOpeningElement: return updateJsxOpeningElement(node, visitNode((node).tagName, visitor, isJsxTagNameExpression), + nodesVisitor((node).typeArguments, visitor, isTypeNode), visitNode((node).attributes, visitor, isJsxAttributes)); case SyntaxKind.JsxClosingElement: diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 77e288e79ddd8..68a319244acb0 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -1078,11 +1078,13 @@ declare namespace ts { kind: SyntaxKind.JsxOpeningElement; parent?: JsxElement; tagName: JsxTagNameExpression; + typeArguments?: NodeArray; attributes: JsxAttributes; } interface JsxSelfClosingElement extends PrimaryExpression { kind: SyntaxKind.JsxSelfClosingElement; tagName: JsxTagNameExpression; + typeArguments?: NodeArray; attributes: JsxAttributes; } interface JsxFragment extends PrimaryExpression { @@ -3665,10 +3667,10 @@ declare namespace ts { function updateExternalModuleReference(node: ExternalModuleReference, expression: Expression): ExternalModuleReference; function createJsxElement(openingElement: JsxOpeningElement, children: ReadonlyArray, closingElement: JsxClosingElement): JsxElement; function updateJsxElement(node: JsxElement, openingElement: JsxOpeningElement, children: ReadonlyArray, closingElement: JsxClosingElement): JsxElement; - function createJsxSelfClosingElement(tagName: JsxTagNameExpression, attributes: JsxAttributes): JsxSelfClosingElement; - function updateJsxSelfClosingElement(node: JsxSelfClosingElement, tagName: JsxTagNameExpression, attributes: JsxAttributes): JsxSelfClosingElement; - function createJsxOpeningElement(tagName: JsxTagNameExpression, attributes: JsxAttributes): JsxOpeningElement; - function updateJsxOpeningElement(node: JsxOpeningElement, tagName: JsxTagNameExpression, attributes: JsxAttributes): JsxOpeningElement; + function createJsxSelfClosingElement(tagName: JsxTagNameExpression, typeArguments: ReadonlyArray | undefined, attributes: JsxAttributes): JsxSelfClosingElement; + function updateJsxSelfClosingElement(node: JsxSelfClosingElement, tagName: JsxTagNameExpression, typeArguments: ReadonlyArray | undefined, attributes: JsxAttributes): JsxSelfClosingElement; + function createJsxOpeningElement(tagName: JsxTagNameExpression, typeArguments: ReadonlyArray | undefined, attributes: JsxAttributes): JsxOpeningElement; + function updateJsxOpeningElement(node: JsxOpeningElement, tagName: JsxTagNameExpression, typeArguments: ReadonlyArray | undefined, attributes: JsxAttributes): JsxOpeningElement; function createJsxClosingElement(tagName: JsxTagNameExpression): JsxClosingElement; function updateJsxClosingElement(node: JsxClosingElement, tagName: JsxTagNameExpression): JsxClosingElement; function createJsxFragment(openingFragment: JsxOpeningFragment, children: ReadonlyArray, closingFragment: JsxClosingFragment): JsxFragment; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 86cae0af609f3..1c8d88cc12214 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -1078,11 +1078,13 @@ declare namespace ts { kind: SyntaxKind.JsxOpeningElement; parent?: JsxElement; tagName: JsxTagNameExpression; + typeArguments?: NodeArray; attributes: JsxAttributes; } interface JsxSelfClosingElement extends PrimaryExpression { kind: SyntaxKind.JsxSelfClosingElement; tagName: JsxTagNameExpression; + typeArguments?: NodeArray; attributes: JsxAttributes; } interface JsxFragment extends PrimaryExpression { @@ -3612,10 +3614,10 @@ declare namespace ts { function updateExternalModuleReference(node: ExternalModuleReference, expression: Expression): ExternalModuleReference; function createJsxElement(openingElement: JsxOpeningElement, children: ReadonlyArray, closingElement: JsxClosingElement): JsxElement; function updateJsxElement(node: JsxElement, openingElement: JsxOpeningElement, children: ReadonlyArray, closingElement: JsxClosingElement): JsxElement; - function createJsxSelfClosingElement(tagName: JsxTagNameExpression, attributes: JsxAttributes): JsxSelfClosingElement; - function updateJsxSelfClosingElement(node: JsxSelfClosingElement, tagName: JsxTagNameExpression, attributes: JsxAttributes): JsxSelfClosingElement; - function createJsxOpeningElement(tagName: JsxTagNameExpression, attributes: JsxAttributes): JsxOpeningElement; - function updateJsxOpeningElement(node: JsxOpeningElement, tagName: JsxTagNameExpression, attributes: JsxAttributes): JsxOpeningElement; + function createJsxSelfClosingElement(tagName: JsxTagNameExpression, typeArguments: ReadonlyArray | undefined, attributes: JsxAttributes): JsxSelfClosingElement; + function updateJsxSelfClosingElement(node: JsxSelfClosingElement, tagName: JsxTagNameExpression, typeArguments: ReadonlyArray | undefined, attributes: JsxAttributes): JsxSelfClosingElement; + function createJsxOpeningElement(tagName: JsxTagNameExpression, typeArguments: ReadonlyArray | undefined, attributes: JsxAttributes): JsxOpeningElement; + function updateJsxOpeningElement(node: JsxOpeningElement, tagName: JsxTagNameExpression, typeArguments: ReadonlyArray | undefined, attributes: JsxAttributes): JsxOpeningElement; function createJsxClosingElement(tagName: JsxTagNameExpression): JsxClosingElement; function updateJsxClosingElement(node: JsxClosingElement, tagName: JsxTagNameExpression): JsxClosingElement; function createJsxFragment(openingFragment: JsxOpeningFragment, children: ReadonlyArray, closingFragment: JsxClosingFragment): JsxFragment; diff --git a/tests/baselines/reference/jsxCheckJsxNoTypeArgumentsAllowed.errors.txt b/tests/baselines/reference/jsxCheckJsxNoTypeArgumentsAllowed.errors.txt new file mode 100644 index 0000000000000..90b3719161ed2 --- /dev/null +++ b/tests/baselines/reference/jsxCheckJsxNoTypeArgumentsAllowed.errors.txt @@ -0,0 +1,22 @@ +tests/cases/conformance/jsx/file.jsx(4,17): error TS8011: 'type arguments' can only be used in a .ts file. + + +==== tests/cases/conformance/jsx/component.d.ts (0 errors) ==== + import * as React from "react"; + export declare class MyComp

extends React.Component { + internalProp: P; + } + + export interface Prop { + a: number, + b: string + } + +==== tests/cases/conformance/jsx/file.jsx (1 errors) ==== + import { MyComp, Prop } from "./component"; + import * as React from "react"; + + let x = a={10} b="hi" />; // error, no type arguments in js + ~~~~ +!!! error TS8011: 'type arguments' can only be used in a .ts file. + \ No newline at end of file diff --git a/tests/baselines/reference/jsxCheckJsxNoTypeArgumentsAllowed.js b/tests/baselines/reference/jsxCheckJsxNoTypeArgumentsAllowed.js new file mode 100644 index 0000000000000..d3f74b2b78da0 --- /dev/null +++ b/tests/baselines/reference/jsxCheckJsxNoTypeArgumentsAllowed.js @@ -0,0 +1,26 @@ +//// [tests/cases/conformance/jsx/jsxCheckJsxNoTypeArgumentsAllowed.tsx] //// + +//// [component.d.ts] +import * as React from "react"; +export declare class MyComp

extends React.Component { + internalProp: P; +} + +export interface Prop { + a: number, + b: string +} + +//// [file.jsx] +import { MyComp, Prop } from "./component"; +import * as React from "react"; + +let x = a={10} b="hi" />; // error, no type arguments in js + + +//// [file.jsx] +"use strict"; +exports.__esModule = true; +var component_1 = require("./component"); +var React = require("react"); +var x = ; // error, no type arguments in js diff --git a/tests/baselines/reference/jsxCheckJsxNoTypeArgumentsAllowed.symbols b/tests/baselines/reference/jsxCheckJsxNoTypeArgumentsAllowed.symbols new file mode 100644 index 0000000000000..98f3f48b281ee --- /dev/null +++ b/tests/baselines/reference/jsxCheckJsxNoTypeArgumentsAllowed.symbols @@ -0,0 +1,42 @@ +=== tests/cases/conformance/jsx/component.d.ts === +import * as React from "react"; +>React : Symbol(React, Decl(component.d.ts, 0, 6)) + +export declare class MyComp

extends React.Component { +>MyComp : Symbol(MyComp, Decl(component.d.ts, 0, 31)) +>P : Symbol(P, Decl(component.d.ts, 1, 28)) +>React.Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66)) +>React : Symbol(React, Decl(component.d.ts, 0, 6)) +>Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66)) +>P : Symbol(P, Decl(component.d.ts, 1, 28)) + + internalProp: P; +>internalProp : Symbol(MyComp.internalProp, Decl(component.d.ts, 1, 63)) +>P : Symbol(P, Decl(component.d.ts, 1, 28)) +} + +export interface Prop { +>Prop : Symbol(Prop, Decl(component.d.ts, 3, 1)) + + a: number, +>a : Symbol(Prop.a, Decl(component.d.ts, 5, 23)) + + b: string +>b : Symbol(Prop.b, Decl(component.d.ts, 6, 14)) +} + +=== tests/cases/conformance/jsx/file.jsx === +import { MyComp, Prop } from "./component"; +>MyComp : Symbol(MyComp, Decl(file.jsx, 0, 8)) +>Prop : Symbol(Prop, Decl(file.jsx, 0, 16)) + +import * as React from "react"; +>React : Symbol(React, Decl(file.jsx, 1, 6)) + +let x = a={10} b="hi" />; // error, no type arguments in js +>x : Symbol(x, Decl(file.jsx, 3, 3)) +>MyComp : Symbol(MyComp, Decl(file.jsx, 0, 8)) +>Prop : Symbol(Prop, Decl(file.jsx, 0, 16)) +>a : Symbol(a, Decl(file.jsx, 3, 21)) +>b : Symbol(b, Decl(file.jsx, 3, 28)) + diff --git a/tests/baselines/reference/jsxCheckJsxNoTypeArgumentsAllowed.types b/tests/baselines/reference/jsxCheckJsxNoTypeArgumentsAllowed.types new file mode 100644 index 0000000000000..cc642467386d8 --- /dev/null +++ b/tests/baselines/reference/jsxCheckJsxNoTypeArgumentsAllowed.types @@ -0,0 +1,44 @@ +=== tests/cases/conformance/jsx/component.d.ts === +import * as React from "react"; +>React : typeof React + +export declare class MyComp

extends React.Component { +>MyComp : MyComp

+>P : P +>React.Component : React.Component +>React : typeof React +>Component : typeof React.Component +>P : P + + internalProp: P; +>internalProp : P +>P : P +} + +export interface Prop { +>Prop : Prop + + a: number, +>a : number + + b: string +>b : string +} + +=== tests/cases/conformance/jsx/file.jsx === +import { MyComp, Prop } from "./component"; +>MyComp : typeof MyComp +>Prop : any + +import * as React from "react"; +>React : typeof React + +let x = a={10} b="hi" />; // error, no type arguments in js +>x : JSX.Element +> a={10} b="hi" /> : JSX.Element +>MyComp : typeof MyComp +>Prop : Prop +>a : number +>10 : 10 +>b : string + diff --git a/tests/baselines/reference/tsxTypeArgumentResolution.errors.txt b/tests/baselines/reference/tsxTypeArgumentResolution.errors.txt new file mode 100644 index 0000000000000..f78fc7c5c7af2 --- /dev/null +++ b/tests/baselines/reference/tsxTypeArgumentResolution.errors.txt @@ -0,0 +1,145 @@ +tests/cases/conformance/jsx/file.tsx(16,19): error TS2322: Type '{ a: number; b: number; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes> & Prop & { children?: ReactNode; }'. + Type '{ a: number; b: number; }' is not assignable to type 'Prop'. + Types of property 'b' are incompatible. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/jsx/file.tsx(18,19): error TS2322: Type '{ a: number; b: number; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes> & Prop & { children?: ReactNode; }'. + Type '{ a: number; b: number; }' is not assignable to type 'Prop'. + Types of property 'b' are incompatible. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/jsx/file.tsx(20,13): error TS2558: Expected 1 type arguments, but got 2. +tests/cases/conformance/jsx/file.tsx(22,13): error TS2558: Expected 1 type arguments, but got 2. +tests/cases/conformance/jsx/file.tsx(24,12): error TS1099: Type argument list cannot be empty. +tests/cases/conformance/jsx/file.tsx(26,12): error TS1099: Type argument list cannot be empty. +tests/cases/conformance/jsx/file.tsx(39,14): error TS2344: Type 'Prop' does not satisfy the constraint '{ a: string; }'. + Types of property 'a' are incompatible. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/jsx/file.tsx(39,20): error TS2322: Type '{ a: number; b: string; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes> & { a: string; } & { children?: ReactNode; }'. + Type '{ a: number; b: string; }' is not assignable to type '{ a: string; }'. + Types of property 'a' are incompatible. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/jsx/file.tsx(41,14): error TS2344: Type 'Prop' does not satisfy the constraint '{ a: string; }'. +tests/cases/conformance/jsx/file.tsx(41,20): error TS2322: Type '{ a: number; b: string; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes> & { a: string; } & { children?: ReactNode; }'. + Type '{ a: number; b: string; }' is not assignable to type '{ a: string; }'. + Types of property 'a' are incompatible. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/jsx/file.tsx(47,14): error TS2558: Expected 1-2 type arguments, but got 3. +tests/cases/conformance/jsx/file.tsx(47,53): error TS2339: Property 'b' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes> & { a: string; } & { children?: ReactNode; }'. +tests/cases/conformance/jsx/file.tsx(49,14): error TS2558: Expected 1-2 type arguments, but got 3. +tests/cases/conformance/jsx/file.tsx(49,53): error TS2339: Property 'b' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes> & { a: string; } & { children?: ReactNode; }'. +tests/cases/conformance/jsx/file.tsx(51,40): error TS2322: Type '{ a: string; b: string; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes> & { a: string; } & { b: number; } & { children?: ReactNode; }'. + Type '{ a: string; b: string; }' is not assignable to type '{ b: number; }'. + Types of property 'b' are incompatible. + Type 'string' is not assignable to type 'number'. +tests/cases/conformance/jsx/file.tsx(53,40): error TS2322: Type '{ a: string; b: string; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes> & { a: string; } & { b: number; } & { children?: ReactNode; }'. + Type '{ a: string; b: string; }' is not assignable to type '{ b: number; }'. + Types of property 'b' are incompatible. + Type 'string' is not assignable to type 'number'. + + +==== tests/cases/conformance/jsx/file.tsx (16 errors) ==== + import React = require('react'); + + interface Prop { + a: number, + b: string + } + + declare class MyComp

extends React.Component { + internalProp: P; + } + + let x = a={10} b="hi" />; // OK + + x = a={10} b="hi">; // OK + + x = a={10} b={20} />; // error + ~~~~~~~~~~~~~ +!!! error TS2322: Type '{ a: number; b: number; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes> & Prop & { children?: ReactNode; }'. +!!! error TS2322: Type '{ a: number; b: number; }' is not assignable to type 'Prop'. +!!! error TS2322: Types of property 'b' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + + x = a={10} b={20}>; // error + ~~~~~~~~~~~~~ +!!! error TS2322: Type '{ a: number; b: number; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes> & Prop & { children?: ReactNode; }'. +!!! error TS2322: Type '{ a: number; b: number; }' is not assignable to type 'Prop'. +!!! error TS2322: Types of property 'b' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + + x = a={10} b="hi" />; // error + ~~~~~~~~~~ +!!! error TS2558: Expected 1 type arguments, but got 2. + + x = a={10} b="hi">; // error + ~~~~~~~~~~ +!!! error TS2558: Expected 1 type arguments, but got 2. + + x = a={10} b="hi" />; // error + ~~ +!!! error TS1099: Type argument list cannot be empty. + + x = a={10} b="hi">; // error + ~~ +!!! error TS1099: Type argument list cannot be empty. + + x= /> // OK + + x= > // OK + + declare class MyComp2

extends React.Component

{ + internalProp: [P, P2]; + } + x = a="a" b="b" />; // OK + + x = a="a" b="b">; // OK + + x = a={10} b="hi" />; // error + ~~~~ +!!! error TS2344: Type 'Prop' does not satisfy the constraint '{ a: string; }'. +!!! error TS2344: Types of property 'a' are incompatible. +!!! error TS2344: Type 'number' is not assignable to type 'string'. + ~~~~~~~~~~~~~ +!!! error TS2322: Type '{ a: number; b: string; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes> & { a: string; } & { children?: ReactNode; }'. +!!! error TS2322: Type '{ a: number; b: string; }' is not assignable to type '{ a: string; }'. +!!! error TS2322: Types of property 'a' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + + x = a={10} b="hi">; // error + ~~~~ +!!! error TS2344: Type 'Prop' does not satisfy the constraint '{ a: string; }'. + ~~~~~~~~~~~~~ +!!! error TS2322: Type '{ a: number; b: string; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes> & { a: string; } & { children?: ReactNode; }'. +!!! error TS2322: Type '{ a: number; b: string; }' is not assignable to type '{ a: string; }'. +!!! error TS2322: Types of property 'a' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + + x = a="hi" b="hi" />; // OK + + x = a="hi" b="hi">; // OK + + x = a="hi" b="hi" />; // error + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2558: Expected 1-2 type arguments, but got 3. + ~~~~~~ +!!! error TS2339: Property 'b' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes> & { a: string; } & { children?: ReactNode; }'. + + x = a="hi" b="hi">; // error + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2558: Expected 1-2 type arguments, but got 3. + ~~~~~~ +!!! error TS2339: Property 'b' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes> & { a: string; } & { children?: ReactNode; }'. + + x = a="hi" b="hi" />; // error + ~~~~~~~~~~~~~ +!!! error TS2322: Type '{ a: string; b: string; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes> & { a: string; } & { b: number; } & { children?: ReactNode; }'. +!!! error TS2322: Type '{ a: string; b: string; }' is not assignable to type '{ b: number; }'. +!!! error TS2322: Types of property 'b' are incompatible. +!!! error TS2322: Type 'string' is not assignable to type 'number'. + + x = a="hi" b="hi">; // error + ~~~~~~~~~~~~~ +!!! error TS2322: Type '{ a: string; b: string; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes> & { a: string; } & { b: number; } & { children?: ReactNode; }'. +!!! error TS2322: Type '{ a: string; b: string; }' is not assignable to type '{ b: number; }'. +!!! error TS2322: Types of property 'b' are incompatible. +!!! error TS2322: Type 'string' is not assignable to type 'number'. + \ No newline at end of file diff --git a/tests/baselines/reference/tsxTypeArgumentResolution.js b/tests/baselines/reference/tsxTypeArgumentResolution.js new file mode 100644 index 0000000000000..dbe6d307786ee --- /dev/null +++ b/tests/baselines/reference/tsxTypeArgumentResolution.js @@ -0,0 +1,80 @@ +//// [file.tsx] +import React = require('react'); + +interface Prop { + a: number, + b: string +} + +declare class MyComp

extends React.Component { + internalProp: P; +} + +let x = a={10} b="hi" />; // OK + +x = a={10} b="hi">; // OK + +x = a={10} b={20} />; // error + +x = a={10} b={20}>; // error + +x = a={10} b="hi" />; // error + +x = a={10} b="hi">; // error + +x = a={10} b="hi" />; // error + +x = a={10} b="hi">; // error + +x= /> // OK + +x= > // OK + +declare class MyComp2

extends React.Component

{ + internalProp: [P, P2]; +} +x = a="a" b="b" />; // OK + +x = a="a" b="b">; // OK + +x = a={10} b="hi" />; // error + +x = a={10} b="hi">; // error + +x = a="hi" b="hi" />; // OK + +x = a="hi" b="hi">; // OK + +x = a="hi" b="hi" />; // error + +x = a="hi" b="hi">; // error + +x = a="hi" b="hi" />; // error + +x = a="hi" b="hi">; // error + + +//// [file.jsx] +"use strict"; +exports.__esModule = true; +var React = require("react"); +var x = ; // OK +x = ; // OK +x = ; // error +x = ; // error +x = ; // error +x = ; // error +x = ; // error +x = ; // error +x = ; // OK +x = ; // OK +x = ; // OK +x = ; // OK +x = ; // error +x = ; // error +x = ; // OK +x = ; // OK +x = ; // error +x = ; // error +x = ; // error +x = ; // error diff --git a/tests/baselines/reference/tsxTypeArgumentResolution.symbols b/tests/baselines/reference/tsxTypeArgumentResolution.symbols new file mode 100644 index 0000000000000..140e083b70bd9 --- /dev/null +++ b/tests/baselines/reference/tsxTypeArgumentResolution.symbols @@ -0,0 +1,197 @@ +=== tests/cases/conformance/jsx/file.tsx === +import React = require('react'); +>React : Symbol(React, Decl(file.tsx, 0, 0)) + +interface Prop { +>Prop : Symbol(Prop, Decl(file.tsx, 0, 32)) + + a: number, +>a : Symbol(Prop.a, Decl(file.tsx, 2, 16)) + + b: string +>b : Symbol(Prop.b, Decl(file.tsx, 3, 14)) +} + +declare class MyComp

extends React.Component { +>MyComp : Symbol(MyComp, Decl(file.tsx, 5, 1)) +>P : Symbol(P, Decl(file.tsx, 7, 21)) +>React.Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66)) +>React : Symbol(React, Decl(file.tsx, 0, 0)) +>Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66)) +>P : Symbol(P, Decl(file.tsx, 7, 21)) + + internalProp: P; +>internalProp : Symbol(MyComp.internalProp, Decl(file.tsx, 7, 56)) +>P : Symbol(P, Decl(file.tsx, 7, 21)) +} + +let x = a={10} b="hi" />; // OK +>x : Symbol(x, Decl(file.tsx, 11, 3)) +>MyComp : Symbol(MyComp, Decl(file.tsx, 5, 1)) +>Prop : Symbol(Prop, Decl(file.tsx, 0, 32)) +>a : Symbol(a, Decl(file.tsx, 11, 21)) +>b : Symbol(b, Decl(file.tsx, 11, 28)) + +x = a={10} b="hi">; // OK +>x : Symbol(x, Decl(file.tsx, 11, 3)) +>MyComp : Symbol(MyComp, Decl(file.tsx, 5, 1)) +>Prop : Symbol(Prop, Decl(file.tsx, 0, 32)) +>a : Symbol(a, Decl(file.tsx, 13, 17)) +>b : Symbol(b, Decl(file.tsx, 13, 24)) +>MyComp : Symbol(MyComp, Decl(file.tsx, 5, 1)) + +x = a={10} b={20} />; // error +>x : Symbol(x, Decl(file.tsx, 11, 3)) +>MyComp : Symbol(MyComp, Decl(file.tsx, 5, 1)) +>Prop : Symbol(Prop, Decl(file.tsx, 0, 32)) +>a : Symbol(a, Decl(file.tsx, 15, 17)) +>b : Symbol(b, Decl(file.tsx, 15, 24)) + +x = a={10} b={20}>; // error +>x : Symbol(x, Decl(file.tsx, 11, 3)) +>MyComp : Symbol(MyComp, Decl(file.tsx, 5, 1)) +>Prop : Symbol(Prop, Decl(file.tsx, 0, 32)) +>a : Symbol(a, Decl(file.tsx, 17, 17)) +>b : Symbol(b, Decl(file.tsx, 17, 24)) +>MyComp : Symbol(MyComp, Decl(file.tsx, 5, 1)) + +x = a={10} b="hi" />; // error +>x : Symbol(x, Decl(file.tsx, 11, 3)) +>MyComp : Symbol(MyComp, Decl(file.tsx, 5, 1)) +>Prop : Symbol(Prop, Decl(file.tsx, 0, 32)) +>Prop : Symbol(Prop, Decl(file.tsx, 0, 32)) +>a : Symbol(a, Decl(file.tsx, 19, 23)) +>b : Symbol(b, Decl(file.tsx, 19, 30)) + +x = a={10} b="hi">; // error +>x : Symbol(x, Decl(file.tsx, 11, 3)) +>MyComp : Symbol(MyComp, Decl(file.tsx, 5, 1)) +>Prop : Symbol(Prop, Decl(file.tsx, 0, 32)) +>Prop : Symbol(Prop, Decl(file.tsx, 0, 32)) +>a : Symbol(a, Decl(file.tsx, 21, 23)) +>b : Symbol(b, Decl(file.tsx, 21, 30)) +>MyComp : Symbol(MyComp, Decl(file.tsx, 5, 1)) + +x = a={10} b="hi" />; // error +>x : Symbol(x, Decl(file.tsx, 11, 3)) +>MyComp : Symbol(MyComp, Decl(file.tsx, 5, 1)) +>a : Symbol(a, Decl(file.tsx, 23, 13)) +>b : Symbol(b, Decl(file.tsx, 23, 20)) + +x = a={10} b="hi">; // error +>x : Symbol(x, Decl(file.tsx, 11, 3)) +>MyComp : Symbol(MyComp, Decl(file.tsx, 5, 1)) +>a : Symbol(a, Decl(file.tsx, 25, 13)) +>b : Symbol(b, Decl(file.tsx, 25, 20)) +>MyComp : Symbol(MyComp, Decl(file.tsx, 5, 1)) + +x= /> // OK +>x : Symbol(x, Decl(file.tsx, 11, 3)) +>MyComp : Symbol(MyComp, Decl(file.tsx, 5, 1)) + +x= > // OK +>x : Symbol(x, Decl(file.tsx, 11, 3)) +>MyComp : Symbol(MyComp, Decl(file.tsx, 5, 1)) +>MyComp : Symbol(MyComp, Decl(file.tsx, 5, 1)) + +declare class MyComp2

extends React.Component

{ +>MyComp2 : Symbol(MyComp2, Decl(file.tsx, 29, 24)) +>P : Symbol(P, Decl(file.tsx, 31, 22)) +>a : Symbol(a, Decl(file.tsx, 31, 33)) +>P2 : Symbol(P2, Decl(file.tsx, 31, 46)) +>React.Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66)) +>React : Symbol(React, Decl(file.tsx, 0, 0)) +>Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66)) +>P : Symbol(P, Decl(file.tsx, 31, 22)) +>P2 : Symbol(P2, Decl(file.tsx, 31, 46)) + + internalProp: [P, P2]; +>internalProp : Symbol(MyComp2.internalProp, Decl(file.tsx, 31, 93)) +>P : Symbol(P, Decl(file.tsx, 31, 22)) +>P2 : Symbol(P2, Decl(file.tsx, 31, 46)) +} +x = a="a" b="b" />; // OK +>x : Symbol(x, Decl(file.tsx, 11, 3)) +>MyComp2 : Symbol(MyComp2, Decl(file.tsx, 29, 24)) +>a : Symbol(a, Decl(file.tsx, 34, 14)) +>b : Symbol(b, Decl(file.tsx, 34, 24)) +>a : Symbol(a, Decl(file.tsx, 34, 36)) +>b : Symbol(b, Decl(file.tsx, 34, 42)) + +x = a="a" b="b">; // OK +>x : Symbol(x, Decl(file.tsx, 11, 3)) +>MyComp2 : Symbol(MyComp2, Decl(file.tsx, 29, 24)) +>a : Symbol(a, Decl(file.tsx, 36, 14)) +>b : Symbol(b, Decl(file.tsx, 36, 24)) +>a : Symbol(a, Decl(file.tsx, 36, 36)) +>b : Symbol(b, Decl(file.tsx, 36, 42)) +>MyComp2 : Symbol(MyComp2, Decl(file.tsx, 29, 24)) + +x = a={10} b="hi" />; // error +>x : Symbol(x, Decl(file.tsx, 11, 3)) +>MyComp2 : Symbol(MyComp2, Decl(file.tsx, 29, 24)) +>Prop : Symbol(Prop, Decl(file.tsx, 0, 32)) +>a : Symbol(a, Decl(file.tsx, 38, 18)) +>b : Symbol(b, Decl(file.tsx, 38, 25)) + +x = a={10} b="hi">; // error +>x : Symbol(x, Decl(file.tsx, 11, 3)) +>MyComp2 : Symbol(MyComp2, Decl(file.tsx, 29, 24)) +>Prop : Symbol(Prop, Decl(file.tsx, 0, 32)) +>a : Symbol(a, Decl(file.tsx, 40, 18)) +>b : Symbol(b, Decl(file.tsx, 40, 25)) +>MyComp2 : Symbol(MyComp2, Decl(file.tsx, 29, 24)) + +x = a="hi" b="hi" />; // OK +>x : Symbol(x, Decl(file.tsx, 11, 3)) +>MyComp2 : Symbol(MyComp2, Decl(file.tsx, 29, 24)) +>a : Symbol(a, Decl(file.tsx, 42, 14)) +>b : Symbol(b, Decl(file.tsx, 42, 27)) +>a : Symbol(a, Decl(file.tsx, 42, 38)) +>b : Symbol(b, Decl(file.tsx, 42, 45)) + +x = a="hi" b="hi">; // OK +>x : Symbol(x, Decl(file.tsx, 11, 3)) +>MyComp2 : Symbol(MyComp2, Decl(file.tsx, 29, 24)) +>a : Symbol(a, Decl(file.tsx, 44, 14)) +>b : Symbol(b, Decl(file.tsx, 44, 27)) +>a : Symbol(a, Decl(file.tsx, 44, 38)) +>b : Symbol(b, Decl(file.tsx, 44, 45)) +>MyComp2 : Symbol(MyComp2, Decl(file.tsx, 29, 24)) + +x = a="hi" b="hi" />; // error +>x : Symbol(x, Decl(file.tsx, 11, 3)) +>MyComp2 : Symbol(MyComp2, Decl(file.tsx, 29, 24)) +>a : Symbol(a, Decl(file.tsx, 46, 14)) +>b : Symbol(b, Decl(file.tsx, 46, 27)) +>Prop : Symbol(Prop, Decl(file.tsx, 0, 32)) +>a : Symbol(a, Decl(file.tsx, 46, 44)) +>b : Symbol(b, Decl(file.tsx, 46, 51)) + +x = a="hi" b="hi">; // error +>x : Symbol(x, Decl(file.tsx, 11, 3)) +>MyComp2 : Symbol(MyComp2, Decl(file.tsx, 29, 24)) +>a : Symbol(a, Decl(file.tsx, 48, 14)) +>b : Symbol(b, Decl(file.tsx, 48, 27)) +>Prop : Symbol(Prop, Decl(file.tsx, 0, 32)) +>a : Symbol(a, Decl(file.tsx, 48, 44)) +>b : Symbol(b, Decl(file.tsx, 48, 51)) +>MyComp2 : Symbol(MyComp2, Decl(file.tsx, 29, 24)) + +x = a="hi" b="hi" />; // error +>x : Symbol(x, Decl(file.tsx, 11, 3)) +>MyComp2 : Symbol(MyComp2, Decl(file.tsx, 29, 24)) +>a : Symbol(a, Decl(file.tsx, 50, 14)) +>b : Symbol(b, Decl(file.tsx, 50, 27)) +>a : Symbol(a, Decl(file.tsx, 50, 38)) +>b : Symbol(b, Decl(file.tsx, 50, 45)) + +x = a="hi" b="hi">; // error +>x : Symbol(x, Decl(file.tsx, 11, 3)) +>MyComp2 : Symbol(MyComp2, Decl(file.tsx, 29, 24)) +>a : Symbol(a, Decl(file.tsx, 52, 14)) +>b : Symbol(b, Decl(file.tsx, 52, 27)) +>a : Symbol(a, Decl(file.tsx, 52, 38)) +>b : Symbol(b, Decl(file.tsx, 52, 45)) +>MyComp2 : Symbol(MyComp2, Decl(file.tsx, 29, 24)) + diff --git a/tests/baselines/reference/tsxTypeArgumentResolution.types b/tests/baselines/reference/tsxTypeArgumentResolution.types new file mode 100644 index 0000000000000..ad1f7dbf7eba0 --- /dev/null +++ b/tests/baselines/reference/tsxTypeArgumentResolution.types @@ -0,0 +1,248 @@ +=== tests/cases/conformance/jsx/file.tsx === +import React = require('react'); +>React : typeof React + +interface Prop { +>Prop : Prop + + a: number, +>a : number + + b: string +>b : string +} + +declare class MyComp

extends React.Component { +>MyComp : MyComp

+>P : P +>React.Component : React.Component +>React : typeof React +>Component : typeof React.Component +>P : P + + internalProp: P; +>internalProp : P +>P : P +} + +let x = a={10} b="hi" />; // OK +>x : JSX.Element +> a={10} b="hi" /> : JSX.Element +>MyComp : typeof MyComp +>Prop : Prop +>a : number +>10 : 10 +>b : string + +x = a={10} b="hi">; // OK +>x = a={10} b="hi"> : JSX.Element +>x : JSX.Element +> a={10} b="hi"> : JSX.Element +>MyComp : typeof MyComp +>Prop : Prop +>a : number +>10 : 10 +>b : string +>MyComp : typeof MyComp + +x = a={10} b={20} />; // error +>x = a={10} b={20} /> : JSX.Element +>x : JSX.Element +> a={10} b={20} /> : JSX.Element +>MyComp : typeof MyComp +>Prop : Prop +>a : number +>10 : 10 +>b : number +>20 : 20 + +x = a={10} b={20}>; // error +>x = a={10} b={20}> : JSX.Element +>x : JSX.Element +> a={10} b={20}> : JSX.Element +>MyComp : typeof MyComp +>Prop : Prop +>a : number +>10 : 10 +>b : number +>20 : 20 +>MyComp : typeof MyComp + +x = a={10} b="hi" />; // error +>x = a={10} b="hi" /> : JSX.Element +>x : JSX.Element +> a={10} b="hi" /> : JSX.Element +>MyComp : typeof MyComp +>Prop : Prop +>Prop : Prop +>a : number +>10 : 10 +>b : string + +x = a={10} b="hi">; // error +>x = a={10} b="hi"> : JSX.Element +>x : JSX.Element +> a={10} b="hi"> : JSX.Element +>MyComp : typeof MyComp +>Prop : Prop +>Prop : Prop +>a : number +>10 : 10 +>b : string +>MyComp : typeof MyComp + +x = a={10} b="hi" />; // error +>x = a={10} b="hi" /> : JSX.Element +>x : JSX.Element +> a={10} b="hi" /> : JSX.Element +>MyComp : typeof MyComp +>a : number +>10 : 10 +>b : string + +x = a={10} b="hi">; // error +>x = a={10} b="hi"> : JSX.Element +>x : JSX.Element +> a={10} b="hi"> : JSX.Element +>MyComp : typeof MyComp +>a : number +>10 : 10 +>b : string +>MyComp : typeof MyComp + +x= /> // OK +>x= /> : JSX.Element +>x : JSX.Element +> /> : JSX.Element +>MyComp : typeof MyComp + +x= > // OK +>x= > : JSX.Element +>x : JSX.Element +>> : JSX.Element +>MyComp : typeof MyComp +>MyComp : typeof MyComp + +declare class MyComp2

extends React.Component

{ +>MyComp2 : MyComp2 +>P : P +>a : string +>P2 : P2 +>React.Component : React.Component

+>React : typeof React +>Component : typeof React.Component +>P : P +>P2 : P2 + + internalProp: [P, P2]; +>internalProp : [P, P2] +>P : P +>P2 : P2 +} +x = a="a" b="b" />; // OK +>x = a="a" b="b" /> : JSX.Element +>x : JSX.Element +> a="a" b="b" /> : JSX.Element +>MyComp2 : typeof MyComp2 +>a : string +>b : string +>a : string +>b : string + +x = a="a" b="b">; // OK +>x = a="a" b="b"> : JSX.Element +>x : JSX.Element +> a="a" b="b"> : JSX.Element +>MyComp2 : typeof MyComp2 +>a : string +>b : string +>a : string +>b : string +>MyComp2 : typeof MyComp2 + +x = a={10} b="hi" />; // error +>x = a={10} b="hi" /> : JSX.Element +>x : JSX.Element +> a={10} b="hi" /> : JSX.Element +>MyComp2 : typeof MyComp2 +>Prop : Prop +>a : number +>10 : 10 +>b : string + +x = a={10} b="hi">; // error +>x = a={10} b="hi"> : JSX.Element +>x : JSX.Element +> a={10} b="hi"> : JSX.Element +>MyComp2 : typeof MyComp2 +>Prop : Prop +>a : number +>10 : 10 +>b : string +>MyComp2 : typeof MyComp2 + +x = a="hi" b="hi" />; // OK +>x = a="hi" b="hi" /> : JSX.Element +>x : JSX.Element +> a="hi" b="hi" /> : JSX.Element +>MyComp2 : typeof MyComp2 +>a : string +>b : string +>a : string +>b : string + +x = a="hi" b="hi">; // OK +>x = a="hi" b="hi"> : JSX.Element +>x : JSX.Element +> a="hi" b="hi"> : JSX.Element +>MyComp2 : typeof MyComp2 +>a : string +>b : string +>a : string +>b : string +>MyComp2 : typeof MyComp2 + +x = a="hi" b="hi" />; // error +>x = a="hi" b="hi" /> : JSX.Element +>x : JSX.Element +> a="hi" b="hi" /> : JSX.Element +>MyComp2 : typeof MyComp2 +>a : string +>b : string +>Prop : Prop +>a : string +>b : string + +x = a="hi" b="hi">; // error +>x = a="hi" b="hi"> : JSX.Element +>x : JSX.Element +> a="hi" b="hi"> : JSX.Element +>MyComp2 : typeof MyComp2 +>a : string +>b : string +>Prop : Prop +>a : string +>b : string +>MyComp2 : typeof MyComp2 + +x = a="hi" b="hi" />; // error +>x = a="hi" b="hi" /> : JSX.Element +>x : JSX.Element +> a="hi" b="hi" /> : JSX.Element +>MyComp2 : typeof MyComp2 +>a : string +>b : number +>a : string +>b : string + +x = a="hi" b="hi">; // error +>x = a="hi" b="hi"> : JSX.Element +>x : JSX.Element +> a="hi" b="hi"> : JSX.Element +>MyComp2 : typeof MyComp2 +>a : string +>b : number +>a : string +>b : string +>MyComp2 : typeof MyComp2 + diff --git a/tests/cases/conformance/jsx/jsxCheckJsxNoTypeArgumentsAllowed.tsx b/tests/cases/conformance/jsx/jsxCheckJsxNoTypeArgumentsAllowed.tsx new file mode 100644 index 0000000000000..c3aa9ad2156aa --- /dev/null +++ b/tests/cases/conformance/jsx/jsxCheckJsxNoTypeArgumentsAllowed.tsx @@ -0,0 +1,23 @@ +// @jsx: preserve +// @noLib: true +// @skipLibCheck: true +// @libFiles: react.d.ts,lib.d.ts +// @allowJs: true +// @outDir: ./out +// @checkJs: true +// @filename: component.d.ts +import * as React from "react"; +export declare class MyComp

extends React.Component { + internalProp: P; +} + +export interface Prop { + a: number, + b: string +} + +// @filename: file.jsx +import { MyComp, Prop } from "./component"; +import * as React from "react"; + +let x = a={10} b="hi" />; // error, no type arguments in js diff --git a/tests/cases/conformance/jsx/tsxTypeArgumentResolution.tsx b/tests/cases/conformance/jsx/tsxTypeArgumentResolution.tsx new file mode 100644 index 0000000000000..a52e0b125cf15 --- /dev/null +++ b/tests/cases/conformance/jsx/tsxTypeArgumentResolution.tsx @@ -0,0 +1,59 @@ +// @filename: file.tsx +// @jsx: preserve +// @noLib: true +// @skipLibCheck: true +// @libFiles: react.d.ts,lib.d.ts + +import React = require('react'); + +interface Prop { + a: number, + b: string +} + +declare class MyComp

extends React.Component { + internalProp: P; +} + +let x = a={10} b="hi" />; // OK + +x = a={10} b="hi">; // OK + +x = a={10} b={20} />; // error + +x = a={10} b={20}>; // error + +x = a={10} b="hi" />; // error + +x = a={10} b="hi">; // error + +x = a={10} b="hi" />; // error + +x = a={10} b="hi">; // error + +x= /> // OK + +x= > // OK + +declare class MyComp2

extends React.Component

{ + internalProp: [P, P2]; +} +x = a="a" b="b" />; // OK + +x = a="a" b="b">; // OK + +x = a={10} b="hi" />; // error + +x = a={10} b="hi">; // error + +x = a="hi" b="hi" />; // OK + +x = a="hi" b="hi">; // OK + +x = a="hi" b="hi" />; // error + +x = a="hi" b="hi">; // error + +x = a="hi" b="hi" />; // error + +x = a="hi" b="hi">; // error From 9e3f5b50bd43f41254e8f8255d6a0c2a31c573c3 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 15 Mar 2018 17:08:31 -0700 Subject: [PATCH 2/2] Fix nits --- src/compiler/checker.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5c82ad9f6ec25..59a4af49162ff 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17381,13 +17381,13 @@ namespace ts { } function getTypeArgumentArityError(node: Node, signatures: Signature[], typeArguments: NodeArray) { - let min = Number.POSITIVE_INFINITY; - let max = Number.NEGATIVE_INFINITY; + let min = Infinity; + let max = -Infinity; for (const sig of signatures) { min = Math.min(min, getMinTypeArgumentCount(sig.typeParameters)); max = Math.max(max, length(sig.typeParameters)); } - const paramCount = min < max ? min + "-" + max : min; + const paramCount = min === max ? min : min + "-" + max; return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, paramCount, typeArguments.length); }