Skip to content

Commit b78ef30

Browse files
authored
No union subtype reduction during type inference (#37327)
* No union type subtype reduction in getImplicitIndexTypeOfType * Add regression test
1 parent 505e7fb commit b78ef30

File tree

5 files changed

+255
-1
lines changed

5 files changed

+255
-1
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10465,7 +10465,7 @@ namespace ts {
1046510465
append(propTypes, getIndexTypeOfType(type, IndexKind.Number));
1046610466
}
1046710467
if (propTypes.length) {
10468-
return getUnionType(propTypes, UnionReduction.Subtype);
10468+
return getUnionType(propTypes);
1046910469
}
1047010470
}
1047110471
return undefined;
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//// [tests/cases/compiler/inferrenceInfiniteLoopWithSubtyping.ts] ////
2+
3+
//// [graphql-compose.d.ts]
4+
export type ObjMapReadOnly<T> = Readonly<{ [key: string]: Readonly<T> }>;
5+
export type Thunk<T> = (() => T) | T;
6+
7+
export type ComposeOutputTypeDefinition = Readonly<ObjectTypeComposer<any, any> | EnumTypeComposer>;
8+
9+
export class EnumTypeComposer {
10+
public setFields(fields: { [name: string]: { [key: string]: any } }): this;
11+
}
12+
13+
export class ObjectTypeComposer<TSource, TContext> {
14+
public setFields(fields: ObjMapReadOnly<Resolver>): this;
15+
16+
public addResolver<TResolverSource>(opts: { type?: Thunk<ComposeOutputTypeDefinition> }): this;
17+
}
18+
19+
export class Resolver {
20+
public wrapArgs<NewContext>(
21+
cb: () => {
22+
[argName: string]: Thunk<Readonly<EnumTypeComposer>>;
23+
}
24+
): void;
25+
26+
public wrapType(cb: () => ComposeOutputTypeDefinition): void;
27+
}
28+
29+
30+
//// [app.ts]
31+
import { ObjectTypeComposer } from './graphql-compose';
32+
33+
declare const User: ObjectTypeComposer<any, any>;
34+
35+
User.addResolver({
36+
type: User, // `User as any` fix the problem
37+
});
38+
39+
40+
//// [app.js]
41+
"use strict";
42+
exports.__esModule = true;
43+
User.addResolver({
44+
type: User
45+
});
46+
47+
48+
//// [app.d.ts]
49+
export {};
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
=== tests/cases/compiler/graphql-compose.d.ts ===
2+
export type ObjMapReadOnly<T> = Readonly<{ [key: string]: Readonly<T> }>;
3+
>ObjMapReadOnly : Symbol(ObjMapReadOnly, Decl(graphql-compose.d.ts, 0, 0))
4+
>T : Symbol(T, Decl(graphql-compose.d.ts, 0, 27))
5+
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
6+
>key : Symbol(key, Decl(graphql-compose.d.ts, 0, 44))
7+
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
8+
>T : Symbol(T, Decl(graphql-compose.d.ts, 0, 27))
9+
10+
export type Thunk<T> = (() => T) | T;
11+
>Thunk : Symbol(Thunk, Decl(graphql-compose.d.ts, 0, 73))
12+
>T : Symbol(T, Decl(graphql-compose.d.ts, 1, 18))
13+
>T : Symbol(T, Decl(graphql-compose.d.ts, 1, 18))
14+
>T : Symbol(T, Decl(graphql-compose.d.ts, 1, 18))
15+
16+
export type ComposeOutputTypeDefinition = Readonly<ObjectTypeComposer<any, any> | EnumTypeComposer>;
17+
>ComposeOutputTypeDefinition : Symbol(ComposeOutputTypeDefinition, Decl(graphql-compose.d.ts, 1, 37))
18+
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
19+
>ObjectTypeComposer : Symbol(ObjectTypeComposer, Decl(graphql-compose.d.ts, 7, 1))
20+
>EnumTypeComposer : Symbol(EnumTypeComposer, Decl(graphql-compose.d.ts, 3, 100))
21+
22+
export class EnumTypeComposer {
23+
>EnumTypeComposer : Symbol(EnumTypeComposer, Decl(graphql-compose.d.ts, 3, 100))
24+
25+
public setFields(fields: { [name: string]: { [key: string]: any } }): this;
26+
>setFields : Symbol(EnumTypeComposer.setFields, Decl(graphql-compose.d.ts, 5, 31))
27+
>fields : Symbol(fields, Decl(graphql-compose.d.ts, 6, 19))
28+
>name : Symbol(name, Decl(graphql-compose.d.ts, 6, 30))
29+
>key : Symbol(key, Decl(graphql-compose.d.ts, 6, 48))
30+
}
31+
32+
export class ObjectTypeComposer<TSource, TContext> {
33+
>ObjectTypeComposer : Symbol(ObjectTypeComposer, Decl(graphql-compose.d.ts, 7, 1))
34+
>TSource : Symbol(TSource, Decl(graphql-compose.d.ts, 9, 32))
35+
>TContext : Symbol(TContext, Decl(graphql-compose.d.ts, 9, 40))
36+
37+
public setFields(fields: ObjMapReadOnly<Resolver>): this;
38+
>setFields : Symbol(ObjectTypeComposer.setFields, Decl(graphql-compose.d.ts, 9, 52))
39+
>fields : Symbol(fields, Decl(graphql-compose.d.ts, 10, 19))
40+
>ObjMapReadOnly : Symbol(ObjMapReadOnly, Decl(graphql-compose.d.ts, 0, 0))
41+
>Resolver : Symbol(Resolver, Decl(graphql-compose.d.ts, 13, 1))
42+
43+
public addResolver<TResolverSource>(opts: { type?: Thunk<ComposeOutputTypeDefinition> }): this;
44+
>addResolver : Symbol(ObjectTypeComposer.addResolver, Decl(graphql-compose.d.ts, 10, 59))
45+
>TResolverSource : Symbol(TResolverSource, Decl(graphql-compose.d.ts, 12, 21))
46+
>opts : Symbol(opts, Decl(graphql-compose.d.ts, 12, 38))
47+
>type : Symbol(type, Decl(graphql-compose.d.ts, 12, 45))
48+
>Thunk : Symbol(Thunk, Decl(graphql-compose.d.ts, 0, 73))
49+
>ComposeOutputTypeDefinition : Symbol(ComposeOutputTypeDefinition, Decl(graphql-compose.d.ts, 1, 37))
50+
}
51+
52+
export class Resolver {
53+
>Resolver : Symbol(Resolver, Decl(graphql-compose.d.ts, 13, 1))
54+
55+
public wrapArgs<NewContext>(
56+
>wrapArgs : Symbol(Resolver.wrapArgs, Decl(graphql-compose.d.ts, 15, 23))
57+
>NewContext : Symbol(NewContext, Decl(graphql-compose.d.ts, 16, 18))
58+
59+
cb: () => {
60+
>cb : Symbol(cb, Decl(graphql-compose.d.ts, 16, 30))
61+
62+
[argName: string]: Thunk<Readonly<EnumTypeComposer>>;
63+
>argName : Symbol(argName, Decl(graphql-compose.d.ts, 18, 7))
64+
>Thunk : Symbol(Thunk, Decl(graphql-compose.d.ts, 0, 73))
65+
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
66+
>EnumTypeComposer : Symbol(EnumTypeComposer, Decl(graphql-compose.d.ts, 3, 100))
67+
}
68+
): void;
69+
70+
public wrapType(cb: () => ComposeOutputTypeDefinition): void;
71+
>wrapType : Symbol(Resolver.wrapType, Decl(graphql-compose.d.ts, 20, 10))
72+
>cb : Symbol(cb, Decl(graphql-compose.d.ts, 22, 18))
73+
>ComposeOutputTypeDefinition : Symbol(ComposeOutputTypeDefinition, Decl(graphql-compose.d.ts, 1, 37))
74+
}
75+
76+
77+
=== tests/cases/compiler/app.ts ===
78+
import { ObjectTypeComposer } from './graphql-compose';
79+
>ObjectTypeComposer : Symbol(ObjectTypeComposer, Decl(app.ts, 0, 8))
80+
81+
declare const User: ObjectTypeComposer<any, any>;
82+
>User : Symbol(User, Decl(app.ts, 2, 13))
83+
>ObjectTypeComposer : Symbol(ObjectTypeComposer, Decl(app.ts, 0, 8))
84+
85+
User.addResolver({
86+
>User.addResolver : Symbol(ObjectTypeComposer.addResolver, Decl(graphql-compose.d.ts, 10, 59))
87+
>User : Symbol(User, Decl(app.ts, 2, 13))
88+
>addResolver : Symbol(ObjectTypeComposer.addResolver, Decl(graphql-compose.d.ts, 10, 59))
89+
90+
type: User, // `User as any` fix the problem
91+
>type : Symbol(type, Decl(app.ts, 4, 18))
92+
>User : Symbol(User, Decl(app.ts, 2, 13))
93+
94+
});
95+
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
=== tests/cases/compiler/graphql-compose.d.ts ===
2+
export type ObjMapReadOnly<T> = Readonly<{ [key: string]: Readonly<T> }>;
3+
>ObjMapReadOnly : Readonly<{ [key: string]: Readonly<T>; }>
4+
>key : string
5+
6+
export type Thunk<T> = (() => T) | T;
7+
>Thunk : Thunk<T>
8+
9+
export type ComposeOutputTypeDefinition = Readonly<ObjectTypeComposer<any, any> | EnumTypeComposer>;
10+
>ComposeOutputTypeDefinition : Readonly<ObjectTypeComposer<any, any>> | Readonly<EnumTypeComposer>
11+
12+
export class EnumTypeComposer {
13+
>EnumTypeComposer : EnumTypeComposer
14+
15+
public setFields(fields: { [name: string]: { [key: string]: any } }): this;
16+
>setFields : (fields: { [name: string]: { [key: string]: any; }; }) => this
17+
>fields : { [name: string]: { [key: string]: any; }; }
18+
>name : string
19+
>key : string
20+
}
21+
22+
export class ObjectTypeComposer<TSource, TContext> {
23+
>ObjectTypeComposer : ObjectTypeComposer<TSource, TContext>
24+
25+
public setFields(fields: ObjMapReadOnly<Resolver>): this;
26+
>setFields : (fields: Readonly<{ [key: string]: Readonly<Resolver>; }>) => this
27+
>fields : Readonly<{ [key: string]: Readonly<Resolver>; }>
28+
29+
public addResolver<TResolverSource>(opts: { type?: Thunk<ComposeOutputTypeDefinition> }): this;
30+
>addResolver : <TResolverSource>(opts: { type?: Thunk<Readonly<ObjectTypeComposer<any, any>> | Readonly<EnumTypeComposer>>; }) => this
31+
>opts : { type?: Thunk<Readonly<ObjectTypeComposer<any, any>> | Readonly<EnumTypeComposer>>; }
32+
>type : Thunk<Readonly<ObjectTypeComposer<any, any>> | Readonly<EnumTypeComposer>>
33+
}
34+
35+
export class Resolver {
36+
>Resolver : Resolver
37+
38+
public wrapArgs<NewContext>(
39+
>wrapArgs : <NewContext>(cb: () => { [argName: string]: Thunk<Readonly<EnumTypeComposer>>; }) => void
40+
41+
cb: () => {
42+
>cb : () => { [argName: string]: Thunk<Readonly<EnumTypeComposer>>; }
43+
44+
[argName: string]: Thunk<Readonly<EnumTypeComposer>>;
45+
>argName : string
46+
}
47+
): void;
48+
49+
public wrapType(cb: () => ComposeOutputTypeDefinition): void;
50+
>wrapType : (cb: () => Readonly<ObjectTypeComposer<any, any>> | Readonly<EnumTypeComposer>) => void
51+
>cb : () => Readonly<ObjectTypeComposer<any, any>> | Readonly<EnumTypeComposer>
52+
}
53+
54+
55+
=== tests/cases/compiler/app.ts ===
56+
import { ObjectTypeComposer } from './graphql-compose';
57+
>ObjectTypeComposer : typeof ObjectTypeComposer
58+
59+
declare const User: ObjectTypeComposer<any, any>;
60+
>User : ObjectTypeComposer<any, any>
61+
62+
User.addResolver({
63+
>User.addResolver({ type: User, // `User as any` fix the problem}) : ObjectTypeComposer<any, any>
64+
>User.addResolver : <TResolverSource>(opts: { type?: import("tests/cases/compiler/graphql-compose").Thunk<Readonly<ObjectTypeComposer<any, any>> | Readonly<import("tests/cases/compiler/graphql-compose").EnumTypeComposer>>; }) => ObjectTypeComposer<any, any>
65+
>User : ObjectTypeComposer<any, any>
66+
>addResolver : <TResolverSource>(opts: { type?: import("tests/cases/compiler/graphql-compose").Thunk<Readonly<ObjectTypeComposer<any, any>> | Readonly<import("tests/cases/compiler/graphql-compose").EnumTypeComposer>>; }) => ObjectTypeComposer<any, any>
67+
>{ type: User, // `User as any` fix the problem} : { type: ObjectTypeComposer<any, any>; }
68+
69+
type: User, // `User as any` fix the problem
70+
>type : ObjectTypeComposer<any, any>
71+
>User : ObjectTypeComposer<any, any>
72+
73+
});
74+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// @filename: graphql-compose.d.ts
2+
// @declaration: true
3+
export type ObjMapReadOnly<T> = Readonly<{ [key: string]: Readonly<T> }>;
4+
export type Thunk<T> = (() => T) | T;
5+
6+
export type ComposeOutputTypeDefinition = Readonly<ObjectTypeComposer<any, any> | EnumTypeComposer>;
7+
8+
export class EnumTypeComposer {
9+
public setFields(fields: { [name: string]: { [key: string]: any } }): this;
10+
}
11+
12+
export class ObjectTypeComposer<TSource, TContext> {
13+
public setFields(fields: ObjMapReadOnly<Resolver>): this;
14+
15+
public addResolver<TResolverSource>(opts: { type?: Thunk<ComposeOutputTypeDefinition> }): this;
16+
}
17+
18+
export class Resolver {
19+
public wrapArgs<NewContext>(
20+
cb: () => {
21+
[argName: string]: Thunk<Readonly<EnumTypeComposer>>;
22+
}
23+
): void;
24+
25+
public wrapType(cb: () => ComposeOutputTypeDefinition): void;
26+
}
27+
28+
29+
// @filename: app.ts
30+
import { ObjectTypeComposer } from './graphql-compose';
31+
32+
declare const User: ObjectTypeComposer<any, any>;
33+
34+
User.addResolver({
35+
type: User, // `User as any` fix the problem
36+
});

0 commit comments

Comments
 (0)