No union subtype reduction during type inference (#37327)

* No union type subtype reduction in getImplicitIndexTypeOfType

* Add regression test
This commit is contained in:
Anders Hejlsberg 2020-03-11 10:27:51 -07:00 committed by GitHub
parent 505e7fb5d9
commit b78ef30cb7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 255 additions and 1 deletions

View File

@ -10465,7 +10465,7 @@ namespace ts {
append(propTypes, getIndexTypeOfType(type, IndexKind.Number));
}
if (propTypes.length) {
return getUnionType(propTypes, UnionReduction.Subtype);
return getUnionType(propTypes);
}
}
return undefined;

View File

@ -0,0 +1,49 @@
//// [tests/cases/compiler/inferrenceInfiniteLoopWithSubtyping.ts] ////
//// [graphql-compose.d.ts]
export type ObjMapReadOnly<T> = Readonly<{ [key: string]: Readonly<T> }>;
export type Thunk<T> = (() => T) | T;
export type ComposeOutputTypeDefinition = Readonly<ObjectTypeComposer<any, any> | EnumTypeComposer>;
export class EnumTypeComposer {
public setFields(fields: { [name: string]: { [key: string]: any } }): this;
}
export class ObjectTypeComposer<TSource, TContext> {
public setFields(fields: ObjMapReadOnly<Resolver>): this;
public addResolver<TResolverSource>(opts: { type?: Thunk<ComposeOutputTypeDefinition> }): this;
}
export class Resolver {
public wrapArgs<NewContext>(
cb: () => {
[argName: string]: Thunk<Readonly<EnumTypeComposer>>;
}
): void;
public wrapType(cb: () => ComposeOutputTypeDefinition): void;
}
//// [app.ts]
import { ObjectTypeComposer } from './graphql-compose';
declare const User: ObjectTypeComposer<any, any>;
User.addResolver({
type: User, // `User as any` fix the problem
});
//// [app.js]
"use strict";
exports.__esModule = true;
User.addResolver({
type: User
});
//// [app.d.ts]
export {};

View File

