Skip to content

Commit 1a43ad0

Browse files
authored
Lookup JSX namespace within factory function (#22207)
* Lookup JSX namespace within factory function * Rename functions
1 parent 6218567 commit 1a43ad0

16 files changed

+1561
-115
lines changed

src/compiler/checker.ts

+64-107
Large diffs are not rendered by default.

src/compiler/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2871,7 +2871,7 @@ namespace ts {
28712871
/* @internal */ getExportsAndPropertiesOfModule(moduleSymbol: Symbol): Symbol[];
28722872

28732873
getAllAttributesTypeFromJsxOpeningLikeElement(elementNode: JsxOpeningLikeElement): Type | undefined;
2874-
getJsxIntrinsicTagNames(): Symbol[];
2874+
getJsxIntrinsicTagNamesAt(location: Node): Symbol[];
28752875
isOptionalParameter(node: ParameterDeclaration): boolean;
28762876
getAmbientModules(): Symbol[];
28772877

src/services/completions.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -943,7 +943,7 @@ namespace ts.Completions {
943943
getTypeScriptMemberSymbols();
944944
}
945945
else if (isRightOfOpenTag) {
946-
const tagSymbols = Debug.assertEachDefined(typeChecker.getJsxIntrinsicTagNames(), "getJsxIntrinsicTagNames() should all be defined");
946+
const tagSymbols = Debug.assertEachDefined(typeChecker.getJsxIntrinsicTagNamesAt(location), "getJsxIntrinsicTagNames() should all be defined");
947947
if (tryGetGlobalSymbols()) {
948948
symbols = tagSymbols.concat(symbols.filter(s => !!(s.flags & (SymbolFlags.Value | SymbolFlags.Alias))));
949949
}

tests/baselines/reference/api/tsserverlibrary.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1811,7 +1811,7 @@ declare namespace ts {
18111811
getAliasedSymbol(symbol: Symbol): Symbol;
18121812
getExportsOfModule(moduleSymbol: Symbol): Symbol[];
18131813
getAllAttributesTypeFromJsxOpeningLikeElement(elementNode: JsxOpeningLikeElement): Type | undefined;
1814-
getJsxIntrinsicTagNames(): Symbol[];
1814+
getJsxIntrinsicTagNamesAt(location: Node): Symbol[];
18151815
isOptionalParameter(node: ParameterDeclaration): boolean;
18161816
getAmbientModules(): Symbol[];
18171817
tryGetMemberInModuleExports(memberName: string, moduleSymbol: Symbol): Symbol | undefined;

tests/baselines/reference/api/typescript.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1811,7 +1811,7 @@ declare namespace ts {
18111811
getAliasedSymbol(symbol: Symbol): Symbol;
18121812
getExportsOfModule(moduleSymbol: Symbol): Symbol[];
18131813
getAllAttributesTypeFromJsxOpeningLikeElement(elementNode: JsxOpeningLikeElement): Type | undefined;
1814-
getJsxIntrinsicTagNames(): Symbol[];
1814+
getJsxIntrinsicTagNamesAt(location: Node): Symbol[];
18151815
isOptionalParameter(node: ParameterDeclaration): boolean;
18161816
getAmbientModules(): Symbol[];
18171817
tryGetMemberInModuleExports(memberName: string, moduleSymbol: Symbol): Symbol | undefined;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
tests/cases/conformance/jsx/inline/index.tsx(5,1): error TS2322: Type 'dom.JSX.Element' is not assignable to type 'predom.JSX.Element'.
2+
Property '__predomBrand' is missing in type 'Element'.
3+
tests/cases/conformance/jsx/inline/index.tsx(21,21): error TS2605: JSX element type 'Element' is not a constructor function for JSX elements.
4+
Property 'render' is missing in type 'Element'.
5+
tests/cases/conformance/jsx/inline/index.tsx(21,28): error TS2322: Type '{ children: Element[]; x: number; y: number; }' is not assignable to type '{ children?: Element[]; }'.
6+
Types of property 'children' are incompatible.
7+
Type 'dom.JSX.Element[]' is not assignable to type 'predom.JSX.Element[]'.
8+
Type 'dom.JSX.Element' is not assignable to type 'predom.JSX.Element'.
9+
tests/cases/conformance/jsx/inline/index.tsx(21,40): error TS2605: JSX element type 'MyClass' is not a constructor function for JSX elements.
10+
tests/cases/conformance/jsx/inline/index.tsx(21,40): error TS2605: JSX element type 'MyClass' is not a constructor function for JSX elements.
11+
Property '__domBrand' is missing in type 'MyClass'.
12+
tests/cases/conformance/jsx/inline/index.tsx(21,63): error TS2605: JSX element type 'MyClass' is not a constructor function for JSX elements.
13+
tests/cases/conformance/jsx/inline/index.tsx(24,30): error TS2322: Type '{ children: Element[]; x: number; y: number; }' is not assignable to type '{ x: number; y: number; children?: Element[]; }'.
14+
Types of property 'children' are incompatible.
15+
Type 'predom.JSX.Element[]' is not assignable to type 'dom.JSX.Element[]'.
16+
Type 'predom.JSX.Element' is not assignable to type 'dom.JSX.Element'.
17+
Property '__domBrand' is missing in type 'Element'.
18+
19+
20+
==== tests/cases/conformance/jsx/inline/renderer.d.ts (0 errors) ====
21+
export namespace dom {
22+
namespace JSX {
23+
interface IntrinsicElements {
24+
[e: string]: {};
25+
}
26+
interface Element {
27+
__domBrand: void;
28+
props: {
29+
children?: Element[];
30+
};
31+
}
32+
interface ElementClass extends Element {
33+
render(): Element;
34+
}
35+
interface ElementAttributesProperty { props: any; }
36+
interface ElementChildrenAttribute { children: any; }
37+
}
38+
}
39+
export function dom(): dom.JSX.Element;
40+
==== tests/cases/conformance/jsx/inline/renderer2.d.ts (0 errors) ====
41+
export namespace predom {
42+
namespace JSX {
43+
interface IntrinsicElements {
44+
[e: string]: {};
45+
}
46+
interface Element {
47+
__predomBrand: void;
48+
props: {
49+
children?: Element[];
50+
};
51+
}
52+
interface ElementClass extends Element {
53+
render(): Element;
54+
}
55+
interface ElementAttributesProperty { props: any; }
56+
interface ElementChildrenAttribute { children: any; }
57+
}
58+
}
59+
export function predom(): predom.JSX.Element;
60+
==== tests/cases/conformance/jsx/inline/component.tsx (0 errors) ====
61+
/** @jsx predom */
62+
import { predom } from "./renderer2"
63+
64+
export const MySFC = (props: {x: number, y: number, children?: predom.JSX.Element[]}) => <p>{props.x} + {props.y} = {props.x + props.y}{...this.props.children}</p>;
65+
66+
export class MyClass implements predom.JSX.Element {
67+
__predomBrand!: void;
68+
constructor(public props: {x: number, y: number, children?: predom.JSX.Element[]}) {}
69+
render() {
70+
return <p>
71+
{this.props.x} + {this.props.y} = {this.props.x + this.props.y}
72+
{...this.props.children}
73+
</p>;
74+
}
75+
}
76+
export const tree = <MySFC x={1} y={2}><MyClass x={3} y={4} /><MyClass x={5} y={6} /></MySFC>
77+
78+
export default <h></h>
79+
80+
==== tests/cases/conformance/jsx/inline/index.tsx (7 errors) ====
81+
/** @jsx dom */
82+
import { dom } from "./renderer"
83+
import prerendered, {MySFC, MyClass, tree} from "./component";
84+
let elem = prerendered;
85+
elem = <h></h>; // Expect assignability error here
86+
~~~~
87+
!!! error TS2322: Type 'dom.JSX.Element' is not assignable to type 'predom.JSX.Element'.
88+
!!! error TS2322: Property '__predomBrand' is missing in type 'Element'.
89+
90+
const DOMSFC = (props: {x: number, y: number, children?: dom.JSX.Element[]}) => <p>{props.x} + {props.y} = {props.x + props.y}{props.children}</p>;
91+
92+
class DOMClass implements dom.JSX.Element {
93+
__domBrand!: void;
94+
constructor(public props: {x: number, y: number, children?: dom.JSX.Element[]}) {}
95+
render() {
96+
return <p>{this.props.x} + {this.props.y} = {this.props.x + this.props.y}{...this.props.children}</p>;
97+
}
98+
}
99+
100+
// Should work, everything is a DOM element
101+
const _tree = <DOMSFC x={1} y={2}><DOMClass x={3} y={4} /><DOMClass x={5} y={6} /></DOMSFC>
102+
103+
// Should fail, no dom elements
104+
const _brokenTree = <MySFC x={1} y={2}><MyClass x={3} y={4} /><MyClass x={5} y={6} /></MySFC>
105+
~~~~~~~~~~~~~~~~~~~
106+
!!! error TS2605: JSX element type 'Element' is not a constructor function for JSX elements.
107+
!!! error TS2605: Property 'render' is missing in type 'Element'.
108+
~~~~~~~~~~~
109+
!!! error TS2322: Type '{ children: Element[]; x: number; y: number; }' is not assignable to type '{ children?: Element[]; }'.
110+
!!! error TS2322: Types of property 'children' are incompatible.
111+
!!! error TS2322: Type 'dom.JSX.Element[]' is not assignable to type 'predom.JSX.Element[]'.
112+
!!! error TS2322: Type 'dom.JSX.Element' is not assignable to type 'predom.JSX.Element'.
113+
~~~~~~~~~~~~~~~~~~~~~~~
114+
!!! error TS2605: JSX element type 'MyClass' is not a constructor function for JSX elements.
115+
~~~~~~~~~~~~~~~~~~~~~~~
116+
!!! error TS2605: JSX element type 'MyClass' is not a constructor function for JSX elements.
117+
!!! error TS2605: Property '__domBrand' is missing in type 'MyClass'.
118+
~~~~~~~~~~~~~~~~~~~~~~~
119+
!!! error TS2605: JSX element type 'MyClass' is not a constructor function for JSX elements.
120+
121+
// Should fail, nondom isn't allowed as children of dom
122+
const _brokenTree2 = <DOMSFC x={1} y={2}>{tree}{tree}</DOMSFC>
123+
~~~~~~~~~~~
124+
!!! error TS2322: Type '{ children: Element[]; x: number; y: number; }' is not assignable to type '{ x: number; y: number; children?: Element[]; }'.
125+
!!! error TS2322: Types of property 'children' are incompatible.
126+
!!! error TS2322: Type 'predom.JSX.Element[]' is not assignable to type 'dom.JSX.Element[]'.
127+
!!! error TS2322: Type 'predom.JSX.Element' is not assignable to type 'dom.JSX.Element'.
128+
!!! error TS2322: Property '__domBrand' is missing in type 'Element'.
129+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
//// [tests/cases/conformance/jsx/inline/inlineJsxFactoryDeclarationsLocalTypes.tsx] ////
2+
3+
//// [renderer.d.ts]
4+
export namespace dom {
5+
namespace JSX {
6+
interface IntrinsicElements {
7+
[e: string]: {};
8+
}
9+
interface Element {
10+
__domBrand: void;
11+
props: {
12+
children?: Element[];
13+
};
14+
}
15+
interface ElementClass extends Element {
16+
render(): Element;
17+
}
18+
interface ElementAttributesProperty { props: any; }
19+
interface ElementChildrenAttribute { children: any; }
20+
}
21+
}
22+
export function dom(): dom.JSX.Element;
23+
//// [renderer2.d.ts]
24+
export namespace predom {
25+
namespace JSX {
26+
interface IntrinsicElements {
27+
[e: string]: {};
28+
}
29+
interface Element {
30+
__predomBrand: void;
31+
props: {
32+
children?: Element[];
33+
};
34+
}
35+
interface ElementClass extends Element {
36+
render(): Element;
37+
}
38+
interface ElementAttributesProperty { props: any; }
39+
interface ElementChildrenAttribute { children: any; }
40+
}
41+
}
42+
export function predom(): predom.JSX.Element;
43+
//// [component.tsx]
44+
/** @jsx predom */
45+
import { predom } from "./renderer2"
46+
47+
export const MySFC = (props: {x: number, y: number, children?: predom.JSX.Element[]}) => <p>{props.x} + {props.y} = {props.x + props.y}{...this.props.children}</p>;
48+
49+
export class MyClass implements predom.JSX.Element {
50+
__predomBrand!: void;
51+
constructor(public props: {x: number, y: number, children?: predom.JSX.Element[]}) {}
52+
render() {
53+
return <p>
54+
{this.props.x} + {this.props.y} = {this.props.x + this.props.y}
55+
{...this.props.children}
56+
</p>;
57+
}
58+
}
59+
export const tree = <MySFC x={1} y={2}><MyClass x={3} y={4} /><MyClass x={5} y={6} /></MySFC>
60+
61+
export default <h></h>
62+
63+
//// [index.tsx]
64+
/** @jsx dom */
65+
import { dom } from "./renderer"
66+
import prerendered, {MySFC, MyClass, tree} from "./component";
67+
let elem = prerendered;
68+
elem = <h></h>; // Expect assignability error here
69+
70+
const DOMSFC = (props: {x: number, y: number, children?: dom.JSX.Element[]}) => <p>{props.x} + {props.y} = {props.x + props.y}{props.children}</p>;
71+
72+
class DOMClass implements dom.JSX.Element {
73+
__domBrand!: void;
74+
constructor(public props: {x: number, y: number, children?: dom.JSX.Element[]}) {}
75+
render() {
76+
return <p>{this.props.x} + {this.props.y} = {this.props.x + this.props.y}{...this.props.children}</p>;
77+
}
78+
}
79+
80+
// Should work, everything is a DOM element
81+
const _tree = <DOMSFC x={1} y={2}><DOMClass x={3} y={4} /><DOMClass x={5} y={6} /></DOMSFC>
82+
83+
// Should fail, no dom elements
84+
const _brokenTree = <MySFC x={1} y={2}><MyClass x={3} y={4} /><MyClass x={5} y={6} /></MySFC>
85+
86+
// Should fail, nondom isn't allowed as children of dom
87+
const _brokenTree2 = <DOMSFC x={1} y={2}>{tree}{tree}</DOMSFC>
88+
89+
90+
//// [component.js]
91+
"use strict";
92+
var _this = this;
93+
exports.__esModule = true;
94+
/** @jsx predom */
95+
var renderer2_1 = require("./renderer2");
96+
exports.MySFC = function (props) { return renderer2_1.predom("p", null,
97+
props.x,
98+
" + ",
99+
props.y,
100+
" = ",
101+
props.x + props.y,
102+
_this.props.children); };
103+
var MyClass = /** @class */ (function () {
104+
function MyClass(props) {
105+
this.props = props;
106+
}
107+
MyClass.prototype.render = function () {
108+
return renderer2_1.predom("p", null,
109+
this.props.x,
110+
" + ",
111+
this.props.y,
112+
" = ",
113+
this.props.x + this.props.y,
114+
this.props.children);
115+
};
116+
return MyClass;
117+
}());
118+
exports.MyClass = MyClass;
119+
exports.tree = renderer2_1.predom(exports.MySFC, { x: 1, y: 2 },
120+
renderer2_1.predom(MyClass, { x: 3, y: 4 }),
121+
renderer2_1.predom(MyClass, { x: 5, y: 6 }));
122+
exports["default"] = renderer2_1.predom("h", null);
123+
//// [index.js]
124+
"use strict";
125+
exports.__esModule = true;
126+
/** @jsx dom */
127+
var renderer_1 = require("./renderer");
128+
var component_1 = require("./component");
129+
var elem = component_1["default"];
130+
elem = renderer_1.dom("h", null); // Expect assignability error here
131+
var DOMSFC = function (props) { return renderer_1.dom("p", null,
132+
props.x,
133+
" + ",
134+
props.y,
135+
" = ",
136+
props.x + props.y,
137+
props.children); };
138+
var DOMClass = /** @class */ (function () {
139+
function DOMClass(props) {
140+
this.props = props;
141+
}
142+
DOMClass.prototype.render = function () {
143+
return renderer_1.dom("p", null,
144+
this.props.x,
145+
" + ",
146+
this.props.y,
147+
" = ",
148+
this.props.x + this.props.y,
149+
this.props.children);
150+
};
151+
return DOMClass;
152+
}());
153+
// Should work, everything is a DOM element
154+
var _tree = renderer_1.dom(DOMSFC, { x: 1, y: 2 },
155+
renderer_1.dom(DOMClass, { x: 3, y: 4 }),
156+
renderer_1.dom(DOMClass, { x: 5, y: 6 }));
157+
// Should fail, no dom elements
158+
var _brokenTree = renderer_1.dom(component_1.MySFC, { x: 1, y: 2 },
159+
renderer_1.dom(component_1.MyClass, { x: 3, y: 4 }),
160+
renderer_1.dom(component_1.MyClass, { x: 5, y: 6 }));
161+
// Should fail, nondom isn't allowed as children of dom
162+
var _brokenTree2 = renderer_1.dom(DOMSFC, { x: 1, y: 2 },
163+
component_1.tree,
164+
component_1.tree);

0 commit comments

Comments
 (0)