mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-15 03:23:08 -06:00
* Fix #15463: use intersection types to emulate spread in generic react components * Fix lint errors * reverse condition
This commit is contained in:
parent
f93c71c34e
commit
d51e467238
@ -13314,6 +13314,7 @@ namespace ts {
|
||||
let spread: Type = emptyObjectType;
|
||||
let attributesArray: Symbol[] = [];
|
||||
let hasSpreadAnyType = false;
|
||||
let typeToIntersect: Type;
|
||||
let explicitlySpecifyChildrenAttribute = false;
|
||||
const jsxChildrenPropertyName = getJsxElementChildrenPropertyname();
|
||||
|
||||
@ -13345,11 +13346,16 @@ namespace ts {
|
||||
attributesArray = [];
|
||||
attributesTable = createMap<Symbol>();
|
||||
}
|
||||
const exprType = getApparentType(checkExpression(attributeDecl.expression));
|
||||
const exprType = checkExpression(attributeDecl.expression);
|
||||
if (isTypeAny(exprType)) {
|
||||
hasSpreadAnyType = true;
|
||||
}
|
||||
spread = getSpreadType(spread, exprType);
|
||||
if (isValidSpreadType(exprType)) {
|
||||
spread = getSpreadType(spread, exprType);
|
||||
}
|
||||
else {
|
||||
typeToIntersect = typeToIntersect ? getIntersectionType([typeToIntersect, exprType]) : exprType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -13404,7 +13410,13 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
return hasSpreadAnyType ? anyType : createJsxAttributesType(attributes.symbol, attributesTable);
|
||||
if (hasSpreadAnyType) {
|
||||
return anyType;
|
||||
}
|
||||
|
||||
const attributeType = createJsxAttributesType(attributes.symbol, attributesTable);
|
||||
return typeToIntersect && attributesTable.size ? getIntersectionType([typeToIntersect, attributeType]) :
|
||||
typeToIntersect ? typeToIntersect : attributeType;
|
||||
|
||||
/**
|
||||
* Create anonymous type from given attributes symbol table.
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
tests/cases/conformance/jsx/file.tsx(21,16): error TS2322: Type '{ x: number; }' is not assignable to type 'Attribs1'.
|
||||
Types of property 'x' are incompatible.
|
||||
Type 'number' is not assignable to type 'string'.
|
||||
tests/cases/conformance/jsx/file.tsx(25,16): error TS2322: Type '{ y: string; }' is not assignable to type 'Attribs1'.
|
||||
Property 'x' is missing in type '{ y: string; }'.
|
||||
tests/cases/conformance/jsx/file.tsx(21,16): error TS2322: Type 'T' is not assignable to type 'Attribs1'.
|
||||
Type '{ x: number; }' is not assignable to type 'Attribs1'.
|
||||
Types of property 'x' are incompatible.
|
||||
Type 'number' is not assignable to type 'string'.
|
||||
tests/cases/conformance/jsx/file.tsx(25,16): error TS2322: Type 'T' is not assignable to type 'Attribs1'.
|
||||
Type '{ y: string; }' is not assignable to type 'Attribs1'.
|
||||
Property 'x' is missing in type '{ y: string; }'.
|
||||
tests/cases/conformance/jsx/file.tsx(29,8): error TS2322: Type '{}' is not assignable to type 'Attribs1'.
|
||||
Property 'x' is missing in type '{}'.
|
||||
|
||||
@ -30,16 +32,18 @@ tests/cases/conformance/jsx/file.tsx(29,8): error TS2322: Type '{}' is not assig
|
||||
function make2<T extends {x: number}> (obj: T) {
|
||||
return <test1 {...obj} />; // Error (x is number, not string)
|
||||
~~~~~~~~
|
||||
!!! error TS2322: Type '{ x: number; }' is not assignable to type 'Attribs1'.
|
||||
!!! error TS2322: Types of property 'x' are incompatible.
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'Attribs1'.
|
||||
!!! error TS2322: Type '{ x: number; }' is not assignable to type 'Attribs1'.
|
||||
!!! error TS2322: Types of property 'x' are incompatible.
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
}
|
||||
|
||||
function make3<T extends {y: string}> (obj: T) {
|
||||
return <test1 {...obj} />; // Error, missing x
|
||||
~~~~~~~~
|
||||
!!! error TS2322: Type '{ y: string; }' is not assignable to type 'Attribs1'.
|
||||
!!! error TS2322: Property 'x' is missing in type '{ y: string; }'.
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'Attribs1'.
|
||||
!!! error TS2322: Type '{ y: string; }' is not assignable to type 'Attribs1'.
|
||||
!!! error TS2322: Property 'x' is missing in type '{ y: string; }'.
|
||||
}
|
||||
|
||||
|
||||
|
||||
40
tests/baselines/reference/tsxGenericAttributesType9.js
Normal file
40
tests/baselines/reference/tsxGenericAttributesType9.js
Normal file
@ -0,0 +1,40 @@
|
||||
//// [file.tsx]
|
||||
import React = require('react');
|
||||
|
||||
export function makeP<P>(Ctor: React.ComponentClass<P>): React.ComponentClass<P> {
|
||||
return class extends React.PureComponent<P, void> {
|
||||
public render(): JSX.Element {
|
||||
return (
|
||||
<Ctor {...this.props } />
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//// [file.jsx]
|
||||
"use strict";
|
||||
var __extends = (this && this.__extends) || (function () {
|
||||
var extendStatics = Object.setPrototypeOf ||
|
||||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
||||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
|
||||
return function (d, b) {
|
||||
extendStatics(d, b);
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
})();
|
||||
exports.__esModule = true;
|
||||
var React = require("react");
|
||||
function makeP(Ctor) {
|
||||
return (function (_super) {
|
||||
__extends(class_1, _super);
|
||||
function class_1() {
|
||||
return _super !== null && _super.apply(this, arguments) || this;
|
||||
}
|
||||
class_1.prototype.render = function () {
|
||||
return (<Ctor {...this.props}/>);
|
||||
};
|
||||
return class_1;
|
||||
}(React.PureComponent));
|
||||
}
|
||||
exports.makeP = makeP;
|
||||
37
tests/baselines/reference/tsxGenericAttributesType9.symbols
Normal file
37
tests/baselines/reference/tsxGenericAttributesType9.symbols
Normal file
@ -0,0 +1,37 @@
|
||||
=== tests/cases/conformance/jsx/file.tsx ===
|
||||
import React = require('react');
|
||||
>React : Symbol(React, Decl(file.tsx, 0, 0))
|
||||
|
||||
export function makeP<P>(Ctor: React.ComponentClass<P>): React.ComponentClass<P> {
|
||||
>makeP : Symbol(makeP, Decl(file.tsx, 0, 32))
|
||||
>P : Symbol(P, Decl(file.tsx, 2, 22))
|
||||
>Ctor : Symbol(Ctor, Decl(file.tsx, 2, 25))
|
||||
>React : Symbol(React, Decl(file.tsx, 0, 0))
|
||||
>ComponentClass : Symbol(React.ComponentClass, Decl(react.d.ts, 204, 5))
|
||||
>P : Symbol(P, Decl(file.tsx, 2, 22))
|
||||
>React : Symbol(React, Decl(file.tsx, 0, 0))
|
||||
>ComponentClass : Symbol(React.ComponentClass, Decl(react.d.ts, 204, 5))
|
||||
>P : Symbol(P, Decl(file.tsx, 2, 22))
|
||||
|
||||
return class extends React.PureComponent<P, void> {
|
||||
>React.PureComponent : Symbol(React.PureComponent, Decl(react.d.ts, 179, 5))
|
||||
>React : Symbol(React, Decl(file.tsx, 0, 0))
|
||||
>PureComponent : Symbol(React.PureComponent, Decl(react.d.ts, 179, 5))
|
||||
>P : Symbol(P, Decl(file.tsx, 2, 22))
|
||||
|
||||
public render(): JSX.Element {
|
||||
>render : Symbol((Anonymous class).render, Decl(file.tsx, 3, 52))
|
||||
>JSX : Symbol(JSX, Decl(react.d.ts, 2352, 1))
|
||||
>Element : Symbol(JSX.Element, Decl(react.d.ts, 2355, 27))
|
||||
|
||||
return (
|
||||
<Ctor {...this.props } />
|
||||
>Ctor : Symbol(Ctor, Decl(file.tsx, 2, 25))
|
||||
>this.props : Symbol(React.Component.props, Decl(react.d.ts, 166, 37))
|
||||
>this : Symbol((Anonymous class), Decl(file.tsx, 3, 7))
|
||||
>props : Symbol(React.Component.props, Decl(react.d.ts, 166, 37))
|
||||
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
41
tests/baselines/reference/tsxGenericAttributesType9.types
Normal file
41
tests/baselines/reference/tsxGenericAttributesType9.types
Normal file
@ -0,0 +1,41 @@
|
||||
=== tests/cases/conformance/jsx/file.tsx ===
|
||||
import React = require('react');
|
||||
>React : typeof React
|
||||
|
||||
export function makeP<P>(Ctor: React.ComponentClass<P>): React.ComponentClass<P> {
|
||||
>makeP : <P>(Ctor: React.ComponentClass<P>) => React.ComponentClass<P>
|
||||
>P : P
|
||||
>Ctor : React.ComponentClass<P>
|
||||
>React : any
|
||||
>ComponentClass : React.ComponentClass<P>
|
||||
>P : P
|
||||
>React : any
|
||||
>ComponentClass : React.ComponentClass<P>
|
||||
>P : P
|
||||
|
||||
return class extends React.PureComponent<P, void> {
|
||||
>class extends React.PureComponent<P, void> { public render(): JSX.Element { return ( <Ctor {...this.props } /> ); } } : typeof (Anonymous class)
|
||||
>React.PureComponent : React.PureComponent<P, void>
|
||||
>React : typeof React
|
||||
>PureComponent : typeof React.PureComponent
|
||||
>P : P
|
||||
|
||||
public render(): JSX.Element {
|
||||
>render : () => JSX.Element
|
||||
>JSX : any
|
||||
>Element : JSX.Element
|
||||
|
||||
return (
|
||||
>( <Ctor {...this.props } /> ) : JSX.Element
|
||||
|
||||
<Ctor {...this.props } />
|
||||
><Ctor {...this.props } /> : JSX.Element
|
||||
>Ctor : React.ComponentClass<P>
|
||||
>this.props : P & { children?: React.ReactNode; }
|
||||
>this : this
|
||||
>props : P & { children?: React.ReactNode; }
|
||||
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -1,10 +1,9 @@
|
||||
tests/cases/conformance/jsx/file.tsx(8,34): error TS2322: Type '{ ignore-prop: 10; prop: number; }' is not assignable to type 'IntrinsicAttributes & { prop: number; "ignore-prop": string; }'.
|
||||
Type '{ ignore-prop: 10; prop: number; }' is not assignable to type '{ prop: number; "ignore-prop": string; }'.
|
||||
tests/cases/conformance/jsx/file.tsx(8,34): error TS2322: Type 'T & { ignore-prop: 10; }' is not assignable to type 'IntrinsicAttributes & { prop: number; "ignore-prop": string; }'.
|
||||
Type 'T & { ignore-prop: 10; }' is not assignable to type '{ prop: number; "ignore-prop": string; }'.
|
||||
Types of property '"ignore-prop"' are incompatible.
|
||||
Type '10' is not assignable to type 'string'.
|
||||
tests/cases/conformance/jsx/file.tsx(13,34): error TS2322: Type '{}' is not assignable to type 'IntrinsicAttributes & { prop: {}; "ignore-prop": string; }'.
|
||||
Type '{}' is not assignable to type '{ prop: {}; "ignore-prop": string; }'.
|
||||
Property 'prop' is missing in type '{}'.
|
||||
tests/cases/conformance/jsx/file.tsx(13,34): error TS2322: Type 'T' is not assignable to type 'IntrinsicAttributes & { prop: {}; "ignore-prop": string; }'.
|
||||
Type 'T' is not assignable to type '{ prop: {}; "ignore-prop": string; }'.
|
||||
tests/cases/conformance/jsx/file.tsx(20,19): error TS2322: Type '{ func: (a: number, b: string) => void; }' is not assignable to type 'IntrinsicAttributes & { func: (arg: number) => void; }'.
|
||||
Type '{ func: (a: number, b: string) => void; }' is not assignable to type '{ func: (arg: number) => void; }'.
|
||||
Types of property 'func' are incompatible.
|
||||
@ -25,8 +24,8 @@ tests/cases/conformance/jsx/file.tsx(31,10): error TS2453: The type argument for
|
||||
function Bar<T extends {prop: number}>(arg: T) {
|
||||
let a1 = <ComponentSpecific1 {...arg} ignore-prop={10} />;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2322: Type '{ ignore-prop: 10; prop: number; }' is not assignable to type 'IntrinsicAttributes & { prop: number; "ignore-prop": string; }'.
|
||||
!!! error TS2322: Type '{ ignore-prop: 10; prop: number; }' is not assignable to type '{ prop: number; "ignore-prop": string; }'.
|
||||
!!! error TS2322: Type 'T & { ignore-prop: 10; }' is not assignable to type 'IntrinsicAttributes & { prop: number; "ignore-prop": string; }'.
|
||||
!!! error TS2322: Type 'T & { ignore-prop: 10; }' is not assignable to type '{ prop: number; "ignore-prop": string; }'.
|
||||
!!! error TS2322: Types of property '"ignore-prop"' are incompatible.
|
||||
!!! error TS2322: Type '10' is not assignable to type 'string'.
|
||||
}
|
||||
@ -35,9 +34,8 @@ tests/cases/conformance/jsx/file.tsx(31,10): error TS2453: The type argument for
|
||||
function Baz<T>(arg: T) {
|
||||
let a0 = <ComponentSpecific1 {...arg} />
|
||||
~~~~~~~~
|
||||
!!! error TS2322: Type '{}' is not assignable to type 'IntrinsicAttributes & { prop: {}; "ignore-prop": string; }'.
|
||||
!!! error TS2322: Type '{}' is not assignable to type '{ prop: {}; "ignore-prop": string; }'.
|
||||
!!! error TS2322: Property 'prop' is missing in type '{}'.
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'IntrinsicAttributes & { prop: {}; "ignore-prop": string; }'.
|
||||
!!! error TS2322: Type 'T' is not assignable to type '{ prop: {}; "ignore-prop": string; }'.
|
||||
}
|
||||
|
||||
declare function Link<U>(l: {func: (arg: U)=>void}): JSX.Element;
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
tests/cases/conformance/jsx/file.tsx(9,33): error TS2322: Type '{ a: number; }' is not assignable to type 'IntrinsicAttributes & { b: {}; a: number; }'.
|
||||
Type '{ a: number; }' is not assignable to type '{ b: {}; a: number; }'.
|
||||
Property 'b' is missing in type '{ a: number; }'.
|
||||
tests/cases/conformance/jsx/file.tsx(10,33): error TS2322: Type '{ b: number; }' is not assignable to type 'IntrinsicAttributes & { b: number; a: {}; }'.
|
||||
Type '{ b: number; }' is not assignable to type '{ b: number; a: {}; }'.
|
||||
Property 'a' is missing in type '{ b: number; }'.
|
||||
tests/cases/conformance/jsx/file.tsx(10,33): error TS2322: Type 'T' is not assignable to type 'IntrinsicAttributes & { b: number; a: {}; }'.
|
||||
Type '{ b: number; }' is not assignable to type 'IntrinsicAttributes & { b: number; a: {}; }'.
|
||||
Type '{ b: number; }' is not assignable to type '{ b: number; a: {}; }'.
|
||||
Type 'T' is not assignable to type '{ b: number; a: {}; }'.
|
||||
Type '{ b: number; }' is not assignable to type '{ b: number; a: {}; }'.
|
||||
Property 'a' is missing in type '{ b: number; }'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsx/file.tsx (2 errors) ====
|
||||
@ -22,7 +25,10 @@ tests/cases/conformance/jsx/file.tsx(10,33): error TS2322: Type '{ b: number; }'
|
||||
!!! error TS2322: Property 'b' is missing in type '{ a: number; }'.
|
||||
let a2 = <OverloadComponent {...arg1} ignore-prop /> // missing a
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2322: Type '{ b: number; }' is not assignable to type 'IntrinsicAttributes & { b: number; a: {}; }'.
|
||||
!!! error TS2322: Type '{ b: number; }' is not assignable to type '{ b: number; a: {}; }'.
|
||||
!!! error TS2322: Property 'a' is missing in type '{ b: number; }'.
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'IntrinsicAttributes & { b: number; a: {}; }'.
|
||||
!!! error TS2322: Type '{ b: number; }' is not assignable to type 'IntrinsicAttributes & { b: number; a: {}; }'.
|
||||
!!! error TS2322: Type '{ b: number; }' is not assignable to type '{ b: number; a: {}; }'.
|
||||
!!! error TS2322: Type 'T' is not assignable to type '{ b: number; a: {}; }'.
|
||||
!!! error TS2322: Type '{ b: number; }' is not assignable to type '{ b: number; a: {}; }'.
|
||||
!!! error TS2322: Property 'a' is missing in type '{ b: number; }'.
|
||||
}
|
||||
@ -1,7 +1,11 @@
|
||||
tests/cases/conformance/jsx/file.tsx(15,14): error TS2605: JSX element type 'Element' is not a constructor function for JSX elements.
|
||||
Property 'render' is missing in type 'Element'.
|
||||
tests/cases/conformance/jsx/file.tsx(15,15): error TS2453: The type argument for type parameter 'U' cannot be inferred from the usage. Consider specifying the type arguments explicitly.
|
||||
Type argument candidate 'number' is not a valid type argument because it is not a supertype of candidate '"hello"'.
|
||||
tests/cases/conformance/jsx/file.tsx(16,42): error TS2339: Property 'prop1' does not exist on type 'IntrinsicAttributes & { prop: number; }'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsx/file.tsx (1 errors) ====
|
||||
==== tests/cases/conformance/jsx/file.tsx (3 errors) ====
|
||||
import React = require('react')
|
||||
|
||||
declare function Component<U>(l: U): JSX.Element;
|
||||
@ -17,6 +21,12 @@ tests/cases/conformance/jsx/file.tsx(16,42): error TS2339: Property 'prop1' does
|
||||
let a1 = <ComponentSpecific {...arg} ignore-prop="hi" />; // U is number
|
||||
let a2 = <ComponentSpecific1 {...arg} ignore-prop={10} />; // U is number
|
||||
let a3 = <ComponentSpecific {...arg} prop="hello" />; // U is "hello"
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2605: JSX element type 'Element' is not a constructor function for JSX elements.
|
||||
!!! error TS2605: Property 'render' is missing in type 'Element'.
|
||||
~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2453: The type argument for type parameter 'U' cannot be inferred from the usage. Consider specifying the type arguments explicitly.
|
||||
!!! error TS2453: Type argument candidate 'number' is not a valid type argument because it is not a supertype of candidate '"hello"'.
|
||||
let a4 = <ComponentSpecific {...arg} prop1="hello" />; // U is "hello"
|
||||
~~~~~~~~~~~~~
|
||||
!!! error TS2339: Property 'prop1' does not exist on type 'IntrinsicAttributes & { prop: number; }'.
|
||||
|
||||
16
tests/cases/conformance/jsx/tsxGenericAttributesType9.tsx
Normal file
16
tests/cases/conformance/jsx/tsxGenericAttributesType9.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
// @filename: file.tsx
|
||||
// @jsx: preserve
|
||||
// @noLib: true
|
||||
// @libFiles: react.d.ts,lib.d.ts
|
||||
|
||||
import React = require('react');
|
||||
|
||||
export function makeP<P>(Ctor: React.ComponentClass<P>): React.ComponentClass<P> {
|
||||
return class extends React.PureComponent<P, void> {
|
||||
public render(): JSX.Element {
|
||||
return (
|
||||
<Ctor {...this.props } />
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -15,5 +15,5 @@
|
||||
|
||||
verify.quickInfos({
|
||||
1: "function ComponentSpecific<number>(l: {\n prop: number;\n}): any",
|
||||
2: "function ComponentSpecific<\"hello\">(l: {\n prop: \"hello\";\n}): any"
|
||||
2: "function ComponentSpecific<U>(l: {\n prop: U;\n}): any"
|
||||
});
|
||||
|
||||
@ -24,6 +24,6 @@ verify.quickInfos({
|
||||
3: "function OverloadComponent<boolean, string>(attr: {\n b: string;\n a: boolean;\n}): any (+2 overloads)",
|
||||
4: "function OverloadComponent<number>(attr: {\n b: number;\n a?: string;\n \"ignore-prop\": boolean;\n}): any (+2 overloads)",
|
||||
5: "function OverloadComponent(): any (+2 overloads)",
|
||||
6: "function OverloadComponent<boolean, number>(attr: {\n b: number;\n a: boolean;\n}): any (+2 overloads)",
|
||||
7: "function OverloadComponent<boolean, string>(attr: {\n b: string;\n a: boolean;\n}): any (+2 overloads)"
|
||||
6: "function OverloadComponent(): any (+2 overloads)",
|
||||
7: "function OverloadComponent(): any (+2 overloads)",
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user