@ -0,0 +1,95 @@
=== tests/cases/compiler/graphql-compose.d.ts ===
export type ObjMapReadOnly<T> = Readonly<{ [key: string]: Readonly<T> }>;
>ObjMapReadOnly : Symbol(ObjMapReadOnly, Decl(graphql-compose.d.ts, 0, 0))
>T : Symbol(T, Decl(graphql-compose.d.ts, 0, 27))
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
>key : Symbol(key, Decl(graphql-compose.d.ts, 0, 44))
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(graphql-compose.d.ts, 0, 27))
export type Thunk<T> = (() => T) | T;
>Thunk : Symbol(Thunk, Decl(graphql-compose.d.ts, 0, 73))
>T : Symbol(T, Decl(graphql-compose.d.ts, 1, 18))
>T : Symbol(T, Decl(graphql-compose.d.ts, 1, 18))
>T : Symbol(T, Decl(graphql-compose.d.ts, 1, 18))
export type ComposeOutputTypeDefinition = Readonly<ObjectTypeComposer<any, any> | EnumTypeComposer>;
>ComposeOutputTypeDefinition : Symbol(ComposeOutputTypeDefinition, Decl(graphql-compose.d.ts, 1, 37))
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
>ObjectTypeComposer : Symbol(ObjectTypeComposer, Decl(graphql-compose.d.ts, 7, 1))
>EnumTypeComposer : Symbol(EnumTypeComposer, Decl(graphql-compose.d.ts, 3, 100))
export class EnumTypeComposer {
>EnumTypeComposer : Symbol(EnumTypeComposer, Decl(graphql-compose.d.ts, 3, 100))
public setFields(fields: { [name: string]: { [key: string]: any } }): this;
>setFields : Symbol(EnumTypeComposer.setFields, Decl(graphql-compose.d.ts, 5, 31))
>fields : Symbol(fields, Decl(graphql-compose.d.ts, 6, 19))
>name : Symbol(name, Decl(graphql-compose.d.ts, 6, 30))
>key : Symbol(key, Decl(graphql-compose.d.ts, 6, 48))
}
export class ObjectTypeComposer<TSource, TContext> {
>ObjectTypeComposer : Symbol(ObjectTypeComposer, Decl(graphql-compose.d.ts, 7, 1))
>TSource : Symbol(TSource, Decl(graphql-compose.d.ts, 9, 32))
>TContext : Symbol(TContext, Decl(graphql-compose.d.ts, 9, 40))
public setFields(fields: ObjMapReadOnly<Resolver>): this;
>setFields : Symbol(ObjectTypeComposer.setFields, Decl(graphql-compose.d.ts, 9, 52))
>fields : Symbol(fields, Decl(graphql-compose.d.ts, 10, 19))
>ObjMapReadOnly : Symbol(ObjMapReadOnly, Decl(graphql-compose.d.ts, 0, 0))
>Resolver : Symbol(Resolver, Decl(graphql-compose.d.ts, 13, 1))
public addResolver<TResolverSource>(opts: { type?: Thunk<ComposeOutputTypeDefinition> }): this;
>addResolver : Symbol(ObjectTypeComposer.addResolver, Decl(graphql-compose.d.ts, 10, 59))
>TResolverSource : Symbol(TResolverSource, Decl(graphql-compose.d.ts, 12, 21))
>opts : Symbol(opts, Decl(graphql-compose.d.ts, 12, 38))
>type : Symbol(type, Decl(graphql-compose.d.ts, 12, 45))
>Thunk : Symbol(Thunk, Decl(graphql-compose.d.ts, 0, 73))
>ComposeOutputTypeDefinition : Symbol(ComposeOutputTypeDefinition, Decl(graphql-compose.d.ts, 1, 37))
}
export class Resolver {
>Resolver : Symbol(Resolver, Decl(graphql-compose.d.ts, 13, 1))
public wrapArgs<NewContext>(
>wrapArgs : Symbol(Resolver.wrapArgs, Decl(graphql-compose.d.ts, 15, 23))
>NewContext : Symbol(NewContext, Decl(graphql-compose.d.ts, 16, 18))
cb: () => {
>cb : Symbol(cb, Decl(graphql-compose.d.ts, 16, 30))
[argName: string]: Thunk<Readonly<EnumTypeComposer>>;
>argName : Symbol(argName, Decl(graphql-compose.d.ts, 18, 7))
>Thunk : Symbol(Thunk, Decl(graphql-compose.d.ts, 0, 73))
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
>EnumTypeComposer : Symbol(EnumTypeComposer, Decl(graphql-compose.d.ts, 3, 100))
}
): void;
public wrapType(cb: () => ComposeOutputTypeDefinition): void;
>wrapType : Symbol(Resolver.wrapType, Decl(graphql-compose.d.ts, 20, 10))
>cb : Symbol(cb, Decl(graphql-compose.d.ts, 22, 18))
>ComposeOutputTypeDefinition : Symbol(ComposeOutputTypeDefinition, Decl(graphql-compose.d.ts, 1, 37))
}
=== tests/cases/compiler/app.ts ===
import { ObjectTypeComposer } from './graphql-compose';
>ObjectTypeComposer : Symbol(ObjectTypeComposer, Decl(app.ts, 0, 8))
declare const User: ObjectTypeComposer<any, any>;
>User : Symbol(User, Decl(app.ts, 2, 13))
>ObjectTypeComposer : Symbol(ObjectTypeComposer, Decl(app.ts, 0, 8))
User.addResolver({
>User.addResolver : Symbol(ObjectTypeComposer.addResolver, Decl(graphql-compose.d.ts, 10, 59))
>User : Symbol(User, Decl(app.ts, 2, 13))
>addResolver : Symbol(ObjectTypeComposer.addResolver, Decl(graphql-compose.d.ts, 10, 59))
type: User, // `User as any` fix the problem
>type : Symbol(type, Decl(app.ts, 4, 18))
>User : Symbol(User, Decl(app.ts, 2, 13))
});

View File

