Skip to content

Commit b82ff93

Browse files
committed
Don't crash if there's no JSX.Element during SFC resolution
Fixes microsoft#7286
1 parent 8a72229 commit b82ff93

8 files changed

+67
-17
lines changed

src/compiler/checker.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8797,18 +8797,20 @@ namespace ts {
87978797
if (!elemClassType || !isTypeAssignableTo(elemInstanceType, elemClassType)) {
87988798
// Is this is a stateless function component? See if its single signature's return type is
87998799
// assignable to the JSX Element Type
8800-
const elemType = checkExpression(node.tagName);
8801-
const callSignatures = elemType && getSignaturesOfType(elemType, SignatureKind.Call);
8802-
const callSignature = callSignatures && callSignatures.length > 0 && callSignatures[0];
8803-
const callReturnType = callSignature && getReturnTypeOfSignature(callSignature);
8804-
let paramType = callReturnType && (callSignature.parameters.length === 0 ? emptyObjectType : getTypeOfSymbol(callSignature.parameters[0]));
8805-
if (callReturnType && isTypeAssignableTo(callReturnType, jsxElementType)) {
8806-
// Intersect in JSX.IntrinsicAttributes if it exists
8807-
const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes);
8808-
if (intrinsicAttributes !== unknownType) {
8809-
paramType = intersectTypes(intrinsicAttributes, paramType);
8800+
if (jsxElementType) {
8801+
const elemType = checkExpression(node.tagName);
8802+
const callSignatures = elemType && getSignaturesOfType(elemType, SignatureKind.Call);
8803+
const callSignature = callSignatures && callSignatures.length > 0 && callSignatures[0];
8804+
const callReturnType = callSignature && getReturnTypeOfSignature(callSignature);
8805+
let paramType = callReturnType && (callSignature.parameters.length === 0 ? emptyObjectType : getTypeOfSymbol(callSignature.parameters[0]));
8806+
if (callReturnType && isTypeAssignableTo(callReturnType, jsxElementType)) {
8807+
// Intersect in JSX.IntrinsicAttributes if it exists
8808+
const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes);
8809+
if (intrinsicAttributes !== unknownType) {
8810+
paramType = intersectTypes(intrinsicAttributes, paramType);
8811+
}
8812+
return links.resolvedJsxType = paramType;
88108813
}
8811-
return links.resolvedJsxType = paramType;
88128814
}
88138815
}
88148816

tests/baselines/reference/contextuallyTypedStringLiteralsInJsxAttributes01.errors.txt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1-
tests/cases/conformance/types/contextualTypes/jsxAttributes/contextuallyTypedStringLiteralsInJsxAttributes01.tsx(13,15): error TS2322: Type '"f"' is not assignable to type '"A" | "B" | "C"'.
1+
tests/cases/conformance/types/contextualTypes/jsxAttributes/contextuallyTypedStringLiteralsInJsxAttributes01.tsx(16,15): error TS2322: Type '"f"' is not assignable to type '"A" | "B" | "C"'.
22
Type '"f"' is not assignable to type '"C"'.
3-
tests/cases/conformance/types/contextualTypes/jsxAttributes/contextuallyTypedStringLiteralsInJsxAttributes01.tsx(14,15): error TS2322: Type '"f"' is not assignable to type '"A" | "B" | "C"'.
3+
tests/cases/conformance/types/contextualTypes/jsxAttributes/contextuallyTypedStringLiteralsInJsxAttributes01.tsx(17,15): error TS2322: Type '"f"' is not assignable to type '"A" | "B" | "C"'.
44
Type '"f"' is not assignable to type '"C"'.
55

66

77
==== tests/cases/conformance/types/contextualTypes/jsxAttributes/contextuallyTypedStringLiteralsInJsxAttributes01.tsx (2 errors) ====
88

99
namespace JSX {
10-
interface IntrinsicElements {
10+
export interface IntrinsicElements {
1111
span: {};
1212
}
13+
export interface Element {
14+
something?: any;
15+
}
1316
}
1417

1518
const FooComponent = (props: { foo: "A" | "B" | "C" }) => <span>{props.foo}</span>;

tests/baselines/reference/contextuallyTypedStringLiteralsInJsxAttributes01.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
//// [contextuallyTypedStringLiteralsInJsxAttributes01.tsx]
22

33
namespace JSX {
4-
interface IntrinsicElements {
4+
export interface IntrinsicElements {
55
span: {};
66
}
7+
export interface Element {
8+
something?: any;
9+
}
710
}
811

912
const FooComponent = (props: { foo: "A" | "B" | "C" }) => <span>{props.foo}</span>;
@@ -24,7 +27,13 @@ var FooComponent = function (props) { return <span>{props.foo}</span>; };
2427

2528
//// [contextuallyTypedStringLiteralsInJsxAttributes01.d.ts]
2629
declare namespace JSX {
30+
interface IntrinsicElements {
31+
span: {};
32+
}
33+
interface Element {
34+
something?: any;
35+
}
2736
}
2837
declare const FooComponent: (props: {
2938
foo: "A" | "B" | "C";
30-
}) => any;
39+
}) => JSX.Element;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//// [test.tsx]
2+
3+
function Test() { }
4+
<Test></Test>
5+
6+
7+
//// [test.jsx]
8+
function Test() { }
9+
<Test></Test>;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
=== tests/cases/conformance/jsx/test.tsx ===
2+
3+
function Test() { }
4+
>Test : Symbol(Test, Decl(test.tsx, 0, 0))
5+
6+
<Test></Test>
7+
>Test : Symbol(Test, Decl(test.tsx, 0, 0))
8+
>Test : Symbol(Test, Decl(test.tsx, 0, 0))
9+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
=== tests/cases/conformance/jsx/test.tsx ===
2+
3+
function Test() { }
4+
>Test : () => void
5+
6+
<Test></Test>
7+
><Test></Test> : any
8+
>Test : any
9+
>Test : any
10+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
//@jsx: preserve
2+
3+
//@filename: test.tsx
4+
function Test() { }
5+
<Test></Test>

tests/cases/conformance/types/contextualTypes/jsxAttributes/contextuallyTypedStringLiteralsInJsxAttributes01.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
// @declaration: true
33

44
namespace JSX {
5-
interface IntrinsicElements {
5+
export interface IntrinsicElements {
66
span: {};
77
}
8+
export interface Element {
9+
something?: any;
10+
}
811
}
912

1013
const FooComponent = (props: { foo: "A" | "B" | "C" }) => <span>{props.foo}</span>;

0 commit comments

Comments
 (0)