Fix 8549: Using variable as Jsx tagname (#9337)

* Parse JSXElement's name as property access instead of just entity name. So when one accesses property of the class through this, checker will check correctly

* wip - just resolve to any type for now

* Resolve string type to anytype and look up property in intrinsicElementsType of Jsx

* Add tests and update baselines

* Remove unneccessary comment

* wip-address PR

* Address PR

* Add tets and update baselines

* Fix linting error
This commit is contained in:
Yui
2016-06-24 14:15:44 -07:00
committed by GitHub
parent 2aa1d718ab
commit db0d8e094b
40 changed files with 836 additions and 24 deletions

View File

@@ -9657,8 +9657,9 @@ namespace ts {
/**
* Returns true iff React would emit this tag name as a string rather than an identifier or qualified name
*/
function isJsxIntrinsicIdentifier(tagName: Identifier | QualifiedName) {
if (tagName.kind === SyntaxKind.QualifiedName) {
function isJsxIntrinsicIdentifier(tagName: JsxTagNameExpression) {
// TODO (yuisu): comment
if (tagName.kind === SyntaxKind.PropertyAccessExpression || tagName.kind === SyntaxKind.ThisKeyword) {
return false;
}
else {
@@ -9854,6 +9855,29 @@ namespace ts {
}));
}
// 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 (elemType.flags & TypeFlags.String) {
return anyType;
}
else if (elemType.flags & TypeFlags.StringLiteral) {
// If the elemType is a stringLiteral type, we can then provide a check to make sure that the string literal type is one of the Jsx intrinsic element type
const intrinsicElementsType = getJsxType(JsxNames.IntrinsicElements);
if (intrinsicElementsType !== unknownType) {
const stringLiteralTypeName = (<StringLiteralType>elemType).text;
const intrinsicProp = getPropertyOfType(intrinsicElementsType, stringLiteralTypeName);
if (intrinsicProp) {
return getTypeOfSymbol(intrinsicProp);
}
const indexSignatureType = getIndexTypeOfType(intrinsicElementsType, IndexKind.String);
if (indexSignatureType) {
return indexSignatureType;
}
error(node, Diagnostics.Property_0_does_not_exist_on_type_1, stringLiteralTypeName, "JSX." + JsxNames.IntrinsicElements);
}
// If we need to report an error, we already done so here. So just return any to prevent any more error downstream
return anyType;
}
// Get the element instance type (the result of newing or invoking this tag)
const elemInstanceType = getJsxElementInstanceType(node, elemType);

View File

@@ -1219,7 +1219,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
function jsxEmitReact(node: JsxElement | JsxSelfClosingElement) {
/// Emit a tag name, which is either '"div"' for lower-cased names, or
/// 'Div' for upper-cased or dotted names
function emitTagName(name: Identifier | QualifiedName) {
function emitTagName(name: LeftHandSideExpression) {
if (name.kind === SyntaxKind.Identifier && isIntrinsicJsxName((<Identifier>name).text)) {
write('"');
emit(name);

View File

@@ -3576,7 +3576,7 @@ namespace ts {
return finishNode(node);
}
function tagNamesAreEquivalent(lhs: EntityName, rhs: EntityName): boolean {
function tagNamesAreEquivalent(lhs: JsxTagNameExpression, rhs: JsxTagNameExpression): boolean {
if (lhs.kind !== rhs.kind) {
return false;
}
@@ -3585,8 +3585,15 @@ namespace ts {
return (<Identifier>lhs).text === (<Identifier>rhs).text;
}
return (<QualifiedName>lhs).right.text === (<QualifiedName>rhs).right.text &&
tagNamesAreEquivalent((<QualifiedName>lhs).left, (<QualifiedName>rhs).left);
if (lhs.kind === SyntaxKind.ThisKeyword) {
return true;
}
// If we are at this statement then we must have PropertyAccessExpression and because tag name in Jsx element can only
// take forms of JsxTagNameExpression which includes an identifier, "this" expression, or another propertyAccessExpression
// it is safe to case the expression property as such. See parseJsxElementName for how we parse tag name in Jsx element
return (<PropertyAccessExpression>lhs).name.text === (<PropertyAccessExpression>rhs).name.text &&
tagNamesAreEquivalent((<PropertyAccessExpression>lhs).expression as JsxTagNameExpression, (<PropertyAccessExpression>rhs).expression as JsxTagNameExpression);
}
@@ -3654,7 +3661,7 @@ namespace ts {
Debug.fail("Unknown JSX child kind " + token);
}
function parseJsxChildren(openingTagName: EntityName): NodeArray<JsxChild> {
function parseJsxChildren(openingTagName: LeftHandSideExpression): NodeArray<JsxChild> {
const result = <NodeArray<JsxChild>>[];
result.pos = scanner.getStartPos();
const saveParsingContext = parsingContext;
@@ -3717,17 +3724,22 @@ namespace ts {
return finishNode(node);
}
function parseJsxElementName(): EntityName {
function parseJsxElementName(): JsxTagNameExpression {
scanJsxIdentifier();
let elementName: EntityName = parseIdentifierName();
// JsxElement can have name in the form of
// propertyAccessExpression
// primaryExpression in the form of an identifier and "this" keyword
// We can't just simply use parseLeftHandSideExpressionOrHigher because then we will start consider class,function etc as a keyword
// We only want to consider "this" as a primaryExpression
let expression: JsxTagNameExpression = token === SyntaxKind.ThisKeyword ?
parseTokenNode<PrimaryExpression>() : parseIdentifierName();
while (parseOptional(SyntaxKind.DotToken)) {
scanJsxIdentifier();
const node: QualifiedName = <QualifiedName>createNode(SyntaxKind.QualifiedName, elementName.pos); // !!!
node.left = elementName;
node.right = parseIdentifierName();
elementName = finishNode(node);
const propertyAccess: PropertyAccessExpression = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos);
propertyAccess.expression = expression;
propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true);
expression = finishNode(propertyAccess);
}
return elementName;
return expression;
}
function parseJsxExpression(inExpressionContext: boolean): JsxExpression {

View File

@@ -1042,11 +1042,13 @@ namespace ts {
closingElement: JsxClosingElement;
}
export type JsxTagNameExpression = PrimaryExpression | PropertyAccessExpression;
/// The opening element of a <Tag>...</Tag> JsxElement
// @kind(SyntaxKind.JsxOpeningElement)
export interface JsxOpeningElement extends Expression {
_openingElementBrand?: any;
tagName: EntityName;
tagName: JsxTagNameExpression;
attributes: NodeArray<JsxAttribute | JsxSpreadAttribute>;
}
@@ -1073,7 +1075,7 @@ namespace ts {
// @kind(SyntaxKind.JsxClosingElement)
export interface JsxClosingElement extends Node {
tagName: EntityName;
tagName: JsxTagNameExpression;
}
// @kind(SyntaxKind.JsxExpression)

View File

@@ -0,0 +1,8 @@
//// [tsxDynamicTagName1.tsx]
var CustomTag = "h1";
<CustomTag> Hello World </CustomTag> // No error
//// [tsxDynamicTagName1.jsx]
var CustomTag = "h1";
<CustomTag> Hello World </CustomTag>; // No error

View File

@@ -0,0 +1,9 @@
=== tests/cases/conformance/jsx/tsxDynamicTagName1.tsx ===
var CustomTag = "h1";
>CustomTag : Symbol(CustomTag, Decl(tsxDynamicTagName1.tsx, 1, 3))
<CustomTag> Hello World </CustomTag> // No error
>CustomTag : Symbol(CustomTag, Decl(tsxDynamicTagName1.tsx, 1, 3))
>CustomTag : Symbol(CustomTag, Decl(tsxDynamicTagName1.tsx, 1, 3))

View File

@@ -0,0 +1,11 @@
=== tests/cases/conformance/jsx/tsxDynamicTagName1.tsx ===
var CustomTag = "h1";
>CustomTag : string
>"h1" : string
<CustomTag> Hello World </CustomTag> // No error
><CustomTag> Hello World </CustomTag> : any
>CustomTag : string
>CustomTag : string

View File

@@ -0,0 +1,19 @@
tests/cases/conformance/jsx/tsxDynamicTagName2.tsx(10,1): error TS2339: Property 'customTag' does not exist on type 'JSX.IntrinsicElements'.
tests/cases/conformance/jsx/tsxDynamicTagName2.tsx(10,25): error TS2339: Property 'customTag' does not exist on type 'JSX.IntrinsicElements'.
==== tests/cases/conformance/jsx/tsxDynamicTagName2.tsx (2 errors) ====
declare module JSX {
interface Element { }
interface IntrinsicElements {
div: any
}
}
var customTag = "h1";
<customTag> Hello World </customTag> // This should be an error. The lower-case is look up as an intrinsic element name
~~~~~~~~~~~
!!! error TS2339: Property 'customTag' does not exist on type 'JSX.IntrinsicElements'.
~~~~~~~~~~~~
!!! error TS2339: Property 'customTag' does not exist on type 'JSX.IntrinsicElements'.

View File

@@ -0,0 +1,15 @@
//// [tsxDynamicTagName2.tsx]
declare module JSX {
interface Element { }
interface IntrinsicElements {
div: any
}
}
var customTag = "h1";
<customTag> Hello World </customTag> // This should be an error. The lower-case is look up as an intrinsic element name
//// [tsxDynamicTagName2.jsx]
var customTag = "h1";
<customTag> Hello World </customTag>; // This should be an error. The lower-case is look up as an intrinsic element name

View File

@@ -0,0 +1,16 @@
tests/cases/conformance/jsx/tsxDynamicTagName3.tsx(10,1): error TS2339: Property 'h1' does not exist on type 'JSX.IntrinsicElements'.
==== tests/cases/conformance/jsx/tsxDynamicTagName3.tsx (1 errors) ====
declare module JSX {
interface Element { }
interface IntrinsicElements {
div: any
}
}
var CustomTag: "h1" = "h1";
<CustomTag> Hello World </CustomTag> // This should be an error. we will try look up string literal type in JSX.IntrinsicElements
~~~~~~~~~~~
!!! error TS2339: Property 'h1' does not exist on type 'JSX.IntrinsicElements'.

View File

@@ -0,0 +1,15 @@
//// [tsxDynamicTagName3.tsx]
declare module JSX {
interface Element { }
interface IntrinsicElements {
div: any
}
}
var CustomTag: "h1" = "h1";
<CustomTag> Hello World </CustomTag> // This should be an error. we will try look up string literal type in JSX.IntrinsicElements
//// [tsxDynamicTagName3.jsx]
var CustomTag = "h1";
<CustomTag> Hello World </CustomTag>; // This should be an error. we will try look up string literal type in JSX.IntrinsicElements

View File

@@ -0,0 +1,16 @@
//// [tsxDynamicTagName4.tsx]
declare module JSX {
interface Element { }
interface IntrinsicElements {
div: any
h1: any
}
}
var CustomTag: "h1" = "h1";
<CustomTag> Hello World </CustomTag>
//// [tsxDynamicTagName4.jsx]
var CustomTag = "h1";
<CustomTag> Hello World </CustomTag>;

View File

@@ -0,0 +1,26 @@
=== tests/cases/conformance/jsx/tsxDynamicTagName4.tsx ===
declare module JSX {
>JSX : Symbol(JSX, Decl(tsxDynamicTagName4.tsx, 0, 0))
interface Element { }
>Element : Symbol(Element, Decl(tsxDynamicTagName4.tsx, 1, 20))
interface IntrinsicElements {
>IntrinsicElements : Symbol(IntrinsicElements, Decl(tsxDynamicTagName4.tsx, 2, 22))
div: any
>div : Symbol(IntrinsicElements.div, Decl(tsxDynamicTagName4.tsx, 3, 30))
h1: any
>h1 : Symbol(IntrinsicElements.h1, Decl(tsxDynamicTagName4.tsx, 4, 10))
}
}
var CustomTag: "h1" = "h1";
>CustomTag : Symbol(CustomTag, Decl(tsxDynamicTagName4.tsx, 9, 3))
<CustomTag> Hello World </CustomTag>
>CustomTag : Symbol(CustomTag, Decl(tsxDynamicTagName4.tsx, 9, 3))
>CustomTag : Symbol(CustomTag, Decl(tsxDynamicTagName4.tsx, 9, 3))

View File

@@ -0,0 +1,28 @@
=== tests/cases/conformance/jsx/tsxDynamicTagName4.tsx ===
declare module JSX {
>JSX : any
interface Element { }
>Element : Element
interface IntrinsicElements {
>IntrinsicElements : IntrinsicElements
div: any
>div : any
h1: any
>h1 : any
}
}
var CustomTag: "h1" = "h1";
>CustomTag : "h1"
>"h1" : "h1"
<CustomTag> Hello World </CustomTag>
><CustomTag> Hello World </CustomTag> : JSX.Element
>CustomTag : "h1"
>CustomTag : "h1"

View File

@@ -0,0 +1,41 @@
//// [tests/cases/conformance/jsx/tsxDynamicTagName5.tsx] ////
//// [react.d.ts]
declare module 'react' {
class Component<T, U> { }
}
//// [app.tsx]
import * as React from 'react';
export class Text extends React.Component<{}, {}> {
_tagName: string = 'div';
render() {
return (
<this._tagName />
);
}
}
//// [app.jsx]
"use strict";
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var React = require('react');
var Text = (function (_super) {
__extends(Text, _super);
function Text() {
_super.apply(this, arguments);
this._tagName = 'div';
}
Text.prototype.render = function () {
return (<this._tagName />);
};
return Text;
}(React.Component));
exports.Text = Text;

View File

@@ -0,0 +1,34 @@
=== tests/cases/conformance/jsx/react.d.ts ===
declare module 'react' {
class Component<T, U> { }
>Component : Symbol(Component, Decl(react.d.ts, 1, 24))
>T : Symbol(T, Decl(react.d.ts, 2, 17))
>U : Symbol(U, Decl(react.d.ts, 2, 19))
}
=== tests/cases/conformance/jsx/app.tsx ===
import * as React from 'react';
>React : Symbol(React, Decl(app.tsx, 0, 6))
export class Text extends React.Component<{}, {}> {
>Text : Symbol(Text, Decl(app.tsx, 0, 31))
>React.Component : Symbol(React.Component, Decl(react.d.ts, 1, 24))
>React : Symbol(React, Decl(app.tsx, 0, 6))
>Component : Symbol(React.Component, Decl(react.d.ts, 1, 24))
_tagName: string = 'div';
>_tagName : Symbol(Text._tagName, Decl(app.tsx, 2, 51))
render() {
>render : Symbol(Text.render, Decl(app.tsx, 3, 27))
return (
<this._tagName />
>this._tagName : Symbol(Text._tagName, Decl(app.tsx, 2, 51))
>this : Symbol(Text, Decl(app.tsx, 0, 31))
>_tagName : Symbol(Text._tagName, Decl(app.tsx, 2, 51))
);
}
}

View File

@@ -0,0 +1,38 @@
=== tests/cases/conformance/jsx/react.d.ts ===
declare module 'react' {
class Component<T, U> { }
>Component : Component<T, U>
>T : T
>U : U
}
=== tests/cases/conformance/jsx/app.tsx ===
import * as React from 'react';
>React : typeof React
export class Text extends React.Component<{}, {}> {
>Text : Text
>React.Component : React.Component<{}, {}>
>React : typeof React
>Component : typeof React.Component
_tagName: string = 'div';
>_tagName : string
>'div' : string
render() {
>render : () => any
return (
>( <this._tagName /> ) : any
<this._tagName />
><this._tagName /> : any
>this._tagName : string
>this : this
>_tagName : string
);
}
}

View File

@@ -0,0 +1,15 @@
//// [tsxDynamicTagName6.tsx]
declare module JSX {
interface Element { }
interface IntrinsicElements {
div: any
}
}
const t = {tag:'h1'}
const foo = <t.tag/> // No error
//// [tsxDynamicTagName6.jsx]
var t = { tag: 'h1' };
var foo = <t.tag />; // No error

View File

@@ -0,0 +1,26 @@
=== tests/cases/conformance/jsx/tsxDynamicTagName6.tsx ===
declare module JSX {
>JSX : Symbol(JSX, Decl(tsxDynamicTagName6.tsx, 0, 0))
interface Element { }
>Element : Symbol(Element, Decl(tsxDynamicTagName6.tsx, 1, 20))
interface IntrinsicElements {
>IntrinsicElements : Symbol(IntrinsicElements, Decl(tsxDynamicTagName6.tsx, 2, 22))
div: any
>div : Symbol(IntrinsicElements.div, Decl(tsxDynamicTagName6.tsx, 3, 30))
}
}
const t = {tag:'h1'}
>t : Symbol(t, Decl(tsxDynamicTagName6.tsx, 8, 5))
>tag : Symbol(tag, Decl(tsxDynamicTagName6.tsx, 8, 11))
const foo = <t.tag/> // No error
>foo : Symbol(foo, Decl(tsxDynamicTagName6.tsx, 9, 5))
>t.tag : Symbol(tag, Decl(tsxDynamicTagName6.tsx, 8, 11))
>t : Symbol(t, Decl(tsxDynamicTagName6.tsx, 8, 5))
>tag : Symbol(tag, Decl(tsxDynamicTagName6.tsx, 8, 11))

View File

@@ -0,0 +1,29 @@
=== tests/cases/conformance/jsx/tsxDynamicTagName6.tsx ===
declare module JSX {
>JSX : any
interface Element { }
>Element : Element
interface IntrinsicElements {
>IntrinsicElements : IntrinsicElements
div: any
>div : any
}
}
const t = {tag:'h1'}
>t : { tag: string; }
>{tag:'h1'} : { tag: string; }
>tag : string
>'h1' : string
const foo = <t.tag/> // No error
>foo : JSX.Element
><t.tag/> : JSX.Element
>t.tag : string
>t : { tag: string; }
>tag : string

View File

@@ -0,0 +1,23 @@
tests/cases/conformance/jsx/app.tsx(8,8): error TS2604: JSX element type 'this' does not have any construct or call signatures.
==== tests/cases/conformance/jsx/react.d.ts (0 errors) ====
declare module 'react' {
class Component<T, U> { }
}
==== tests/cases/conformance/jsx/app.tsx (1 errors) ====
import * as React from 'react';
export class Text extends React.Component<{}, {}> {
_tagName: string = 'div';
render() {
return (
<this/> // this should be an error
~~~~
!!! error TS2604: JSX element type 'this' does not have any construct or call signatures.
);
}
}

View File

@@ -0,0 +1,42 @@
//// [tests/cases/conformance/jsx/tsxDynamicTagName7.tsx] ////
//// [react.d.ts]
declare module 'react' {
class Component<T, U> { }
}
//// [app.tsx]
import * as React from 'react';
export class Text extends React.Component<{}, {}> {
_tagName: string = 'div';
render() {
return (
<this/> // this should be an error
);
}
}
//// [app.jsx]
"use strict";
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var React = require('react');
var Text = (function (_super) {
__extends(Text, _super);
function Text() {
_super.apply(this, arguments);
this._tagName = 'div';
}
Text.prototype.render = function () {
return (<this /> // this should be an error
);
};
return Text;
}(React.Component));
exports.Text = Text;

View File

@@ -0,0 +1,41 @@
//// [tests/cases/conformance/jsx/tsxDynamicTagName8.tsx] ////
//// [react.d.ts]
declare module 'react' {
class Component<T, U> { }
}
//// [app.tsx]
import * as React from 'react';
export class Text extends React.Component<{}, {}> {
_tagName: string = 'div';
render() {
return (
<this._tagName> Hello world </this._tagName>
);
}
}
//// [app.jsx]
"use strict";
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var React = require('react');
var Text = (function (_super) {
__extends(Text, _super);
function Text() {
_super.apply(this, arguments);
this._tagName = 'div';
}
Text.prototype.render = function () {
return (<this._tagName> Hello world </this._tagName>);
};
return Text;
}(React.Component));
exports.Text = Text;

View File

@@ -0,0 +1,37 @@
=== tests/cases/conformance/jsx/react.d.ts ===
declare module 'react' {
class Component<T, U> { }
>Component : Symbol(Component, Decl(react.d.ts, 1, 24))
>T : Symbol(T, Decl(react.d.ts, 2, 17))
>U : Symbol(U, Decl(react.d.ts, 2, 19))
}
=== tests/cases/conformance/jsx/app.tsx ===
import * as React from 'react';
>React : Symbol(React, Decl(app.tsx, 0, 6))
export class Text extends React.Component<{}, {}> {
>Text : Symbol(Text, Decl(app.tsx, 0, 31))
>React.Component : Symbol(React.Component, Decl(react.d.ts, 1, 24))
>React : Symbol(React, Decl(app.tsx, 0, 6))
>Component : Symbol(React.Component, Decl(react.d.ts, 1, 24))
_tagName: string = 'div';
>_tagName : Symbol(Text._tagName, Decl(app.tsx, 2, 51))
render() {
>render : Symbol(Text.render, Decl(app.tsx, 3, 27))
return (
<this._tagName> Hello world </this._tagName>
>this._tagName : Symbol(Text._tagName, Decl(app.tsx, 2, 51))
>this : Symbol(Text, Decl(app.tsx, 0, 31))
>_tagName : Symbol(Text._tagName, Decl(app.tsx, 2, 51))
>this._tagName : Symbol(Text._tagName, Decl(app.tsx, 2, 51))
>this : Symbol(Text, Decl(app.tsx, 0, 31))
>_tagName : Symbol(Text._tagName, Decl(app.tsx, 2, 51))
);
}
}

View File

@@ -0,0 +1,41 @@
=== tests/cases/conformance/jsx/react.d.ts ===
declare module 'react' {
class Component<T, U> { }
>Component : Component<T, U>
>T : T
>U : U
}
=== tests/cases/conformance/jsx/app.tsx ===
import * as React from 'react';
>React : typeof React
export class Text extends React.Component<{}, {}> {
>Text : Text
>React.Component : React.Component<{}, {}>
>React : typeof React
>Component : typeof React.Component
_tagName: string = 'div';
>_tagName : string
>'div' : string
render() {
>render : () => any
return (
>( <this._tagName> Hello world </this._tagName> ) : any
<this._tagName> Hello world </this._tagName>
><this._tagName> Hello world </this._tagName> : any
>this._tagName : string
>this : this
>_tagName : string
>this._tagName : string
>this : this
>_tagName : string
);
}
}

View File

@@ -0,0 +1,41 @@
//// [tests/cases/conformance/jsx/tsxDynamicTagName9.tsx] ////
//// [react.d.ts]
declare module 'react' {
class Component<T, U> { }
}
//// [app.tsx]
import * as React from 'react';
export class Text extends React.Component<{}, {}> {
_tagName: "div" = 'div';
render() {
return (
<this._tagName> Hello world </this._tagName>
);
}
}
//// [app.jsx]
"use strict";
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var React = require('react');
var Text = (function (_super) {
__extends(Text, _super);
function Text() {
_super.apply(this, arguments);
this._tagName = 'div';
}
Text.prototype.render = function () {
return (<this._tagName> Hello world </this._tagName>);
};
return Text;
}(React.Component));
exports.Text = Text;

View File

@@ -0,0 +1,37 @@
=== tests/cases/conformance/jsx/react.d.ts ===
declare module 'react' {
class Component<T, U> { }
>Component : Symbol(Component, Decl(react.d.ts, 1, 24))
>T : Symbol(T, Decl(react.d.ts, 2, 17))
>U : Symbol(U, Decl(react.d.ts, 2, 19))
}
=== tests/cases/conformance/jsx/app.tsx ===
import * as React from 'react';
>React : Symbol(React, Decl(app.tsx, 0, 6))
export class Text extends React.Component<{}, {}> {
>Text : Symbol(Text, Decl(app.tsx, 0, 31))
>React.Component : Symbol(React.Component, Decl(react.d.ts, 1, 24))
>React : Symbol(React, Decl(app.tsx, 0, 6))
>Component : Symbol(React.Component, Decl(react.d.ts, 1, 24))
_tagName: "div" = 'div';
>_tagName : Symbol(Text._tagName, Decl(app.tsx, 2, 51))
render() {
>render : Symbol(Text.render, Decl(app.tsx, 3, 26))
return (
<this._tagName> Hello world </this._tagName>
>this._tagName : Symbol(Text._tagName, Decl(app.tsx, 2, 51))
>this : Symbol(Text, Decl(app.tsx, 0, 31))
>_tagName : Symbol(Text._tagName, Decl(app.tsx, 2, 51))
>this._tagName : Symbol(Text._tagName, Decl(app.tsx, 2, 51))
>this : Symbol(Text, Decl(app.tsx, 0, 31))
>_tagName : Symbol(Text._tagName, Decl(app.tsx, 2, 51))
);
}
}

View File

@@ -0,0 +1,41 @@
=== tests/cases/conformance/jsx/react.d.ts ===
declare module 'react' {
class Component<T, U> { }
>Component : Component<T, U>
>T : T
>U : U
}
=== tests/cases/conformance/jsx/app.tsx ===
import * as React from 'react';
>React : typeof React
export class Text extends React.Component<{}, {}> {
>Text : Text
>React.Component : React.Component<{}, {}>
>React : typeof React
>Component : typeof React.Component
_tagName: "div" = 'div';
>_tagName : "div"
>'div' : "div"
render() {
>render : () => any
return (
>( <this._tagName> Hello world </this._tagName> ) : any
<this._tagName> Hello world </this._tagName>
><this._tagName> Hello world </this._tagName> : any
>this._tagName : "div"
>this : this
>_tagName : "div"
>this._tagName : "div"
>this : this
>_tagName : "div"
);
}
}

View File

@@ -5,9 +5,9 @@ tests/cases/conformance/jsx/file.tsx(8,2): error TS2604: JSX element type 'X' do
import React = require('react');
type Invalid1 = React.ComponentClass<any> | string;
type Invalid1 = React.ComponentClass<any> | number;
const X: Invalid1 = "Should fail to construct";
const X: Invalid1 = 1;
<X />;
~

View File

@@ -2,9 +2,9 @@
import React = require('react');
type Invalid1 = React.ComponentClass<any> | string;
type Invalid1 = React.ComponentClass<any> | number;
const X: Invalid1 = "Should fail to construct";
const X: Invalid1 = 1;
<X />;
@@ -14,5 +14,5 @@ const X: Invalid1 = "Should fail to construct";
//// [file.js]
"use strict";
var React = require('react');
var X = "Should fail to construct";
var X = 1;
React.createElement(X, null);

View File

@@ -0,0 +1,4 @@
// @jsx: preserve
var CustomTag = "h1";
<CustomTag> Hello World </CustomTag> // No error

View File

@@ -0,0 +1,11 @@
// @jsx: preserve
declare module JSX {
interface Element { }
interface IntrinsicElements {
div: any
}
}
var customTag = "h1";
<customTag> Hello World </customTag> // This should be an error. The lower-case is look up as an intrinsic element name

View File

@@ -0,0 +1,11 @@
// @jsx: preserve
declare module JSX {
interface Element { }
interface IntrinsicElements {
div: any
}
}
var CustomTag: "h1" = "h1";
<CustomTag> Hello World </CustomTag> // This should be an error. we will try look up string literal type in JSX.IntrinsicElements

View File

@@ -0,0 +1,12 @@
// @jsx: preserve
declare module JSX {
interface Element { }
interface IntrinsicElements {
div: any
h1: any
}
}
var CustomTag: "h1" = "h1";
<CustomTag> Hello World </CustomTag>

View File

@@ -0,0 +1,19 @@
// @jsx: preserve
//@filename: react.d.ts
declare module 'react' {
class Component<T, U> { }
}
//@filename: app.tsx
import * as React from 'react';
export class Text extends React.Component<{}, {}> {
_tagName: string = 'div';
render() {
return (
<this._tagName />
);
}
}

View File

@@ -0,0 +1,11 @@
// @jsx: preserve
declare module JSX {
interface Element { }
interface IntrinsicElements {
div: any
}
}
const t = {tag:'h1'}
const foo = <t.tag/> // No error

View File

@@ -0,0 +1,19 @@
// @jsx: preserve
//@filename: react.d.ts
declare module 'react' {
class Component<T, U> { }
}
//@filename: app.tsx
import * as React from 'react';
export class Text extends React.Component<{}, {}> {
_tagName: string = 'div';
render() {
return (
<this/> // this should be an error
);
}
}

View File

@@ -0,0 +1,19 @@
// @jsx: preserve
//@filename: react.d.ts
declare module 'react' {
class Component<T, U> { }
}
//@filename: app.tsx
import * as React from 'react';
export class Text extends React.Component<{}, {}> {
_tagName: string = 'div';
render() {
return (
<this._tagName> Hello world </this._tagName>
);
}
}

View File

@@ -0,0 +1,19 @@
// @jsx: preserve
//@filename: react.d.ts
declare module 'react' {
class Component<T, U> { }
}
//@filename: app.tsx
import * as React from 'react';
export class Text extends React.Component<{}, {}> {
_tagName: "div" = 'div';
render() {
return (
<this._tagName> Hello world </this._tagName>
);
}
}

View File

@@ -5,9 +5,9 @@
import React = require('react');
type Invalid1 = React.ComponentClass<any> | string;
type Invalid1 = React.ComponentClass<any> | number;
const X: Invalid1 = "Should fail to construct";
const X: Invalid1 = 1;
<X />;