@ -0,0 +1,74 @@
=== tests/cases/compiler/graphql-compose.d.ts ===
export type ObjMapReadOnly<T> = Readonly<{ [key: string]: Readonly<T> }>;
>ObjMapReadOnly : Readonly<{ [key: string]: Readonly<T>; }>
>key : string
export type Thunk<T> = (() => T) | T;
>Thunk : Thunk<T>
export type ComposeOutputTypeDefinition = Readonly<ObjectTypeComposer<any, any> | EnumTypeComposer>;
>ComposeOutputTypeDefinition : Readonly<ObjectTypeComposer<any, any>> | Readonly<EnumTypeComposer>
export class EnumTypeComposer {
>EnumTypeComposer : EnumTypeComposer
public setFields(fields: { [name: string]: { [key: string]: any } }): this;
>setFields : (fields: { [name: string]: { [key: string]: any; }; }) => this
>fields : { [name: string]: { [key: string]: any; }; }
>name : string
>key : string
}
export class ObjectTypeComposer<TSource, TContext> {
>ObjectTypeComposer : ObjectTypeComposer<TSource, TContext>
public setFields(fields: ObjMapReadOnly<Resolver>): this;
>setFields : (fields: Readonly<{ [key: string]: Readonly<Resolver>; }>) => this
>fields : Readonly<{ [key: string]: Readonly<Resolver>; }>
public addResolver<TResolverSource>(opts: { type?: Thunk<ComposeOutputTypeDefinition> }): this;
>addResolver : <TResolverSource>(opts: { type?: Thunk<Readonly<ObjectTypeComposer<any, any>> | Readonly<EnumTypeComposer>>; }) => this
>opts : { type?: Thunk<Readonly<ObjectTypeComposer<any, any>> | Readonly<EnumTypeComposer>>; }
>type : Thunk<Readonly<ObjectTypeComposer<any, any>> | Readonly<EnumTypeComposer>>
}
export class Resolver {
>Resolver : Resolver
public wrapArgs<NewContext>(
>wrapArgs : <NewContext>(cb: () => { [argName: string]: Thunk<Readonly<EnumTypeComposer>>; }) => void
cb: () => {
>cb : () => { [argName: string]: Thunk<Readonly<EnumTypeComposer>>; }
[argName: string]: Thunk<Readonly<EnumTypeComposer>>;
>argName : string
}
): void;
public wrapType(cb: () => ComposeOutputTypeDefinition): void;
>wrapType : (cb: () => Readonly<ObjectTypeComposer<any, any>> | Readonly<EnumTypeComposer>) => void
>cb : () => Readonly<ObjectTypeComposer<any, any>> | Readonly<EnumTypeComposer>
}
=== tests/cases/compiler/app.ts ===
import { ObjectTypeComposer } from './graphql-compose';
>ObjectTypeComposer : typeof ObjectTypeComposer
declare const User: ObjectTypeComposer<any, any>;
>User : ObjectTypeComposer<any, any>
User.addResolver({
>User.addResolver({ type: User, // `User as any` fix the problem}) : ObjectTypeComposer<any, any>
>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>
>User : ObjectTypeComposer<any, any>
>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>
>{ type: User, // `User as any` fix the problem} : { type: ObjectTypeComposer<any, any>; }
type: User, // `User as any` fix the problem
>type : ObjectTypeComposer<any, any>
>User : ObjectTypeComposer<any, any>
});

View File

@ -0,0 +1,36 @@
// @filename: graphql-compose.d.ts
// @declaration: true
export type ObjMapReadOnly<T> = Readonly<{ [key: string]: Readonly<T> }>;
export type Thunk<T> = (() => T) | T;
export type ComposeOutputTypeDefinition = Readonly<ObjectTypeComposer<any, any> | EnumTypeComposer>;
export class EnumTypeComposer {
public setFields(fields: { [name: string]: { [key: string]: any } }): this;
}
export class ObjectTypeComposer<TSource, TContext> {
public setFields(fields: ObjMapReadOnly<Resolver>): this;
public addResolver<TResolverSource>(opts: { type?: Thunk<ComposeOutputTypeDefinition> }): this;
}
export class Resolver {
public wrapArgs<NewContext>(
cb: () => {
[argName: string]: Thunk<Readonly<EnumTypeComposer>>;
}
): void;
public wrapType(cb: () => ComposeOutputTypeDefinition): void;
}
// @filename: app.ts
import { ObjectTypeComposer } from './graphql-compose';
declare const User: ObjectTypeComposer<any, any>;
User.addResolver({
type: User, // `User as any` fix the problem
});