Always call checkExpression on JSX attribute values

Fixes #13676
This commit is contained in:
Ryan Cavanaugh 2017-01-25 10:40:59 -08:00
parent abc30b26c7
commit 76b1e95c3d
5 changed files with 239 additions and 9 deletions

View File

@ -11879,6 +11879,16 @@ namespace ts {
function checkJsxAttribute(node: JsxAttribute, elementAttributesType: Type, nameTable: Map<boolean>) {
let correspondingPropType: Type = undefined;
// We need to unconditionally get the expression type
let exprType: Type;
if (node.initializer) {
exprType = checkExpression(node.initializer);
}
else {
// <Elem attr /> is sugar for <Elem attr={true} />
exprType = booleanType;
}
// Look up the corresponding property for this attribute
if (elementAttributesType === emptyObjectType && isUnhyphenatedJsxName(node.name.text)) {
// If there is no 'props' property, you may not have non-"data-" attributes
@ -11902,15 +11912,6 @@ namespace ts {
}
}
let exprType: Type;
if (node.initializer) {
exprType = checkExpression(node.initializer);
}
else {
// <Elem attr /> is sugar for <Elem attr={true} />
exprType = booleanType;
}
if (correspondingPropType) {
checkTypeAssignableTo(exprType, correspondingPropType, node);
}

View File

@ -0,0 +1,48 @@
//// [tests/cases/compiler/reactImportDropped.ts] ////
//// [react.d.ts]
export = React;
export as namespace React;
declare namespace React {
function createClass(spec: any): ClassicComponentClass;
interface ClassicComponentClass {
new (props?: any): ClassicComponentClass;
}
}
declare global {
namespace JSX {
interface ElementAttributesProperty { }
}
}
//// [TabBar.js]
export default React.createClass({
render() {
return (
null
);
}
});
//// [NavigationView.js]
import TabBar from '../../components/TabBar';
import {layout} from '../../utils/theme'; // <- DO NOT DROP this import
const x = <TabBar height={layout.footerHeight} />;
//// [TabBar.js]
export default React.createClass({
render() {
return (null);
}
});
//// [NavigationView.js]
import TabBar from '../../components/TabBar';
import { layout } from '../../utils/theme'; // <- DO NOT DROP this import
const x = React.createElement(TabBar, { height: layout.footerHeight });

View File

@ -0,0 +1,65 @@
=== tests/cases/compiler/react.d.ts ===
export = React;
>React : Symbol(React, Decl(react.d.ts, 2, 26))
export as namespace React;
>React : Symbol(React, Decl(react.d.ts, 1, 15))
declare namespace React {
>React : Symbol(React, Decl(react.d.ts, 2, 26))
function createClass(spec: any): ClassicComponentClass;
>createClass : Symbol(createClass, Decl(react.d.ts, 4, 25))
>spec : Symbol(spec, Decl(react.d.ts, 6, 25))
>ClassicComponentClass : Symbol(ClassicComponentClass, Decl(react.d.ts, 6, 59))
interface ClassicComponentClass {
>ClassicComponentClass : Symbol(ClassicComponentClass, Decl(react.d.ts, 6, 59))
new (props?: any): ClassicComponentClass;
>props : Symbol(props, Decl(react.d.ts, 9, 13))
>ClassicComponentClass : Symbol(ClassicComponentClass, Decl(react.d.ts, 6, 59))
}
}
declare global {
>global : Symbol(global, Decl(react.d.ts, 11, 1))
namespace JSX {
>JSX : Symbol(JSX, Decl(react.d.ts, 13, 16))
interface ElementAttributesProperty { }
>ElementAttributesProperty : Symbol(ElementAttributesProperty, Decl(react.d.ts, 14, 19))
}
}
=== tests/cases/compiler/src/components/TabBar.js ===
export default React.createClass({
>React.createClass : Symbol(React.createClass, Decl(react.d.ts, 4, 25))
>React : Symbol(React, Decl(react.d.ts, 1, 15))
>createClass : Symbol(React.createClass, Decl(react.d.ts, 4, 25))
render() {
>render : Symbol(render, Decl(TabBar.js, 0, 34))
return (
null
);
}
});
=== tests/cases/compiler/src/modules/navigation/NavigationView.js ===
import TabBar from '../../components/TabBar';
>TabBar : Symbol(TabBar, Decl(NavigationView.js, 0, 6))
import {layout} from '../../utils/theme'; // <- DO NOT DROP this import
>layout : Symbol(layout, Decl(NavigationView.js, 1, 8))
const x = <TabBar height={layout.footerHeight} />;
>x : Symbol(x, Decl(NavigationView.js, 2, 5))
>TabBar : Symbol(TabBar, Decl(NavigationView.js, 0, 6))
>height : Symbol(layout)
>layout : Symbol(layout, Decl(NavigationView.js, 1, 8))

View File

@ -0,0 +1,74 @@
=== tests/cases/compiler/react.d.ts ===
export = React;
>React : typeof React
export as namespace React;
>React : typeof React
declare namespace React {
>React : typeof React
function createClass(spec: any): ClassicComponentClass;
>createClass : (spec: any) => ClassicComponentClass
>spec : any
>ClassicComponentClass : ClassicComponentClass
interface ClassicComponentClass {
>ClassicComponentClass : ClassicComponentClass
new (props?: any): ClassicComponentClass;
>props : any
>ClassicComponentClass : ClassicComponentClass
}
}
declare global {
>global : any
namespace JSX {
>JSX : any
interface ElementAttributesProperty { }
>ElementAttributesProperty : ElementAttributesProperty
}
}
=== tests/cases/compiler/src/components/TabBar.js ===
export default React.createClass({
>React.createClass({ render() { return ( null ); }}) : React.ClassicComponentClass
>React.createClass : (spec: any) => React.ClassicComponentClass
>React : typeof React
>createClass : (spec: any) => React.ClassicComponentClass
>{ render() { return ( null ); }} : { render(): any; }
render() {
>render : () => any
return (
>( null ) : null
null
>null : null
);
}
});
=== tests/cases/compiler/src/modules/navigation/NavigationView.js ===
import TabBar from '../../components/TabBar';
>TabBar : React.ClassicComponentClass
import {layout} from '../../utils/theme'; // <- DO NOT DROP this import
>layout : any
const x = <TabBar height={layout.footerHeight} />;
>x : any
><TabBar height={layout.footerHeight} /> : any
>TabBar : React.ClassicComponentClass
>height : any
>layout.footerHeight : any
>layout : any
>footerHeight : any

View File

@ -0,0 +1,42 @@
//@module: es6
//@moduleResolution: node
//@target: es6
//@noImplicitAny: false
//@allowSyntheticDefaultImports: true
//@allowJs: true
//@jsx: react
//@outDir: "build"
//@filename: react.d.ts
export = React;
export as namespace React;
declare namespace React {
function createClass(spec: any): ClassicComponentClass;
interface ClassicComponentClass {
new (props?: any): ClassicComponentClass;
}
}
declare global {
namespace JSX {
interface ElementAttributesProperty { }
}
}
//@filename: src/components/TabBar.js
export default React.createClass({
render() {
return (
null
);
}
});
//@filename: src/modules/navigation/NavigationView.js
import TabBar from '../../components/TabBar';
import {layout} from '../../utils/theme'; // <- DO NOT DROP this import
const x = <TabBar height={layout.footerHeight} />;