From 1e806cea01a08641a2514e99707ea259df67d95a Mon Sep 17 00:00:00 2001 From: Kanchalai Tanglertsampan Date: Mon, 1 May 2017 11:53:13 -0700 Subject: [PATCH 1/2] For React Component class, we fill in missing type parameter and instantiate the constructor signature with the new type arguments. --- src/compiler/checker.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1e483eb80c..e1ed2f4fa1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13438,7 +13438,18 @@ namespace ts { } } - return getUnionType(map(signatures, getReturnTypeOfSignature), /*subtypeReduction*/ true); + const instantiatedSignatures = []; + for (const signature of signatures) { + if (signature.typeParameters) { + const typeArguments = fillMissingTypeArguments(/*typeArguments*/ undefined, signature.typeParameters, /*minTypeArgumentCount*/ 0); + instantiatedSignatures.push(getSignatureInstantiation(signature, typeArguments)); + } + else { + instantiatedSignatures.push(signature); + } + } + + return getUnionType(map(instantiatedSignatures, getReturnTypeOfSignature), /*subtypeReduction*/ true); } /** From b1cfee2070aa20148803971ca9a3dda717554177 Mon Sep 17 00:00:00 2001 From: Kanchalai Tanglertsampan Date: Mon, 1 May 2017 13:19:06 -0700 Subject: [PATCH 2/2] Add tests and baselines --- ...ReactComponentWithDefaultTypeParameter1.js | 19 ++++++++++ ...ComponentWithDefaultTypeParameter1.symbols | 34 +++++++++++++++++ ...ctComponentWithDefaultTypeParameter1.types | 36 ++++++++++++++++++ ...ponentWithDefaultTypeParameter2.errors.txt | 33 +++++++++++++++++ ...ReactComponentWithDefaultTypeParameter2.js | 23 ++++++++++++ ...ponentWithDefaultTypeParameter3.errors.txt | 30 +++++++++++++++ ...ReactComponentWithDefaultTypeParameter3.js | 28 ++++++++++++++ ...ctionComponentWithDefaultTypeParameter1.js | 26 +++++++++++++ ...ComponentWithDefaultTypeParameter1.symbols | 34 +++++++++++++++++ ...onComponentWithDefaultTypeParameter1.types | 37 +++++++++++++++++++ ...ponentWithDefaultTypeParameter2.errors.txt | 25 +++++++++++++ ...ctionComponentWithDefaultTypeParameter2.js | 25 +++++++++++++ ...eactComponentWithDefaultTypeParameter1.tsx | 17 +++++++++ ...eactComponentWithDefaultTypeParameter2.tsx | 19 ++++++++++ ...eactComponentWithDefaultTypeParameter3.tsx | 22 +++++++++++ ...tionComponentWithDefaultTypeParameter1.tsx | 19 ++++++++++ ...tionComponentWithDefaultTypeParameter2.tsx | 19 ++++++++++ 17 files changed, 446 insertions(+) create mode 100644 tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter1.js create mode 100644 tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter1.symbols create mode 100644 tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter1.types create mode 100644 tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter2.errors.txt create mode 100644 tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter2.js create mode 100644 tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter3.errors.txt create mode 100644 tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter3.js create mode 100644 tests/baselines/reference/tsxStatelessFunctionComponentWithDefaultTypeParameter1.js create mode 100644 tests/baselines/reference/tsxStatelessFunctionComponentWithDefaultTypeParameter1.symbols create mode 100644 tests/baselines/reference/tsxStatelessFunctionComponentWithDefaultTypeParameter1.types create mode 100644 tests/baselines/reference/tsxStatelessFunctionComponentWithDefaultTypeParameter2.errors.txt create mode 100644 tests/baselines/reference/tsxStatelessFunctionComponentWithDefaultTypeParameter2.js create mode 100644 tests/cases/conformance/jsx/tsxReactComponentWithDefaultTypeParameter1.tsx create mode 100644 tests/cases/conformance/jsx/tsxReactComponentWithDefaultTypeParameter2.tsx create mode 100644 tests/cases/conformance/jsx/tsxReactComponentWithDefaultTypeParameter3.tsx create mode 100644 tests/cases/conformance/jsx/tsxStatelessFunctionComponentWithDefaultTypeParameter1.tsx create mode 100644 tests/cases/conformance/jsx/tsxStatelessFunctionComponentWithDefaultTypeParameter2.tsx diff --git a/tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter1.js b/tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter1.js new file mode 100644 index 0000000000..3bd876dbc3 --- /dev/null +++ b/tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter1.js @@ -0,0 +1,19 @@ +//// [file.tsx] +import React = require('react'); + +interface Prop { + a: number, + b: string +} + +declare class MyComp

extends React.Component { + internalProp: P; +} + +let x = + +//// [file.jsx] +"use strict"; +exports.__esModule = true; +var React = require("react"); +var x = ; diff --git a/tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter1.symbols b/tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter1.symbols new file mode 100644 index 0000000000..b4aaafb21a --- /dev/null +++ b/tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter1.symbols @@ -0,0 +1,34 @@ +=== tests/cases/conformance/jsx/file.tsx === +import React = require('react'); +>React : Symbol(React, Decl(file.tsx, 0, 0)) + +interface Prop { +>Prop : Symbol(Prop, Decl(file.tsx, 0, 32)) + + a: number, +>a : Symbol(Prop.a, Decl(file.tsx, 2, 16)) + + b: string +>b : Symbol(Prop.b, Decl(file.tsx, 3, 14)) +} + +declare class MyComp

extends React.Component { +>MyComp : Symbol(MyComp, Decl(file.tsx, 5, 1)) +>P : Symbol(P, Decl(file.tsx, 7, 21)) +>Prop : Symbol(Prop, Decl(file.tsx, 0, 32)) +>React.Component : Symbol(React.Component, Decl(react.d.ts, 158, 55)) +>React : Symbol(React, Decl(file.tsx, 0, 0)) +>Component : Symbol(React.Component, Decl(react.d.ts, 158, 55)) +>P : Symbol(P, Decl(file.tsx, 7, 21)) + + internalProp: P; +>internalProp : Symbol(MyComp.internalProp, Decl(file.tsx, 7, 63)) +>P : Symbol(P, Decl(file.tsx, 7, 21)) +} + +let x = +>x : Symbol(x, Decl(file.tsx, 11, 3)) +>MyComp : Symbol(MyComp, Decl(file.tsx, 5, 1)) +>a : Symbol(a, Decl(file.tsx, 11, 15)) +>b : Symbol(b, Decl(file.tsx, 11, 22)) + diff --git a/tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter1.types b/tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter1.types new file mode 100644 index 0000000000..07eb311f7e --- /dev/null +++ b/tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter1.types @@ -0,0 +1,36 @@ +=== tests/cases/conformance/jsx/file.tsx === +import React = require('react'); +>React : typeof React + +interface Prop { +>Prop : Prop + + a: number, +>a : number + + b: string +>b : string +} + +declare class MyComp

extends React.Component { +>MyComp : MyComp

+>P : P +>Prop : Prop +>React.Component : React.Component +>React : typeof React +>Component : typeof React.Component +>P : P + + internalProp: P; +>internalProp : P +>P : P +} + +let x = +>x : JSX.Element +> : JSX.Element +>MyComp : typeof MyComp +>a : number +>10 : 10 +>b : string + diff --git a/tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter2.errors.txt b/tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter2.errors.txt new file mode 100644 index 0000000000..61d26c8afd --- /dev/null +++ b/tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter2.errors.txt @@ -0,0 +1,33 @@ +tests/cases/conformance/jsx/file.tsx(13,9): error TS2322: Type '{}' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes> & Prop & { children?: ReactNode; }'. + Type '{}' is not assignable to type 'Prop'. + Property 'a' is missing in type '{}'. +tests/cases/conformance/jsx/file.tsx(14,18): error TS2322: Type '{ a: "hi"; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes> & Prop & { children?: ReactNode; }'. + Type '{ a: "hi"; }' is not assignable to type 'Prop'. + Types of property 'a' are incompatible. + Type '"hi"' is not assignable to type 'number'. + + +==== tests/cases/conformance/jsx/file.tsx (2 errors) ==== + import React = require('react'); + + interface Prop { + a: number, + b: string + } + + declare class MyComp

extends React.Component { + internalProp: P; + } + + // Error + let x = + ~~~~~~~~~~ +!!! error TS2322: Type '{}' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes> & Prop & { children?: ReactNode; }'. +!!! error TS2322: Type '{}' is not assignable to type 'Prop'. +!!! error TS2322: Property 'a' is missing in type '{}'. + let x1 = + ~~~~~~ +!!! error TS2322: Type '{ a: "hi"; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes> & Prop & { children?: ReactNode; }'. +!!! error TS2322: Type '{ a: "hi"; }' is not assignable to type 'Prop'. +!!! error TS2322: Types of property 'a' are incompatible. +!!! error TS2322: Type '"hi"' is not assignable to type 'number'. \ No newline at end of file diff --git a/tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter2.js b/tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter2.js new file mode 100644 index 0000000000..469adbee4b --- /dev/null +++ b/tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter2.js @@ -0,0 +1,23 @@ +//// [file.tsx] +import React = require('react'); + +interface Prop { + a: number, + b: string +} + +declare class MyComp

extends React.Component { + internalProp: P; +} + +// Error +let x = +let x1 = + +//// [file.jsx] +"use strict"; +exports.__esModule = true; +var React = require("react"); +// Error +var x = ; +var x1 = ; diff --git a/tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter3.errors.txt b/tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter3.errors.txt new file mode 100644 index 0000000000..c49bd64353 --- /dev/null +++ b/tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter3.errors.txt @@ -0,0 +1,30 @@ +tests/cases/conformance/jsx/file.tsx(16,17): error TS2322: Type '{ a: 10; b: "hi"; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes> & { children?: ReactNode; }'. + Property 'a' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes> & { children?: ReactNode; }'. +tests/cases/conformance/jsx/file.tsx(17,18): error TS2322: Type '{ a: "hi"; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes> & { children?: ReactNode; }'. + Property 'a' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes> & { children?: ReactNode; }'. + + +==== tests/cases/conformance/jsx/file.tsx (2 errors) ==== + import React = require('react'); + + interface Prop { + a: number, + b: string + } + + declare class MyComp

extends React.Component { + internalProp: P; + } + + // OK: we fille in missing type argument with empty object + let x1 = + + // Error + let x = + ~~~~~~~~~~~~~ +!!! error TS2322: Type '{ a: 10; b: "hi"; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes> & { children?: ReactNode; }'. +!!! error TS2322: Property 'a' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes> & { children?: ReactNode; }'. + let x2 = + ~~~~~~ +!!! error TS2322: Type '{ a: "hi"; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes> & { children?: ReactNode; }'. +!!! error TS2322: Property 'a' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes> & { children?: ReactNode; }'. \ No newline at end of file diff --git a/tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter3.js b/tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter3.js new file mode 100644 index 0000000000..3eed9e5fb1 --- /dev/null +++ b/tests/baselines/reference/tsxReactComponentWithDefaultTypeParameter3.js @@ -0,0 +1,28 @@ +//// [file.tsx] +import React = require('react'); + +interface Prop { + a: number, + b: string +} + +declare class MyComp

extends React.Component { + internalProp: P; +} + +// OK: we fille in missing type argument with empty object +let x1 = + +// Error +let x = +let x2 = + +//// [file.jsx] +"use strict"; +exports.__esModule = true; +var React = require("react"); +// OK: we fille in missing type argument with empty object +var x1 = ; +// Error +var x = ; +var x2 = ; diff --git a/tests/baselines/reference/tsxStatelessFunctionComponentWithDefaultTypeParameter1.js b/tests/baselines/reference/tsxStatelessFunctionComponentWithDefaultTypeParameter1.js new file mode 100644 index 0000000000..95957dcd36 --- /dev/null +++ b/tests/baselines/reference/tsxStatelessFunctionComponentWithDefaultTypeParameter1.js @@ -0,0 +1,26 @@ +//// [file.tsx] +import React = require('react') + +interface MyComponentProp { + values: string; +} + +function MyComponent(attr: T) { + return

attr.values
+} + +// OK +let i = ; // We infer type arguments here +let i1 = ; + +//// [file.jsx] +define(["require", "exports", "react"], function (require, exports, React) { + "use strict"; + exports.__esModule = true; + function MyComponent(attr) { + return
attr.values
; + } + // OK + var i = ; // We infer type arguments here + var i1 = ; +}); diff --git a/tests/baselines/reference/tsxStatelessFunctionComponentWithDefaultTypeParameter1.symbols b/tests/baselines/reference/tsxStatelessFunctionComponentWithDefaultTypeParameter1.symbols new file mode 100644 index 0000000000..3cc5e4b300 --- /dev/null +++ b/tests/baselines/reference/tsxStatelessFunctionComponentWithDefaultTypeParameter1.symbols @@ -0,0 +1,34 @@ +=== tests/cases/conformance/jsx/file.tsx === +import React = require('react') +>React : Symbol(React, Decl(file.tsx, 0, 0)) + +interface MyComponentProp { +>MyComponentProp : Symbol(MyComponentProp, Decl(file.tsx, 0, 31)) + + values: string; +>values : Symbol(MyComponentProp.values, Decl(file.tsx, 2, 27)) +} + +function MyComponent(attr: T) { +>MyComponent : Symbol(MyComponent, Decl(file.tsx, 4, 1)) +>T : Symbol(T, Decl(file.tsx, 6, 21)) +>MyComponentProp : Symbol(MyComponentProp, Decl(file.tsx, 0, 31)) +>attr : Symbol(attr, Decl(file.tsx, 6, 42)) +>T : Symbol(T, Decl(file.tsx, 6, 21)) + + return
attr.values
+>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +} + +// OK +let i = ; // We infer type arguments here +>i : Symbol(i, Decl(file.tsx, 11, 3)) +>MyComponent : Symbol(MyComponent, Decl(file.tsx, 4, 1)) +>values : Symbol(values, Decl(file.tsx, 11, 20)) + +let i1 = ; +>i1 : Symbol(i1, Decl(file.tsx, 12, 3)) +>MyComponent : Symbol(MyComponent, Decl(file.tsx, 4, 1)) +>values : Symbol(values, Decl(file.tsx, 12, 21)) + diff --git a/tests/baselines/reference/tsxStatelessFunctionComponentWithDefaultTypeParameter1.types b/tests/baselines/reference/tsxStatelessFunctionComponentWithDefaultTypeParameter1.types new file mode 100644 index 0000000000..ddbeb8deca --- /dev/null +++ b/tests/baselines/reference/tsxStatelessFunctionComponentWithDefaultTypeParameter1.types @@ -0,0 +1,37 @@ +=== tests/cases/conformance/jsx/file.tsx === +import React = require('react') +>React : typeof React + +interface MyComponentProp { +>MyComponentProp : MyComponentProp + + values: string; +>values : string +} + +function MyComponent(attr: T) { +>MyComponent : (attr: T) => JSX.Element +>T : T +>MyComponentProp : MyComponentProp +>attr : T +>T : T + + return
attr.values
+>
attr.values
: JSX.Element +>div : any +>div : any +} + +// OK +let i = ; // We infer type arguments here +>i : JSX.Element +> : JSX.Element +>MyComponent : (attr: T) => JSX.Element +>values : true + +let i1 = ; +>i1 : JSX.Element +> : JSX.Element +>MyComponent : (attr: T) => JSX.Element +>values : string + diff --git a/tests/baselines/reference/tsxStatelessFunctionComponentWithDefaultTypeParameter2.errors.txt b/tests/baselines/reference/tsxStatelessFunctionComponentWithDefaultTypeParameter2.errors.txt new file mode 100644 index 0000000000..81273f178d --- /dev/null +++ b/tests/baselines/reference/tsxStatelessFunctionComponentWithDefaultTypeParameter2.errors.txt @@ -0,0 +1,25 @@ +tests/cases/conformance/jsx/file.tsx(13,24): error TS2322: Type '{ values: 5; }' is not assignable to type 'IntrinsicAttributes & MyComponentProp'. + Type '{ values: 5; }' is not assignable to type 'MyComponentProp'. + Types of property 'values' are incompatible. + Type '5' is not assignable to type 'string'. + + +==== tests/cases/conformance/jsx/file.tsx (1 errors) ==== + import React = require('react') + + interface MyComponentProp { + values: string; + } + + function MyComponent1(attr: T) { + return
attr.values
+ } + + + // Error + let i1 = ; + ~~~~~~~~~~ +!!! error TS2322: Type '{ values: 5; }' is not assignable to type 'IntrinsicAttributes & MyComponentProp'. +!!! error TS2322: Type '{ values: 5; }' is not assignable to type 'MyComponentProp'. +!!! error TS2322: Types of property 'values' are incompatible. +!!! error TS2322: Type '5' is not assignable to type 'string'. \ No newline at end of file diff --git a/tests/baselines/reference/tsxStatelessFunctionComponentWithDefaultTypeParameter2.js b/tests/baselines/reference/tsxStatelessFunctionComponentWithDefaultTypeParameter2.js new file mode 100644 index 0000000000..b418948a29 --- /dev/null +++ b/tests/baselines/reference/tsxStatelessFunctionComponentWithDefaultTypeParameter2.js @@ -0,0 +1,25 @@ +//// [file.tsx] +import React = require('react') + +interface MyComponentProp { + values: string; +} + +function MyComponent1(attr: T) { + return
attr.values
+} + + +// Error +let i1 = ; + +//// [file.jsx] +define(["require", "exports", "react"], function (require, exports, React) { + "use strict"; + exports.__esModule = true; + function MyComponent1(attr) { + return
attr.values
; + } + // Error + var i1 = ; +}); diff --git a/tests/cases/conformance/jsx/tsxReactComponentWithDefaultTypeParameter1.tsx b/tests/cases/conformance/jsx/tsxReactComponentWithDefaultTypeParameter1.tsx new file mode 100644 index 0000000000..5a8434dfe6 --- /dev/null +++ b/tests/cases/conformance/jsx/tsxReactComponentWithDefaultTypeParameter1.tsx @@ -0,0 +1,17 @@ +// @filename: file.tsx +// @jsx: preserve +// @noLib: true +// @libFiles: react.d.ts,lib.d.ts + +import React = require('react'); + +interface Prop { + a: number, + b: string +} + +declare class MyComp

extends React.Component { + internalProp: P; +} + +let x = \ No newline at end of file diff --git a/tests/cases/conformance/jsx/tsxReactComponentWithDefaultTypeParameter2.tsx b/tests/cases/conformance/jsx/tsxReactComponentWithDefaultTypeParameter2.tsx new file mode 100644 index 0000000000..2aa4afc2e2 --- /dev/null +++ b/tests/cases/conformance/jsx/tsxReactComponentWithDefaultTypeParameter2.tsx @@ -0,0 +1,19 @@ +// @filename: file.tsx +// @jsx: preserve +// @noLib: true +// @libFiles: react.d.ts,lib.d.ts + +import React = require('react'); + +interface Prop { + a: number, + b: string +} + +declare class MyComp

extends React.Component { + internalProp: P; +} + +// Error +let x = +let x1 = \ No newline at end of file diff --git a/tests/cases/conformance/jsx/tsxReactComponentWithDefaultTypeParameter3.tsx b/tests/cases/conformance/jsx/tsxReactComponentWithDefaultTypeParameter3.tsx new file mode 100644 index 0000000000..e4a045f136 --- /dev/null +++ b/tests/cases/conformance/jsx/tsxReactComponentWithDefaultTypeParameter3.tsx @@ -0,0 +1,22 @@ +// @filename: file.tsx +// @jsx: preserve +// @noLib: true +// @libFiles: react.d.ts,lib.d.ts + +import React = require('react'); + +interface Prop { + a: number, + b: string +} + +declare class MyComp

extends React.Component { + internalProp: P; +} + +// OK: we fille in missing type argument with empty object +let x1 = + +// Error +let x = +let x2 = \ No newline at end of file diff --git a/tests/cases/conformance/jsx/tsxStatelessFunctionComponentWithDefaultTypeParameter1.tsx b/tests/cases/conformance/jsx/tsxStatelessFunctionComponentWithDefaultTypeParameter1.tsx new file mode 100644 index 0000000000..f1a0fa20e0 --- /dev/null +++ b/tests/cases/conformance/jsx/tsxStatelessFunctionComponentWithDefaultTypeParameter1.tsx @@ -0,0 +1,19 @@ +// @filename: file.tsx +// @jsx: preserve +// @module: amd +// @noLib: true +// @libFiles: react.d.ts,lib.d.ts + +import React = require('react') + +interface MyComponentProp { + values: string; +} + +function MyComponent(attr: T) { + return

attr.values
+} + +// OK +let i = ; // We infer type arguments here +let i1 = ; \ No newline at end of file diff --git a/tests/cases/conformance/jsx/tsxStatelessFunctionComponentWithDefaultTypeParameter2.tsx b/tests/cases/conformance/jsx/tsxStatelessFunctionComponentWithDefaultTypeParameter2.tsx new file mode 100644 index 0000000000..cfc1fbb579 --- /dev/null +++ b/tests/cases/conformance/jsx/tsxStatelessFunctionComponentWithDefaultTypeParameter2.tsx @@ -0,0 +1,19 @@ +// @filename: file.tsx +// @jsx: preserve +// @module: amd +// @noLib: true +// @libFiles: react.d.ts,lib.d.ts + +import React = require('react') + +interface MyComponentProp { + values: string; +} + +function MyComponent1(attr: T) { + return
attr.values
+} + + +// Error +let i1 = ; \ No newline at end of file