Skip to content

Commit 99d6b0d

Browse files
authored
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
1 parent 9ad9dc1 commit 99d6b0d

10 files changed

+385
-8
lines changed

src/compiler/checker.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5416,18 +5416,19 @@ namespace ts {
54165416
return symbol;
54175417
}
54185418

5419-
function getTypeWithThisArgument(type: Type, thisArgument?: Type): Type {
5419+
function getTypeWithThisArgument(type: Type, thisArgument?: Type, needApparentType?: boolean): Type {
54205420
if (getObjectFlags(type) & ObjectFlags.Reference) {
54215421
const target = (<TypeReference>type).target;
54225422
const typeArguments = (<TypeReference>type).typeArguments;
54235423
if (length(target.typeParameters) === length(typeArguments)) {
5424-
return createTypeReference(target, concatenate(typeArguments, [thisArgument || target.thisType]));
5424+
const ref = createTypeReference(target, concatenate(typeArguments, [thisArgument || target.thisType]));
5425+
return needApparentType ? getApparentType(ref) : ref;
54255426
}
54265427
}
54275428
else if (type.flags & TypeFlags.Intersection) {
5428-
return getIntersectionType(map((<IntersectionType>type).types, t => getTypeWithThisArgument(t, thisArgument)));
5429+
return getIntersectionType(map((<IntersectionType>type).types, t => getTypeWithThisArgument(t, thisArgument, needApparentType)));
54295430
}
5430-
return type;
5431+
return needApparentType ? getApparentType(type) : type;
54315432
}
54325433

54335434
function resolveObjectTypeMembers(type: ObjectType, source: InterfaceTypeWithDeclaredMembers, typeParameters: TypeParameter[], typeArguments: Type[]) {
@@ -6107,7 +6108,7 @@ namespace ts {
61076108
}
61086109

61096110
function getApparentTypeOfIntersectionType(type: IntersectionType) {
6110-
return type.resolvedApparentType || (type.resolvedApparentType = getTypeWithThisArgument(type, type));
6111+
return type.resolvedApparentType || (type.resolvedApparentType = getTypeWithThisArgument(type, type, /*apparentType*/ true));
61116112
}
61126113

61136114
function getResolvedTypeParameterDefault(typeParameter: TypeParameter): Type | undefined {
@@ -14068,7 +14069,7 @@ namespace ts {
1406814069
// If the given type is an object or union type with a single signature, and if that signature has at
1406914070
// least as many parameters as the given function, return the signature. Otherwise return undefined.
1407014071
function getContextualCallSignature(type: Type, node: FunctionExpression | ArrowFunction | MethodDeclaration): Signature {
14071-
const signatures = getSignaturesOfStructuredType(type, SignatureKind.Call);
14072+
const signatures = getSignaturesOfType(type, SignatureKind.Call);
1407214073
if (signatures.length === 1) {
1407314074
const signature = signatures[0];
1407414075
if (!isAritySmaller(signature, node)) {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//// [intersectionOfTypeVariableHasApparentSignatures.ts]
2+
interface Component<P> {
3+
props: Readonly<P> & Readonly<{ children?: {} }>;
4+
}
5+
6+
interface Props {
7+
children?: (items: {x: number}) => void
8+
}
9+
10+
declare function f<T extends Props>(i: Component<T>): void;
11+
12+
f({
13+
props: {
14+
children: (({ x }) => { })
15+
}
16+
});
17+
18+
//// [intersectionOfTypeVariableHasApparentSignatures.js]
19+
f({
20+
props: {
21+
children: (function (_a) {
22+
var x = _a.x;
23+
})
24+
}
25+
});
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
=== tests/cases/compiler/intersectionOfTypeVariableHasApparentSignatures.ts ===
2+
interface Component<P> {
3+
>Component : Symbol(Component, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 0, 0))
4+
>P : Symbol(P, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 0, 20))
5+
6+
props: Readonly<P> & Readonly<{ children?: {} }>;
7+
>props : Symbol(Component.props, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 0, 24))
8+
>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --))
9+
>P : Symbol(P, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 0, 20))
10+
>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --))
11+
>children : Symbol(children, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 1, 35))
12+
}
13+
14+
interface Props {
15+
>Props : Symbol(Props, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 2, 1))
16+
17+
children?: (items: {x: number}) => void
18+
>children : Symbol(Props.children, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 4, 17))
19+
>items : Symbol(items, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 5, 16))
20+
>x : Symbol(x, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 5, 24))
21+
}
22+
23+
declare function f<T extends Props>(i: Component<T>): void;
24+
>f : Symbol(f, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 6, 1))
25+
>T : Symbol(T, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 8, 19))
26+
>Props : Symbol(Props, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 2, 1))
27+
>i : Symbol(i, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 8, 36))
28+
>Component : Symbol(Component, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 0, 0))
29+
>T : Symbol(T, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 8, 19))
30+
31+
f({
32+
>f : Symbol(f, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 6, 1))
33+
34+
props: {
35+
>props : Symbol(props, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 10, 3))
36+
37+
children: (({ x }) => { })
38+
>children : Symbol(children, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 11, 12))
39+
>x : Symbol(x, Decl(intersectionOfTypeVariableHasApparentSignatures.ts, 12, 21))
40+
}
41+
});
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
=== tests/cases/compiler/intersectionOfTypeVariableHasApparentSignatures.ts ===
2+
interface Component<P> {
3+
>Component : Component<P>
4+
>P : P
5+
6+
props: Readonly<P> & Readonly<{ children?: {} }>;
7+
>props : Readonly<P> & Readonly<{ children?: {} | undefined; }>
8+
>Readonly : Readonly<T>
9+
>P : P
10+
>Readonly : Readonly<T>
11+
>children : {} | undefined
12+
}
13+
14+
interface Props {
15+
>Props : Props
16+
17+
children?: (items: {x: number}) => void
18+
>children : ((items: { x: number; }) => void) | undefined
19+
>items : { x: number; }
20+
>x : number
21+
}
22+
23+
declare function f<T extends Props>(i: Component<T>): void;
24+
>f : <T extends Props>(i: Component<T>) => void
25+
>T : T
26+
>Props : Props
27+
>i : Component<T>
28+
>Component : Component<P>
29+
>T : T
30+
31+
f({
32+
>f({ props: { children: (({ x }) => { }) }}) : void
33+
>f : <T extends Props>(i: Component<T>) => void
34+
>{ props: { children: (({ x }) => { }) }} : { props: { children: ({ x }: { x: number; }) => void; }; }
35+
36+
props: {
37+
>props : { children: ({ x }: { x: number; }) => void; }
38+
>{ children: (({ x }) => { }) } : { children: ({ x }: { x: number; }) => void; }
39+
40+
children: (({ x }) => { })
41+
>children : ({ x }: { x: number; }) => void
42+
>(({ x }) => { }) : ({ x }: { x: number; }) => void
43+
>({ x }) => { } : ({ x }: { x: number; }) => void
44+
>x : number
45+
}
46+
});
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//// [jsxCallbackWithDestructuring.tsx]
2+
// minimal component
3+
interface Component<P = {}, S = {}> { }
4+
declare class Component<P, S> {
5+
constructor(props: P, context?: any);
6+
render(): {};
7+
props: Readonly<{ children?: {} }> & Readonly<P>;
8+
}
9+
10+
declare global {
11+
namespace JSX {
12+
interface Element { }
13+
interface ElementClass {
14+
render(): {};
15+
}
16+
interface ElementAttributesProperty { props: {}; }
17+
interface ElementChildrenAttribute { children: {}; }
18+
interface IntrinsicAttributes { }
19+
interface IntrinsicClassAttributes<T> { }
20+
}
21+
}
22+
23+
export interface RouteProps {
24+
children?: (props: { x: number }) => any;
25+
}
26+
export class MyComponent<T extends RouteProps = RouteProps> extends Component<T> { }
27+
<MyComponent children={({ x }) => {}}/>
28+
29+
//// [jsxCallbackWithDestructuring.jsx]
30+
"use strict";
31+
var __extends = (this && this.__extends) || (function () {
32+
var extendStatics = Object.setPrototypeOf ||
33+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
34+
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
35+
return function (d, b) {
36+
extendStatics(d, b);
37+
function __() { this.constructor = d; }
38+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
39+
};
40+
})();
41+
exports.__esModule = true;
42+
var MyComponent = /** @class */ (function (_super) {
43+
__extends(MyComponent, _super);
44+
function MyComponent() {
45+
return _super !== null && _super.apply(this, arguments) || this;
46+
}
47+
return MyComponent;
48+
}(Component));
49+
exports.MyComponent = MyComponent;
50+
<MyComponent children={function (_a) {
51+
var x = _a.x;
52+
}}/>;
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
=== tests/cases/compiler/jsxCallbackWithDestructuring.tsx ===
2+
// minimal component
3+
interface Component<P = {}, S = {}> { }
4+
>Component : Symbol(Component, Decl(jsxCallbackWithDestructuring.tsx, 0, 0), Decl(jsxCallbackWithDestructuring.tsx, 1, 39))
5+
>P : Symbol(P, Decl(jsxCallbackWithDestructuring.tsx, 1, 20), Decl(jsxCallbackWithDestructuring.tsx, 2, 24))
6+
>S : Symbol(S, Decl(jsxCallbackWithDestructuring.tsx, 1, 27), Decl(jsxCallbackWithDestructuring.tsx, 2, 26))
7+
8+
declare class Component<P, S> {
9+
>Component : Symbol(Component, Decl(jsxCallbackWithDestructuring.tsx, 0, 0), Decl(jsxCallbackWithDestructuring.tsx, 1, 39))
10+
>P : Symbol(P, Decl(jsxCallbackWithDestructuring.tsx, 1, 20), Decl(jsxCallbackWithDestructuring.tsx, 2, 24))
11+
>S : Symbol(S, Decl(jsxCallbackWithDestructuring.tsx, 1, 27), Decl(jsxCallbackWithDestructuring.tsx, 2, 26))
12+
13+
constructor(props: P, context?: any);
14+
>props : Symbol(props, Decl(jsxCallbackWithDestructuring.tsx, 3, 16))
15+
>P : Symbol(P, Decl(jsxCallbackWithDestructuring.tsx, 1, 20), Decl(jsxCallbackWithDestructuring.tsx, 2, 24))
16+
>context : Symbol(context, Decl(jsxCallbackWithDestructuring.tsx, 3, 25))
17+
18+
render(): {};
19+
>render : Symbol(Component.render, Decl(jsxCallbackWithDestructuring.tsx, 3, 41))
20+
21+
props: Readonly<{ children?: {} }> & Readonly<P>;
22+
>props : Symbol(Component.props, Decl(jsxCallbackWithDestructuring.tsx, 4, 17))
23+
>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --))
24+
>children : Symbol(children, Decl(jsxCallbackWithDestructuring.tsx, 5, 21))
25+
>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --))
26+
>P : Symbol(P, Decl(jsxCallbackWithDestructuring.tsx, 1, 20), Decl(jsxCallbackWithDestructuring.tsx, 2, 24))
27+
}
28+
29+
declare global {
30+
>global : Symbol(global, Decl(jsxCallbackWithDestructuring.tsx, 6, 1))
31+
32+
namespace JSX {
33+
>JSX : Symbol(JSX, Decl(jsxCallbackWithDestructuring.tsx, 8, 16))
34+
35+
interface Element { }
36+
>Element : Symbol(Element, Decl(jsxCallbackWithDestructuring.tsx, 9, 19))
37+
38+
interface ElementClass {
39+
>ElementClass : Symbol(ElementClass, Decl(jsxCallbackWithDestructuring.tsx, 10, 30))
40+
41+
render(): {};
42+
>render : Symbol(ElementClass.render, Decl(jsxCallbackWithDestructuring.tsx, 11, 33))
43+
}
44+
interface ElementAttributesProperty { props: {}; }
45+
>ElementAttributesProperty : Symbol(ElementAttributesProperty, Decl(jsxCallbackWithDestructuring.tsx, 13, 9))
46+
>props : Symbol(ElementAttributesProperty.props, Decl(jsxCallbackWithDestructuring.tsx, 14, 45))
47+
48+
interface ElementChildrenAttribute { children: {}; }
49+
>ElementChildrenAttribute : Symbol(ElementChildrenAttribute, Decl(jsxCallbackWithDestructuring.tsx, 14, 58))
50+
>children : Symbol(ElementChildrenAttribute.children, Decl(jsxCallbackWithDestructuring.tsx, 15, 44))
51+
52+
interface IntrinsicAttributes { }
53+
>IntrinsicAttributes : Symbol(IntrinsicAttributes, Decl(jsxCallbackWithDestructuring.tsx, 15, 60))
54+
55+
interface IntrinsicClassAttributes<T> { }
56+
>IntrinsicClassAttributes : Symbol(IntrinsicClassAttributes, Decl(jsxCallbackWithDestructuring.tsx, 16, 42))
57+
>T : Symbol(T, Decl(jsxCallbackWithDestructuring.tsx, 17, 43))
58+
}
59+
}
60+
61+
export interface RouteProps {
62+
>RouteProps : Symbol(RouteProps, Decl(jsxCallbackWithDestructuring.tsx, 19, 1))
63+
64+
children?: (props: { x: number }) => any;
65+
>children : Symbol(RouteProps.children, Decl(jsxCallbackWithDestructuring.tsx, 21, 29))
66+
>props : Symbol(props, Decl(jsxCallbackWithDestructuring.tsx, 22, 16))
67+
>x : Symbol(x, Decl(jsxCallbackWithDestructuring.tsx, 22, 24))
68+
}
69+
export class MyComponent<T extends RouteProps = RouteProps> extends Component<T> { }
70+
>MyComponent : Symbol(MyComponent, Decl(jsxCallbackWithDestructuring.tsx, 23, 1))
71+
>T : Symbol(T, Decl(jsxCallbackWithDestructuring.tsx, 24, 25))
72+
>RouteProps : Symbol(RouteProps, Decl(jsxCallbackWithDestructuring.tsx, 19, 1))
73+
>RouteProps : Symbol(RouteProps, Decl(jsxCallbackWithDestructuring.tsx, 19, 1))
74+
>Component : Symbol(Component, Decl(jsxCallbackWithDestructuring.tsx, 0, 0), Decl(jsxCallbackWithDestructuring.tsx, 1, 39))
75+
>T : Symbol(T, Decl(jsxCallbackWithDestructuring.tsx, 24, 25))
76+
77+
<MyComponent children={({ x }) => {}}/>
78+
>MyComponent : Symbol(MyComponent, Decl(jsxCallbackWithDestructuring.tsx, 23, 1))
79+
>children : Symbol(children, Decl(jsxCallbackWithDestructuring.tsx, 25, 12))
80+
>x : Symbol(x, Decl(jsxCallbackWithDestructuring.tsx, 25, 25))
81+
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
=== tests/cases/compiler/jsxCallbackWithDestructuring.tsx ===
2+
// minimal component
3+
interface Component<P = {}, S = {}> { }
4+
>Component : Component<P, S>
5+
>P : P
6+
>S : S
7+
8+
declare class Component<P, S> {
9+
>Component : Component<P, S>
10+
>P : P
11+
>S : S
12+
13+
constructor(props: P, context?: any);
14+
>props : P
15+
>P : P
16+
>context : any
17+
18+
render(): {};
19+
>render : () => {}
20+
21+
props: Readonly<{ children?: {} }> & Readonly<P>;
22+
>props : Readonly<{ children?: {} | undefined; }> & Readonly<P>
23+
>Readonly : Readonly<T>
24+
>children : {} | undefined
25+
>Readonly : Readonly<T>
26+
>P : P
27+
}
28+
29+
declare global {
30+
>global : any
31+
32+
namespace JSX {
33+
>JSX : any
34+
35+
interface Element { }
36+
>Element : Element
37+
38+
interface ElementClass {
39+
>ElementClass : ElementClass
40+
41+
render(): {};
42+
>render : () => {}
43+
}
44+
interface ElementAttributesProperty { props: {}; }
45+
>ElementAttributesProperty : ElementAttributesProperty
46+
>props : {}
47+
48+
interface ElementChildrenAttribute { children: {}; }
49+
>ElementChildrenAttribute : ElementChildrenAttribute
50+
>children : {}
51+
52+
interface IntrinsicAttributes { }
53+
>IntrinsicAttributes : IntrinsicAttributes
54+
55+
interface IntrinsicClassAttributes<T> { }
56+
>IntrinsicClassAttributes : IntrinsicClassAttributes<T>
57+
>T : T
58+
}
59+
}
60+
61+
export interface RouteProps {
62+
>RouteProps : RouteProps
63+
64+
children?: (props: { x: number }) => any;
65+
>children : ((props: { x: number; }) => any) | undefined
66+
>props : { x: number; }
67+
>x : number
68+
}
69+
export class MyComponent<T extends RouteProps = RouteProps> extends Component<T> { }
70+
>MyComponent : MyComponent<T>
71+
>T : T
72+
>RouteProps : RouteProps
73+
>RouteProps : RouteProps
74+
>Component : Component<T, {}>
75+
>T : T
76+
77+
<MyComponent children={({ x }) => {}}/>
78+
><MyComponent children={({ x }) => {}}/> : JSX.Element
79+
>MyComponent : typeof MyComponent
80+
>children : ({ x }: { x: number; }) => void
81+
>({ x }) => {} : ({ x }: { x: number; }) => void
82+
>x : number
83+

tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments4.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ tests/cases/conformance/jsx/file.tsx(9,33): error TS2322: Type '{ a: number; }'
33
Property 'b' is missing in type '{ a: number; }'.
44
tests/cases/conformance/jsx/file.tsx(10,33): error TS2322: Type 'T & { ignore-prop: true; }' is not assignable to type 'IntrinsicAttributes & { b: {}; a: {}; }'.
55
Type 'T & { ignore-prop: true; }' is not assignable to type '{ b: {}; a: {}; }'.
6-
Property 'a' is missing in type 'T & { ignore-prop: true; }'.
6+
Property 'a' is missing in type '{ b: number; } & { ignore-prop: true; }'.
77

88

99
==== 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
2424
~~~~~~~~~~~~~~~~~~~~~
2525
!!! error TS2322: Type 'T & { ignore-prop: true; }' is not assignable to type 'IntrinsicAttributes & { b: {}; a: {}; }'.
2626
!!! error TS2322: Type 'T & { ignore-prop: true; }' is not assignable to type '{ b: {}; a: {}; }'.
27-
!!! error TS2322: Property 'a' is missing in type 'T & { ignore-prop: true; }'.
27+
!!! error TS2322: Property 'a' is missing in type '{ b: number; } & { ignore-prop: true; }'.
2828
}

0 commit comments

Comments
 (0)