Skip to content

Commit 5bc10b9

Browse files
committed
It's no longer safe to store JSX elem. attr. type in nodelinks.resolvedType
1 parent 16c8344 commit 5bc10b9

File tree

6 files changed

+158
-13
lines changed

6 files changed

+158
-13
lines changed

src/compiler/checker.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6980,57 +6980,57 @@ namespace ts {
69806980
*/
69816981
function getJsxElementAttributesType(node: JsxOpeningLikeElement): Type {
69826982
let links = getNodeLinks(node);
6983-
if (!links.resolvedType) {
6983+
if (!links.resolvedJsxType) {
69846984
let sym = getJsxElementTagSymbol(node);
69856985

69866986
if (links.jsxFlags & JsxFlags.ClassElement) {
69876987
let elemInstanceType = getJsxElementInstanceType(node);
69886988

69896989
if (isTypeAny(elemInstanceType)) {
6990-
return links.resolvedType = anyType;
6990+
return links.resolvedJsxType = anyType;
69916991
}
69926992

69936993
var propsName = getJsxElementPropertiesName();
69946994
if (propsName === undefined) {
69956995
// There is no type ElementAttributesProperty, return 'any'
6996-
return links.resolvedType = anyType;
6996+
return links.resolvedJsxType = anyType;
69976997
}
69986998
else if (propsName === '') {
69996999
// If there is no e.g. 'props' member in ElementAttributesProperty, use the element class type instead
7000-
return links.resolvedType = elemInstanceType;
7000+
return links.resolvedJsxType = elemInstanceType;
70017001
}
70027002
else {
70037003
var attributesType = getTypeOfPropertyOfType(elemInstanceType, propsName);
70047004

70057005
if (!attributesType) {
70067006
// There is no property named 'props' on this instance type
7007-
return links.resolvedType = emptyObjectType;
7007+
return links.resolvedJsxType = emptyObjectType;
70087008
}
70097009
else if (isTypeAny(attributesType) || (attributesType === unknownType)) {
7010-
return links.resolvedType = attributesType;
7010+
return links.resolvedJsxType = attributesType;
70117011
}
70127012
else if (!(attributesType.flags & TypeFlags.ObjectType)) {
70137013
error(node.tagName, Diagnostics.JSX_element_attributes_type_0_must_be_an_object_type, typeToString(attributesType));
7014-
return links.resolvedType = anyType;
7014+
return links.resolvedJsxType = anyType;
70157015
}
70167016
else {
7017-
return links.resolvedType = attributesType;
7017+
return links.resolvedJsxType = attributesType;
70187018
}
70197019
}
70207020
}
70217021
else if (links.jsxFlags & JsxFlags.IntrinsicNamedElement) {
7022-
return links.resolvedType = getTypeOfSymbol(sym);
7022+
return links.resolvedJsxType = getTypeOfSymbol(sym);
70237023
}
70247024
else if (links.jsxFlags & JsxFlags.IntrinsicIndexedElement) {
7025-
return links.resolvedType = getIndexTypeOfSymbol(sym, IndexKind.String);
7025+
return links.resolvedJsxType = getIndexTypeOfSymbol(sym, IndexKind.String);
70267026
}
70277027
else {
70287028
// Resolution failed
7029-
return links.resolvedType = anyType;
7029+
return links.resolvedJsxType = anyType;
70307030
}
70317031
}
70327032

7033-
return links.resolvedType;
7033+
return links.resolvedJsxType;
70347034
}
70357035

70367036
/**
@@ -7100,6 +7100,7 @@ namespace ts {
71007100
if (!(targetProperties[i].flags & SymbolFlags.Optional) &&
71017101
nameTable[targetProperties[i].name] === undefined) {
71027102

7103+
console.log('oops?');
71037104
error(node, Diagnostics.Property_0_is_missing_in_type_1, targetProperties[i].name, typeToString(targetAttributesType));
71047105
}
71057106
}

src/compiler/parser.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3255,7 +3255,6 @@ namespace ts {
32553255
let node = <JsxElement>createNode(SyntaxKind.JsxElement, opening.pos);
32563256
node.openingElement = opening;
32573257

3258-
debugger;
32593258
node.children = parseJsxChildren(node.openingElement.tagName);
32603259
node.closingElement = parseJsxClosingElement();
32613260
return finishNode(node);

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1687,6 +1687,7 @@ namespace ts {
16871687
hasReportedStatementInAmbientContext?: boolean; // Cache boolean if we report statements in ambient context
16881688
importOnRightSide?: Symbol; // for import declarations - import that appear on the right side
16891689
jsxFlags?: JsxFlags; // flags for knowning what kind of element/attributes we're dealing with
1690+
resolvedJsxType?: Type; // resolved element attributes type of a JSX openinglike element
16901691
}
16911692

16921693
export const enum TypeFlags {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//// [tsxInArrowFunction.tsx]
2+
3+
declare namespace JSX {
4+
interface Element { }
5+
interface IntrinsicElements {
6+
div: {
7+
text?: string;
8+
}
9+
}
10+
}
11+
12+
13+
// didn't work
14+
<div>{() => <div text="wat" />}</div>;
15+
16+
// didn't work
17+
<div>{x => <div text="wat" />}</div>;
18+
19+
// worked
20+
<div>{() => (<div text="wat" />)}</div>;
21+
22+
// worked (!)
23+
<div>{() => <div text="wat"></div>}</div>;
24+
25+
26+
//// [tsxInArrowFunction.jsx]
27+
// didn't work
28+
<div>{function () { return <div text="wat"/>; }}</div>;
29+
// didn't work
30+
<div>{function (x) { return <div text="wat"/>; }}</div>;
31+
// worked
32+
<div>{function () { return (<div text="wat"/>); }}</div>;
33+
// worked (!)
34+
<div>{function () { return <div text="wat"></div>; }}</div>;
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
=== tests/cases/conformance/jsx/tsxInArrowFunction.tsx ===
2+
3+
declare namespace JSX {
4+
>JSX : Symbol(JSX, Decl(tsxInArrowFunction.tsx, 0, 0))
5+
6+
interface Element { }
7+
>Element : Symbol(Element, Decl(tsxInArrowFunction.tsx, 1, 23))
8+
9+
interface IntrinsicElements {
10+
>IntrinsicElements : Symbol(IntrinsicElements, Decl(tsxInArrowFunction.tsx, 2, 25))
11+
12+
div: {
13+
>div : Symbol(div, Decl(tsxInArrowFunction.tsx, 3, 33))
14+
15+
text?: string;
16+
>text : Symbol(text, Decl(tsxInArrowFunction.tsx, 4, 14))
17+
}
18+
}
19+
}
20+
21+
22+
// didn't work
23+
<div>{() => <div text="wat" />}</div>;
24+
>div : Symbol(JSX.IntrinsicElements.div, Decl(tsxInArrowFunction.tsx, 3, 33))
25+
>div : Symbol(JSX.IntrinsicElements.div, Decl(tsxInArrowFunction.tsx, 3, 33))
26+
>text : Symbol(text, Decl(tsxInArrowFunction.tsx, 4, 14))
27+
28+
// didn't work
29+
<div>{x => <div text="wat" />}</div>;
30+
>div : Symbol(JSX.IntrinsicElements.div, Decl(tsxInArrowFunction.tsx, 3, 33))
31+
>x : Symbol(x, Decl(tsxInArrowFunction.tsx, 15, 6))
32+
>div : Symbol(JSX.IntrinsicElements.div, Decl(tsxInArrowFunction.tsx, 3, 33))
33+
>text : Symbol(text, Decl(tsxInArrowFunction.tsx, 4, 14))
34+
35+
// worked
36+
<div>{() => (<div text="wat" />)}</div>;
37+
>div : Symbol(JSX.IntrinsicElements.div, Decl(tsxInArrowFunction.tsx, 3, 33))
38+
>div : Symbol(JSX.IntrinsicElements.div, Decl(tsxInArrowFunction.tsx, 3, 33))
39+
>text : Symbol(text, Decl(tsxInArrowFunction.tsx, 4, 14))
40+
41+
// worked (!)
42+
<div>{() => <div text="wat"></div>}</div>;
43+
>div : Symbol(JSX.IntrinsicElements.div, Decl(tsxInArrowFunction.tsx, 3, 33))
44+
>div : Symbol(JSX.IntrinsicElements.div, Decl(tsxInArrowFunction.tsx, 3, 33))
45+
>text : Symbol(text, Decl(tsxInArrowFunction.tsx, 4, 14))
46+
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
=== tests/cases/conformance/jsx/tsxInArrowFunction.tsx ===
2+
3+
declare namespace JSX {
4+
>JSX : any
5+
6+
interface Element { }
7+
>Element : Element
8+
9+
interface IntrinsicElements {
10+
>IntrinsicElements : IntrinsicElements
11+
12+
div: {
13+
>div : { text?: string; }
14+
15+
text?: string;
16+
>text : string
17+
}
18+
}
19+
}
20+
21+
22+
// didn't work
23+
<div>{() => <div text="wat" />}</div>;
24+
><div>{() => <div text="wat" />}</div> : JSX.Element
25+
>div : any
26+
>() => <div text="wat" /> : () => JSX.Element
27+
><div text="wat" /> : JSX.Element
28+
>div : any
29+
>text : any
30+
>div : any
31+
32+
// didn't work
33+
<div>{x => <div text="wat" />}</div>;
34+
><div>{x => <div text="wat" />}</div> : JSX.Element
35+
>div : any
36+
>x => <div text="wat" /> : (x: any) => JSX.Element
37+
>x : any
38+
><div text="wat" /> : JSX.Element
39+
>div : any
40+
>text : any
41+
>div : any
42+
43+
// worked
44+
<div>{() => (<div text="wat" />)}</div>;
45+
><div>{() => (<div text="wat" />)}</div> : JSX.Element
46+
>div : any
47+
>() => (<div text="wat" />) : () => JSX.Element
48+
>(<div text="wat" />) : JSX.Element
49+
><div text="wat" /> : JSX.Element
50+
>div : any
51+
>text : any
52+
>div : any
53+
54+
// worked (!)
55+
<div>{() => <div text="wat"></div>}</div>;
56+
><div>{() => <div text="wat"></div>}</div> : JSX.Element
57+
>div : any
58+
>() => <div text="wat"></div> : () => JSX.Element
59+
><div text="wat"></div> : JSX.Element
60+
>div : any
61+
>text : any
62+
>div : any
63+
>div : any
64+

0 commit comments

Comments
 (0)