Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 21 additions & 14 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15159,7 +15159,7 @@ namespace ts {
* element is not a class element, or the class element type cannot be determined, returns 'undefined'.
* For example, in the element <MyClass>, the element instance type is `MyClass` (not `typeof MyClass`).
*/
function getJsxElementInstanceType(node: JsxOpeningLikeElement, valueType: Type, sourceAttributesType: Type) {
function getJsxElementInstanceType(node: JsxOpeningLikeElement, valueType: Type, sourceAttributesType: Type | undefined) {
Debug.assert(!(valueType.flags & TypeFlags.Union));
if (isTypeAny(valueType)) {
// Short-circuit if the class tag is using an element type 'any'
Expand All @@ -15178,20 +15178,27 @@ namespace ts {
}
}

const instantiatedSignatures = [];
for (const signature of signatures) {
if (signature.typeParameters) {
const isJavascript = isInJavaScriptFile(node);
const inferenceContext = createInferenceContext(signature, /*flags*/ isJavascript ? InferenceFlags.AnyDefault : 0);
const typeArguments = inferJsxTypeArguments(signature, sourceAttributesType, inferenceContext);
instantiatedSignatures.push(getSignatureInstantiation(signature, typeArguments, isJavascript));
}
else {
instantiatedSignatures.push(signature);
if (sourceAttributesType) {
// Instantiate in context of source type
const instantiatedSignatures = [];
for (const signature of signatures) {
if (signature.typeParameters) {
const isJavascript = isInJavaScriptFile(node);
const inferenceContext = createInferenceContext(signature, /*flags*/ isJavascript ? InferenceFlags.AnyDefault : 0);
const typeArguments = inferJsxTypeArguments(signature, sourceAttributesType, inferenceContext);
instantiatedSignatures.push(getSignatureInstantiation(signature, typeArguments, isJavascript));
}
else {
instantiatedSignatures.push(signature);
}
}
}

return getUnionType(map(instantiatedSignatures, getReturnTypeOfSignature), UnionReduction.Subtype);
return getUnionType(map(instantiatedSignatures, getReturnTypeOfSignature), UnionReduction.Subtype);
}
else {
// Do not instantiate if no source type is provided - type parameters and their constraints will be used by contextual typing
return getUnionType(map(signatures, getReturnTypeOfSignature), UnionReduction.Subtype);
}
}

/**
Expand Down Expand Up @@ -15415,7 +15422,7 @@ namespace ts {
}

// Get the element instance type (the result of newing or invoking this tag)
const elemInstanceType = getJsxElementInstanceType(openingLikeElement, elementType, sourceAttributesType || emptyObjectType);
const elemInstanceType = getJsxElementInstanceType(openingLikeElement, elementType, sourceAttributesType);

// If we should include all stateless attributes type, then get all attributes type from all stateless function signature.
// Otherwise get only attributes type from the signature picked by choose-overload logic.
Expand Down
32 changes: 32 additions & 0 deletions tests/baselines/reference/jsxHasLiteralType.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//// [jsxHasLiteralType.tsx]
import * as React from "react";

interface Props {
x?: "a" | "b";
}
class MyComponent<P extends Props = Props> extends React.Component<P, {}> {}
const m = <MyComponent x="a"/>


//// [jsxHasLiteralType.js]
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
exports.__esModule = true;
var React = require("react");
var MyComponent = /** @class */ (function (_super) {
__extends(MyComponent, _super);
function MyComponent() {
return _super !== null && _super.apply(this, arguments) || this;
}
return MyComponent;
}(React.Component));
var m = React.createElement(MyComponent, { x: "a" });
25 changes: 25 additions & 0 deletions tests/baselines/reference/jsxHasLiteralType.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
=== tests/cases/compiler/jsxHasLiteralType.tsx ===
import * as React from "react";
>React : Symbol(React, Decl(jsxHasLiteralType.tsx, 0, 6))

interface Props {
>Props : Symbol(Props, Decl(jsxHasLiteralType.tsx, 0, 31))

x?: "a" | "b";
>x : Symbol(Props.x, Decl(jsxHasLiteralType.tsx, 2, 17))
}
class MyComponent<P extends Props = Props> extends React.Component<P, {}> {}
>MyComponent : Symbol(MyComponent, Decl(jsxHasLiteralType.tsx, 4, 1))
>P : Symbol(P, Decl(jsxHasLiteralType.tsx, 5, 18))
>Props : Symbol(Props, Decl(jsxHasLiteralType.tsx, 0, 31))
>Props : Symbol(Props, Decl(jsxHasLiteralType.tsx, 0, 31))
>React.Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66))
>React : Symbol(React, Decl(jsxHasLiteralType.tsx, 0, 6))
>Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66))
>P : Symbol(P, Decl(jsxHasLiteralType.tsx, 5, 18))

const m = <MyComponent x="a"/>
>m : Symbol(m, Decl(jsxHasLiteralType.tsx, 6, 5))
>MyComponent : Symbol(MyComponent, Decl(jsxHasLiteralType.tsx, 4, 1))
>x : Symbol(x, Decl(jsxHasLiteralType.tsx, 6, 22))

26 changes: 26 additions & 0 deletions tests/baselines/reference/jsxHasLiteralType.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
=== tests/cases/compiler/jsxHasLiteralType.tsx ===
import * as React from "react";
>React : typeof React

interface Props {
>Props : Props

x?: "a" | "b";
>x : "a" | "b" | undefined
}
class MyComponent<P extends Props = Props> extends React.Component<P, {}> {}
>MyComponent : MyComponent<P>
>P : P
>Props : Props
>Props : Props
>React.Component : React.Component<P, {}>
>React : typeof React
>Component : typeof React.Component
>P : P

const m = <MyComponent x="a"/>
>m : JSX.Element
><MyComponent x="a"/> : JSX.Element
>MyComponent : typeof MyComponent
>x : "a"

11 changes: 11 additions & 0 deletions tests/cases/compiler/jsxHasLiteralType.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// @strictNullChecks: true
// @jsx: react
// @skipLibCheck: true
// @libFiles: lib.d.ts,react.d.ts
import * as React from "react";

interface Props {
x?: "a" | "b";
}
class MyComponent<P extends Props = Props> extends React.Component<P, {}> {}
const m = <MyComponent x="a"/>