Skip to content
Prev Previous commit
Next Next commit
wip-address PR
  • Loading branch information
Kanchalai Tanglertsampan committed Jun 23, 2016
commit 7a3f88a1936089c7d948258188a6f1274f709f10
7 changes: 4 additions & 3 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9628,8 +9628,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: LeftHandSideExpression) {
if (tagName.kind === SyntaxKind.PropertyAccessExpression) {
function isJsxIntrinsicIdentifier(tagName: JsxTagNameExpression) {
// TODO (yuisu): comment
if (tagName.kind === SyntaxKind.PropertyAccessExpression || tagName.kind === SyntaxKind.ThisKeyword) {
return false;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The else case here needs to be hardened since it assumes tagName: Identifier

else {
Expand Down Expand Up @@ -9830,7 +9831,7 @@ namespace ts {
return anyType;
}
else if (elemType.flags & TypeFlags.StringLiteral) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finish sentence in comment

// If the elemType is a stringLiteral type, we can then provide a check and give
// 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;
Expand Down
13 changes: 8 additions & 5 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3575,7 +3575,7 @@ namespace ts {
return finishNode(node);
}

function tagNamesAreEquivalent(lhs: LeftHandSideExpression, rhs: LeftHandSideExpression): boolean {
function tagNamesAreEquivalent(lhs: JsxTagNameExpression, rhs: JsxTagNameExpression): boolean {
if (lhs.kind !== rhs.kind) {
return false;
}
Expand All @@ -3588,8 +3588,9 @@ namespace ts {
return true;
}

// If we are at this statement then we must have PropertyAccessExpression
return (<PropertyAccessExpression>lhs).name.text === (<PropertyAccessExpression>rhs).name.text &&
tagNamesAreEquivalent((<PropertyAccessExpression>lhs).expression, (<PropertyAccessExpression>rhs).expression);
tagNamesAreEquivalent((<PropertyAccessExpression>lhs).expression as JsxTagNameExpression, (<PropertyAccessExpression>rhs).expression as JsxTagNameExpression);
}


Expand Down Expand Up @@ -3720,12 +3721,14 @@ namespace ts {
return finishNode(node);
}

function parseJsxElementName(): LeftHandSideExpression {
function parseJsxElementName(): JsxTagNameExpression {
scanJsxIdentifier();
// JsxElement can have name in the form of property-access expression or an identifier or string literal
// 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: LeftHandSideExpression = token === SyntaxKind.ThisKeyword ?
let expression: JsxTagNameExpression = token === SyntaxKind.ThisKeyword ?
parseTokenNode<PrimaryExpression>() : parseIdentifierName();
while (parseOptional(SyntaxKind.DotToken)) {
const propertyAccess: PropertyAccessExpression = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos);
Expand Down
6 changes: 4 additions & 2 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: LeftHandSideExpression;
tagName: JsxTagNameExpression;
attributes: NodeArray<JsxAttribute | JsxSpreadAttribute>;
}

Expand All @@ -1073,7 +1075,7 @@ namespace ts {

// @kind(SyntaxKind.JsxClosingElement)
export interface JsxClosingElement extends Node {
tagName: LeftHandSideExpression;
tagName: JsxTagNameExpression;
}

// @kind(SyntaxKind.JsxExpression)
Expand Down
19 changes: 19 additions & 0 deletions tests/cases/conformance/jsx/tsxDynamicTagName7.tsx
Original file line number Diff line number Diff line change
@@ -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
);
}
}
19 changes: 19 additions & 0 deletions tests/cases/conformance/jsx/tsxDynamicTagName8.tsx
Original file line number Diff line number Diff line change
@@ -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>
);
}
}
4 changes: 2 additions & 2 deletions tests/cases/conformance/jsx/tsxUnionTypeComponent2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 />;

Expand Down