Actually get the apparent type of intersection members when calculating intersection apparent types (#21133)

* Actually get the apparent type of intersection members when calculating intersection apparent types

* Add nonjsx variant

* Fix nit
This commit is contained in:
Wesley Wigham authored and GitHub committed 2018-01-17 15:20:09 -08:00
1 parent 9ad9dc106c
commit 99d6b0d308
10 files changed
+385 -8

No files matched your search

+7 -6
View File
@@ -5416,18 +5416,19 @@ namespace ts {
return symbol;
}
function getTypeWithThisArgument(type: Type, thisArgument?: Type): Type {
function getTypeWithThisArgument(type: Type, thisArgument?: Type, needApparentType?: boolean): Type {
if (getObjectFlags(type) & ObjectFlags.Reference) {
const target = (<TypeReference>type).target;
const typeArguments = (<TypeReference>type).typeArguments;
if (length(target.typeParameters) === length(typeArguments)) {
return createTypeReference(target, concatenate(typeArguments, [thisArgument || target.thisType]));
const ref = createTypeReference(target, concatenate(typeArguments, [thisArgument || target.thisType]));
return needApparentType ? getApparentType(ref) : ref;
}
}
else if (type.flags & TypeFlags.Intersection) {
return getIntersectionType(map((<IntersectionType>type).types, t => getTypeWithThisArgument(t, thisArgument)));
return getIntersectionType(map((<IntersectionType>type).types, t => getTypeWithThisArgument(t, thisArgument, needApparentType)));
}
return type;
return needApparentType ? getApparentType(type) : type;
}
function resolveObjectTypeMembers(type: ObjectType, source: InterfaceTypeWithDeclaredMembers, typeParameters: TypeParameter[], typeArguments: Type[]) {
@@ -6107,7 +6108,7 @@ namespace ts {
}
function getApparentTypeOfIntersectionType(type: IntersectionType) {
return type.resolvedApparentType || (type.resolvedApparentType = getTypeWithThisArgument(type, type));
return type.resolvedApparentType || (type.resolvedApparentType = getTypeWithThisArgument(type, type, /*apparentType*/ true));
}
function getResolvedTypeParameterDefault(typeParameter: TypeParameter): Type | undefined {
@@ -14068,7 +14069,7 @@ namespace ts {
// If the given type is an object or union type with a single signature, and if that signature has at
// least as many parameters as the given function, return the signature. Otherwise return undefined.
function getContextualCallSignature(type: Type, node: FunctionExpression | ArrowFunction | MethodDeclaration): Signature {
const signatures = getSignaturesOfStructuredType(type, SignatureKind.Call);
const signatures = getSignaturesOfType(type, SignatureKind.Call);
if (signatures.length === 1) {
const signature = signatures[0];
if (!isAritySmaller(signature, node)) {
@@ -0,0 +1,25 @@
//// [intersectionOfTypeVariableHasApparentSignatures.ts]
interface Component<P> {
props: Readonly<P> & Readonly<{ children?: {} }>;
}
interface Props {
children?: (items: {x: number}) => void
}
declare function f<T extends Props>(i: Component<T>): void;
f({
props: {
children: (({ x }) => { })
}
});
//// [intersectionOfTypeVariableHasApparentSignatures.js]
f({
props: {
children: (function (_a) {
var x = _a.x;
})
}
});
@@ -0,0 +1,41 @@
=== tests/cases/compiler/intersectionOfTypeVariableHasApparentSignatures.ts ===
interface Component<P> {
>Component : Symbol(Component, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 0, 0))
>P : Symbol(P, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 0, 20))
props: Readonly<P> & Readonly<{ children?: {} }>;
>props : Symbol(Component.props, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 0, 24))
>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --))
>P : Symbol(P, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 0, 20))
>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --))
>children : Symbol(children, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 1, 35))
}
interface Props {
>Props : Symbol(Props, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 2, 1))
children?: (items: {x: number}) => void
>children : Symbol(Props.children, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 4, 17))
>items : Symbol(items, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 5, 16))
>x : Symbol(x, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 5, 24))
}
declare function f<T extends Props>(i: Component<T>): void;
>f : Symbol(f, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 6, 1))
>T : Symbol(T, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 8, 19))
>Props : Symbol(Props, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 2, 1))
>i : Symbol(i, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 8, 36))
>Component : Symbol(Component, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 0, 0))
>T : Symbol(T, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 8, 19))
f({
>f : Symbol(f, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 6, 1))
props: {
>props : Symbol(props, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 10, 3))
children: (({ x }) => { })
>children : Symbol(children, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 11, 12))
>x : Symbol(x, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 12, 21))
}
});
@@ -0,0 +1,46 @@
=== tests/cases/compiler/intersectionOfTypeVariableHasApparentSignatures.ts ===
interface Component<P> {
>Component : Component<P>
>P : P
props: Readonly<P> & Readonly<{ children?: {} }>;
>props : Readonly<P> & Readonly<{ children?: {} | undefined; }>
>Readonly : Readonly<T>
>P : P
>Readonly : Readonly<T>
>children : {} | undefined
}
interface Props {
>Props : Props
children?: (items: {x: number}) => void
>children : ((items: { x: number; }) => void) | undefined
>items : { x: number; }
>x : number
}
declare function f<T extends Props>(i: Component<T>): void;
>f : <T extends Props>(i: Component<T>) => void
>T : T
>Props : Props
>i : Component<T>
>Component : Component<P>
>T : T
f({
>f({ props: { children: (({ x }) => { }) }}) : void
>f : <T extends Props>(i: Component<T>) => void
>{ props: { children: (({ x }) => { }) }} : { props: { children: ({ x }: { x: number; }) => void; }; }
props: {
>props : { children: ({ x }: { x: number; }) => void; }
>{ children: (({ x }) => { }) } : { children: ({ x }: { x: number; }) => void; }
children: (({ x }) => { })
>children : ({ x }: { x: number; }) => void
>(({ x }) => { }) : ({ x }: { x: number; }) => void
>({ x }) => { } : ({ x }: { x: number; }) => void
>x : number
}
});
@@ -0,0 +1,52 @@
//// [jsxCallbackWithDestructuring.tsx]
// minimal component
interface Component<P = {}, S = {}> { }
declare class Component<P, S> {
constructor(props: P, context?: any);
render(): {};
props: Readonly<{ children?: {} }> & Readonly<P>;
}
declare global {
namespace JSX {
interface Element { }
interface ElementClass {
render(): {};
}
interface ElementAttributesProperty { props: {}; }
interface ElementChildrenAttribute { children: {}; }
interface IntrinsicAttributes { }
interface IntrinsicClassAttributes<T> { }
}
}
export interface RouteProps {
children?: (props: { x: number }) => any;
}
export class MyComponent<T extends RouteProps = RouteProps> extends Component<T> { }
<MyComponent children={({ x }) => {}}/>
//// [jsxCallbackWithDestructuring.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 MyComponent = /** @class */ (function (_super) {
__extends(MyComponent, _super);
function MyComponent() {
return _super !== null && _super.apply(this, arguments) || this;
}
return MyComponent;
}(Component));
exports.MyComponent = MyComponent;
<MyComponent children={function (_a) {
var x = _a.x;
}}/>;
@@ -0,0 +1,81 @@
=== tests/cases/compiler/jsxCallbackWithDestructuring.tsx ===
// minimal component
interface Component<P = {}, S = {}> { }
>Component : Symbol(Component, Decl(jsxCallbackWithDestructuring.tsx, 0, 0), Decl(jsxCallbackWithDestructuring.tsx, 1, 39))
>P : Symbol(P, Decl(jsxCallbackWithDestructuring.tsx, 1, 20), Decl(jsxCallbackWithDestructuring.tsx, 2, 24))
>S : Symbol(S, Decl(jsxCallbackWithDestructuring.tsx, 1, 27), Decl(jsxCallbackWithDestructuring.tsx, 2, 26))
declare class Component<P, S> {
>Component : Symbol(Component, Decl(jsxCallbackWithDestructuring.tsx, 0, 0), Decl(jsxCallbackWithDestructuring.tsx, 1, 39))
>P : Symbol(P, Decl(jsxCallbackWithDestructuring.tsx, 1, 20), Decl(jsxCallbackWithDestructuring.tsx, 2, 24))
>S : Symbol(S, Decl(jsxCallbackWithDestructuring.tsx, 1, 27), Decl(jsxCallbackWithDestructuring.tsx, 2, 26))
constructor(props: P, context?: any);
>props : Symbol(props, Decl(jsxCallbackWithDestructuring.tsx, 3, 16))
>P : Symbol(P, Decl(jsxCallbackWithDestructuring.tsx, 1, 20), Decl(jsxCallbackWithDestructuring.tsx, 2, 24))
>context : Symbol(context, Decl(jsxCallbackWithDestructuring.tsx, 3, 25))
render(): {};
>render : Symbol(Component.render, Decl(jsxCallbackWithDestructuring.tsx, 3, 41))
props: Readonly<{ children?: {} }> & Readonly<P>;
>props : Symbol(Component.props, Decl(jsxCallbackWithDestructuring.tsx, 4, 17))
>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --))
>children : Symbol(children, Decl(jsxCallbackWithDestructuring.tsx, 5, 21))
>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --))
>P : Symbol(P, Decl(jsxCallbackWithDestructuring.tsx, 1, 20), Decl(jsxCallbackWithDestructuring.tsx, 2, 24))
}
declare global {
>global : Symbol(global, Decl(jsxCallbackWithDestructuring.tsx, 6, 1))
namespace JSX {
>JSX : Symbol(JSX, Decl(jsxCallbackWithDestructuring.tsx, 8, 16))
interface Element { }
>Element : Symbol(Element, Decl(jsxCallbackWithDestructuring.tsx, 9, 19))
interface ElementClass {
>ElementClass : Symbol(ElementClass, Decl(jsxCallbackWithDestructuring.tsx, 10, 30))
render(): {};
>render : Symbol(ElementClass.render, Decl(jsxCallbackWithDestructuring.tsx, 11, 33))
}
interface ElementAttributesProperty { props: {}; }
>ElementAttributesProperty : Symbol(ElementAttributesProperty, Decl(jsxCallbackWithDestructuring.tsx, 13, 9))
>props : Symbol(ElementAttributesProperty.props, Decl(jsxCallbackWithDestructuring.tsx, 14, 45))
interface ElementChildrenAttribute { children: {}; }
>ElementChildrenAttribute : Symbol(ElementChildrenAttribute, Decl(jsxCallbackWithDestructuring.tsx, 14, 58))
>children : Symbol(ElementChildrenAttribute.children, Decl(jsxCallbackWithDestructuring.tsx, 15, 44))
interface IntrinsicAttributes { }
>IntrinsicAttributes : Symbol(IntrinsicAttributes, Decl(jsxCallbackWithDestructuring.tsx, 15, 60))
interface IntrinsicClassAttributes<T> { }
>IntrinsicClassAttributes : Symbol(IntrinsicClassAttributes, Decl(jsxCallbackWithDestructuring.tsx, 16, 42))
>T : Symbol(T, Decl(jsxCallbackWithDestructuring.tsx, 17, 43))
}
}
export interface RouteProps {
>RouteProps : Symbol(RouteProps, Decl(jsxCallbackWithDestructuring.tsx, 19, 1))
children?: (props: { x: number }) => any;
>children : Symbol(RouteProps.children, Decl(jsxCallbackWithDestructuring.tsx, 21, 29))
>props : Symbol(props, Decl(jsxCallbackWithDestructuring.tsx, 22, 16))
>x : Symbol(x, Decl(jsxCallbackWithDestructuring.tsx, 22, 24))
}
export class MyComponent<T extends RouteProps = RouteProps> extends Component<T> { }
>MyComponent : Symbol(MyComponent, Decl(jsxCallbackWithDestructuring.tsx, 23, 1))
>T : Symbol(T, Decl(jsxCallbackWithDestructuring.tsx, 24, 25))
>RouteProps : Symbol(RouteProps, Decl(jsxCallbackWithDestructuring.tsx, 19, 1))
>RouteProps : Symbol(RouteProps, Decl(jsxCallbackWithDestructuring.tsx, 19, 1))
>Component : Symbol(Component, Decl(jsxCallbackWithDestructuring.tsx, 0, 0), Decl(jsxCallbackWithDestructuring.tsx, 1, 39))
>T : Symbol(T, Decl(jsxCallbackWithDestructuring.tsx, 24, 25))
<MyComponent children={({ x }) => {}}/>
>MyComponent : Symbol(MyComponent, Decl(jsxCallbackWithDestructuring.tsx, 23, 1))
>children : Symbol(children, Decl(jsxCallbackWithDestructuring.tsx, 25, 12))
>x : Symbol(x, Decl(jsxCallbackWithDestructuring.tsx, 25, 25))
@@ -0,0 +1,83 @@
=== tests/cases/compiler/jsxCallbackWithDestructuring.tsx ===
// minimal component
interface Component<P = {}, S = {}> { }
>Component : Component<P, S>
>P : P
>S : S
declare class Component<P, S> {
>Component : Component<P, S>
>P : P
>S : S
constructor(props: P, context?: any);
>props : P
>P : P
>context : any
render(): {};
>render : () => {}
props: Readonly<{ children?: {} }> & Readonly<P>;
>props : Readonly<{ children?: {} | undefined; }> & Readonly<P>
>Readonly : Readonly<T>
>children : {} | undefined
>Readonly : Readonly<T>
>P : P
}
declare global {
>global : any
namespace JSX {
>JSX : any
interface Element { }
>Element : Element
interface ElementClass {
>ElementClass : ElementClass
render(): {};
>render : () => {}
}
interface ElementAttributesProperty { props: {}; }
>ElementAttributesProperty : ElementAttributesProperty
>props : {}
interface ElementChildrenAttribute { children: {}; }
>ElementChildrenAttribute : ElementChildrenAttribute
>children : {}
interface IntrinsicAttributes { }
>IntrinsicAttributes : IntrinsicAttributes
interface IntrinsicClassAttributes<T> { }
>IntrinsicClassAttributes : IntrinsicClassAttributes<T>
>T : T
}
}
export interface RouteProps {
>RouteProps : RouteProps
children?: (props: { x: number }) => any;
>children : ((props: { x: number; }) => any) | undefined
>props : { x: number; }
>x : number
}
export class MyComponent<T extends RouteProps = RouteProps> extends Component<T> { }
>MyComponent : MyComponent<T>
>T : T
>RouteProps : RouteProps
>RouteProps : RouteProps
>Component : Component<T, {}>
>T : T
<MyComponent children={({ x }) => {}}/>
><MyComponent children={({ x }) => {}}/> : JSX.Element
>MyComponent : typeof MyComponent
>children : ({ x }: { x: number; }) => void
>({ x }) => {} : ({ x }: { x: number; }) => void
>x : number
@@ -3,7 +3,7 @@ tests/cases/conformance/jsx/file.tsx(9,33): error TS2322: Type '{ a: number; }'
Property 'b' is missing in type '{ a: number; }'.
tests/cases/conformance/jsx/file.tsx(10,33): error TS2322: Type 'T & { ignore-prop: true; }' is not assignable to type 'IntrinsicAttributes & { b: {}; a: {}; }'.
Type 'T & { ignore-prop: true; }' is not assignable to type '{ b: {}; a: {}; }'.
Property 'a' is missing in type 'T & { ignore-prop: true; }'.
Property 'a' is missing in type '{ b: number; } & { ignore-prop: true; }'.
==== tests/cases/conformance/jsx/file.tsx (2 errors) ====
@@ -24,5 +24,5 @@ tests/cases/conformance/jsx/file.tsx(10,33): error TS2322: Type 'T & { ignore-pr
~~~~~~~~~~~~~~~~~~~~~
!!! error TS2322: Type 'T & { ignore-prop: true; }' is not assignable to type 'IntrinsicAttributes & { b: {}; a: {}; }'.
!!! error TS2322: Type 'T & { ignore-prop: true; }' is not assignable to type '{ b: {}; a: {}; }'.
!!! error TS2322: Property 'a' is missing in type 'T & { ignore-prop: true; }'.
!!! error TS2322: Property 'a' is missing in type '{ b: number; } & { ignore-prop: true; }'.
}
@@ -0,0 +1,17 @@
// @strictNullChecks: true
// @noImplicitAny: true
interface Component<P> {
props: Readonly<P> & Readonly<{ children?: {} }>;
}
interface Props {
children?: (items: {x: number}) => void
}
declare function f<T extends Props>(i: Component<T>): void;
f({
props: {
children: (({ x }) => { })
}
});
@@ -0,0 +1,31 @@
// @jsx: preserve
// @noImplicitAny: true
// @strictNullChecks: true
// minimal component
interface Component<P = {}, S = {}> { }
declare class Component<P, S> {
constructor(props: P, context?: any);
render(): {};
props: Readonly<{ children?: {} }> & Readonly<P>;
}
declare global {
namespace JSX {
interface Element { }
interface ElementClass {
render(): {};
}
interface ElementAttributesProperty { props: {}; }
interface ElementChildrenAttribute { children: {}; }
interface IntrinsicAttributes { }
interface IntrinsicClassAttributes<T> { }
}
}
export interface RouteProps {
children?: (props: { x: number }) => any;
}
export class MyComponent<T extends RouteProps = RouteProps> extends Component<T> { }
<MyComponent children={({ x }) => {}}/>