Add inference priority level for conditional types in contravariant positions (#35199)

* Add inference priority level for conditional types in contravariant positions

* Accept new API baselines

* Add regression tests

* Accept new baselines
This commit is contained in:
Anders Hejlsberg 2019-11-21 13:05:44 -08:00 committed by GitHub
parent 84c84d8dbc
commit 94d4023043
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 396 additions and 18 deletions

View file

@ -17552,9 +17552,12 @@ namespace ts {
inferFromTypes(getTrueTypeFromConditionalType(<ConditionalType>source), getTrueTypeFromConditionalType(<ConditionalType>target));
inferFromTypes(getFalseTypeFromConditionalType(<ConditionalType>source), getFalseTypeFromConditionalType(<ConditionalType>target));
}
else if (target.flags & TypeFlags.Conditional && !contravariant) {
else if (target.flags & TypeFlags.Conditional) {
const savePriority = priority;
priority |= contravariant ? InferencePriority.ContravariantConditional : 0;
const targetTypes = [getTrueTypeFromConditionalType(<ConditionalType>target), getFalseTypeFromConditionalType(<ConditionalType>target)];
inferToMultipleTypes(source, targetTypes, target.flags);
priority = savePriority;
}
else if (target.flags & TypeFlags.UnionOrIntersection) {
inferToMultipleTypes(source, (<UnionOrIntersectionType>target).types, target.flags);

View file

@ -4740,11 +4740,12 @@ namespace ts {
HomomorphicMappedType = 1 << 1, // Reverse inference for homomorphic mapped type
PartialHomomorphicMappedType = 1 << 2, // Partial reverse inference for homomorphic mapped type
MappedTypeConstraint = 1 << 3, // Reverse inference for mapped type
ReturnType = 1 << 4, // Inference made from return type of generic function
LiteralKeyof = 1 << 5, // Inference made from a string literal to a keyof T
NoConstraints = 1 << 6, // Don't infer from constraints of instantiable types
AlwaysStrict = 1 << 7, // Always use strict rules for contravariant inferences
MaxValue = 1 << 8, // Seed for inference priority tracking
ContravariantConditional = 1 << 4, // Conditional type in contravariant position
ReturnType = 1 << 5, // Inference made from return type of generic function
LiteralKeyof = 1 << 6, // Inference made from a string literal to a keyof T
NoConstraints = 1 << 7, // Don't infer from constraints of instantiable types
AlwaysStrict = 1 << 8, // Always use strict rules for contravariant inferences
MaxValue = 1 << 9, // Seed for inference priority tracking
PriorityImpliesCombination = ReturnType | MappedTypeConstraint | LiteralKeyof, // These priorities imply that the resulting type should be a combination of all candidates
Circularity = -1, // Inference circularity (value less than all other priorities)

View file

@ -2500,12 +2500,13 @@ declare namespace ts {
HomomorphicMappedType = 2,
PartialHomomorphicMappedType = 4,
MappedTypeConstraint = 8,
ReturnType = 16,
LiteralKeyof = 32,
NoConstraints = 64,
AlwaysStrict = 128,
MaxValue = 256,
PriorityImpliesCombination = 56,
ContravariantConditional = 16,
ReturnType = 32,
LiteralKeyof = 64,
NoConstraints = 128,
AlwaysStrict = 256,
MaxValue = 512,
PriorityImpliesCombination = 104,
Circularity = -1
}
/** @deprecated Use FileExtensionInfo instead. */

View file

@ -2500,12 +2500,13 @@ declare namespace ts {
HomomorphicMappedType = 2,
PartialHomomorphicMappedType = 4,
MappedTypeConstraint = 8,
ReturnType = 16,
LiteralKeyof = 32,
NoConstraints = 64,
AlwaysStrict = 128,
MaxValue = 256,
PriorityImpliesCombination = 56,
ContravariantConditional = 16,
ReturnType = 32,
LiteralKeyof = 64,
NoConstraints = 128,
AlwaysStrict = 256,
MaxValue = 512,
PriorityImpliesCombination = 104,
Circularity = -1
}
/** @deprecated Use FileExtensionInfo instead. */

View file

@ -273,4 +273,47 @@ tests/cases/conformance/types/conditional/conditionalTypes2.ts(75,12): error TS2
type Hmm<T, U extends T> = U extends T ? { [K in keyof U]: number } : never;
type What = Hmm<{}, { a: string }>
const w: What = { a: 4 };
// Repro from #33568
declare function save(_response: IRootResponse<string>): void;
exportCommand(save);
declare function exportCommand<TResponse>(functionToCall: IExportCallback<TResponse>): void;
interface IExportCallback<TResponse> {
(response: IRootResponse<TResponse>): void;
}
type IRootResponse<TResponse> =
TResponse extends IRecord ? IRecordResponse<TResponse> : IResponse<TResponse>;
interface IRecord {
readonly Id: string;
}
declare type IRecordResponse<T extends IRecord> = IResponse<T> & {
sendRecord(): void;
};
declare type IResponse<T> = {
sendValue(name: keyof GetAllPropertiesOfType<T, string>): void;
};
declare type GetPropertyNamesOfType<T, RestrictToType> = {
[PropertyName in Extract<keyof T, string>]: T[PropertyName] extends RestrictToType ? PropertyName : never
}[Extract<keyof T, string>];
declare type GetAllPropertiesOfType<T, RestrictToType> = Pick<
T,
GetPropertyNamesOfType<Required<T>, RestrictToType>
>;
// Repro from #33568
declare function ff(x: Foo3<string>): void;
declare function gg<T>(f: (x: Foo3<T>) => void): void;
type Foo3<T> = T extends number ? { n: T } : { x: T };
gg(ff);

View file

@ -194,6 +194,49 @@ type PCCB = ProductComplementComplement['b'];
type Hmm<T, U extends T> = U extends T ? { [K in keyof U]: number } : never;
type What = Hmm<{}, { a: string }>
const w: What = { a: 4 };
// Repro from #33568
declare function save(_response: IRootResponse<string>): void;
exportCommand(save);
declare function exportCommand<TResponse>(functionToCall: IExportCallback<TResponse>): void;
interface IExportCallback<TResponse> {
(response: IRootResponse<TResponse>): void;
}
type IRootResponse<TResponse> =
TResponse extends IRecord ? IRecordResponse<TResponse> : IResponse<TResponse>;
interface IRecord {
readonly Id: string;
}
declare type IRecordResponse<T extends IRecord> = IResponse<T> & {
sendRecord(): void;
};
declare type IResponse<T> = {
sendValue(name: keyof GetAllPropertiesOfType<T, string>): void;
};
declare type GetPropertyNamesOfType<T, RestrictToType> = {
[PropertyName in Extract<keyof T, string>]: T[PropertyName] extends RestrictToType ? PropertyName : never
}[Extract<keyof T, string>];
declare type GetAllPropertiesOfType<T, RestrictToType> = Pick<
T,
GetPropertyNamesOfType<Required<T>, RestrictToType>
>;
// Repro from #33568
declare function ff(x: Foo3<string>): void;
declare function gg<T>(f: (x: Foo3<T>) => void): void;
type Foo3<T> = T extends number ? { n: T } : { x: T };
gg(ff);
//// [conditionalTypes2.js]
@ -272,6 +315,8 @@ function foo(value) {
}
}
var w = { a: 4 };
exportCommand(save);
gg(ff);
//// [conditionalTypes2.d.ts]
@ -406,3 +451,29 @@ declare type What = Hmm<{}, {
a: string;
}>;
declare const w: What;
declare function save(_response: IRootResponse<string>): void;
declare function exportCommand<TResponse>(functionToCall: IExportCallback<TResponse>): void;
interface IExportCallback<TResponse> {
(response: IRootResponse<TResponse>): void;
}
declare type IRootResponse<TResponse> = TResponse extends IRecord ? IRecordResponse<TResponse> : IResponse<TResponse>;
interface IRecord {
readonly Id: string;
}
declare type IRecordResponse<T extends IRecord> = IResponse<T> & {
sendRecord(): void;
};
declare type IResponse<T> = {
sendValue(name: keyof GetAllPropertiesOfType<T, string>): void;
};
declare type GetPropertyNamesOfType<T, RestrictToType> = {
[PropertyName in Extract<keyof T, string>]: T[PropertyName] extends RestrictToType ? PropertyName : never;
}[Extract<keyof T, string>];
declare type GetAllPropertiesOfType<T, RestrictToType> = Pick<T, GetPropertyNamesOfType<Required<T>, RestrictToType>>;
declare function ff(x: Foo3<string>): void;
declare function gg<T>(f: (x: Foo3<T>) => void): void;
declare type Foo3<T> = T extends number ? {
n: T;
} : {
x: T;
};

View file

@ -707,3 +707,137 @@ const w: What = { a: 4 };
>What : Symbol(What, Decl(conditionalTypes2.ts, 192, 76))
>a : Symbol(a, Decl(conditionalTypes2.ts, 194, 17))
// Repro from #33568
declare function save(_response: IRootResponse<string>): void;
>save : Symbol(save, Decl(conditionalTypes2.ts, 194, 25))
>_response : Symbol(_response, Decl(conditionalTypes2.ts, 198, 22))
>IRootResponse : Symbol(IRootResponse, Decl(conditionalTypes2.ts, 206, 1))
exportCommand(save);
>exportCommand : Symbol(exportCommand, Decl(conditionalTypes2.ts, 200, 20))
>save : Symbol(save, Decl(conditionalTypes2.ts, 194, 25))
declare function exportCommand<TResponse>(functionToCall: IExportCallback<TResponse>): void;
>exportCommand : Symbol(exportCommand, Decl(conditionalTypes2.ts, 200, 20))
>TResponse : Symbol(TResponse, Decl(conditionalTypes2.ts, 202, 31))
>functionToCall : Symbol(functionToCall, Decl(conditionalTypes2.ts, 202, 42))
>IExportCallback : Symbol(IExportCallback, Decl(conditionalTypes2.ts, 202, 92))
>TResponse : Symbol(TResponse, Decl(conditionalTypes2.ts, 202, 31))
interface IExportCallback<TResponse> {
>IExportCallback : Symbol(IExportCallback, Decl(conditionalTypes2.ts, 202, 92))
>TResponse : Symbol(TResponse, Decl(conditionalTypes2.ts, 204, 26))
(response: IRootResponse<TResponse>): void;
>response : Symbol(response, Decl(conditionalTypes2.ts, 205, 2))
>IRootResponse : Symbol(IRootResponse, Decl(conditionalTypes2.ts, 206, 1))
>TResponse : Symbol(TResponse, Decl(conditionalTypes2.ts, 204, 26))
}
type IRootResponse<TResponse> =
>IRootResponse : Symbol(IRootResponse, Decl(conditionalTypes2.ts, 206, 1))
>TResponse : Symbol(TResponse, Decl(conditionalTypes2.ts, 208, 19))
TResponse extends IRecord ? IRecordResponse<TResponse> : IResponse<TResponse>;
>TResponse : Symbol(TResponse, Decl(conditionalTypes2.ts, 208, 19))
>IRecord : Symbol(IRecord, Decl(conditionalTypes2.ts, 209, 79))
>IRecordResponse : Symbol(IRecordResponse, Decl(conditionalTypes2.ts, 213, 1))
>TResponse : Symbol(TResponse, Decl(conditionalTypes2.ts, 208, 19))
>IResponse : Symbol(IResponse, Decl(conditionalTypes2.ts, 217, 2))
>TResponse : Symbol(TResponse, Decl(conditionalTypes2.ts, 208, 19))
interface IRecord {
>IRecord : Symbol(IRecord, Decl(conditionalTypes2.ts, 209, 79))
readonly Id: string;
>Id : Symbol(IRecord.Id, Decl(conditionalTypes2.ts, 211, 19))
}
declare type IRecordResponse<T extends IRecord> = IResponse<T> & {
>IRecordResponse : Symbol(IRecordResponse, Decl(conditionalTypes2.ts, 213, 1))
>T : Symbol(T, Decl(conditionalTypes2.ts, 215, 29))
>IRecord : Symbol(IRecord, Decl(conditionalTypes2.ts, 209, 79))
>IResponse : Symbol(IResponse, Decl(conditionalTypes2.ts, 217, 2))
>T : Symbol(T, Decl(conditionalTypes2.ts, 215, 29))
sendRecord(): void;
>sendRecord : Symbol(sendRecord, Decl(conditionalTypes2.ts, 215, 66))
};
declare type IResponse<T> = {
>IResponse : Symbol(IResponse, Decl(conditionalTypes2.ts, 217, 2))
>T : Symbol(T, Decl(conditionalTypes2.ts, 219, 23))
sendValue(name: keyof GetAllPropertiesOfType<T, string>): void;
>sendValue : Symbol(sendValue, Decl(conditionalTypes2.ts, 219, 29))
>name : Symbol(name, Decl(conditionalTypes2.ts, 220, 11))
>GetAllPropertiesOfType : Symbol(GetAllPropertiesOfType, Decl(conditionalTypes2.ts, 225, 28))
>T : Symbol(T, Decl(conditionalTypes2.ts, 219, 23))
};
declare type GetPropertyNamesOfType<T, RestrictToType> = {
>GetPropertyNamesOfType : Symbol(GetPropertyNamesOfType, Decl(conditionalTypes2.ts, 221, 2))
>T : Symbol(T, Decl(conditionalTypes2.ts, 223, 36))
>RestrictToType : Symbol(RestrictToType, Decl(conditionalTypes2.ts, 223, 38))
[PropertyName in Extract<keyof T, string>]: T[PropertyName] extends RestrictToType ? PropertyName : never
>PropertyName : Symbol(PropertyName, Decl(conditionalTypes2.ts, 224, 2))
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(conditionalTypes2.ts, 223, 36))
>T : Symbol(T, Decl(conditionalTypes2.ts, 223, 36))
>PropertyName : Symbol(PropertyName, Decl(conditionalTypes2.ts, 224, 2))
>RestrictToType : Symbol(RestrictToType, Decl(conditionalTypes2.ts, 223, 38))
>PropertyName : Symbol(PropertyName, Decl(conditionalTypes2.ts, 224, 2))
}[Extract<keyof T, string>];
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(conditionalTypes2.ts, 223, 36))
declare type GetAllPropertiesOfType<T, RestrictToType> = Pick<
>GetAllPropertiesOfType : Symbol(GetAllPropertiesOfType, Decl(conditionalTypes2.ts, 225, 28))
>T : Symbol(T, Decl(conditionalTypes2.ts, 227, 36))
>RestrictToType : Symbol(RestrictToType, Decl(conditionalTypes2.ts, 227, 38))
>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --))
T,
>T : Symbol(T, Decl(conditionalTypes2.ts, 227, 36))
GetPropertyNamesOfType<Required<T>, RestrictToType>
>GetPropertyNamesOfType : Symbol(GetPropertyNamesOfType, Decl(conditionalTypes2.ts, 221, 2))
>Required : Symbol(Required, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(conditionalTypes2.ts, 227, 36))
>RestrictToType : Symbol(RestrictToType, Decl(conditionalTypes2.ts, 227, 38))
>;
// Repro from #33568
declare function ff(x: Foo3<string>): void;
>ff : Symbol(ff, Decl(conditionalTypes2.ts, 230, 2))
>x : Symbol(x, Decl(conditionalTypes2.ts, 234, 20))
>Foo3 : Symbol(Foo3, Decl(conditionalTypes2.ts, 235, 54))
declare function gg<T>(f: (x: Foo3<T>) => void): void;
>gg : Symbol(gg, Decl(conditionalTypes2.ts, 234, 43))
>T : Symbol(T, Decl(conditionalTypes2.ts, 235, 20))
>f : Symbol(f, Decl(conditionalTypes2.ts, 235, 23))
>x : Symbol(x, Decl(conditionalTypes2.ts, 235, 27))
>Foo3 : Symbol(Foo3, Decl(conditionalTypes2.ts, 235, 54))
>T : Symbol(T, Decl(conditionalTypes2.ts, 235, 20))
type Foo3<T> = T extends number ? { n: T } : { x: T };
>Foo3 : Symbol(Foo3, Decl(conditionalTypes2.ts, 235, 54))
>T : Symbol(T, Decl(conditionalTypes2.ts, 236, 10))
>T : Symbol(T, Decl(conditionalTypes2.ts, 236, 10))
>n : Symbol(n, Decl(conditionalTypes2.ts, 236, 35))
>T : Symbol(T, Decl(conditionalTypes2.ts, 236, 10))
>x : Symbol(x, Decl(conditionalTypes2.ts, 236, 46))
>T : Symbol(T, Decl(conditionalTypes2.ts, 236, 10))
gg(ff);
>gg : Symbol(gg, Decl(conditionalTypes2.ts, 234, 43))
>ff : Symbol(ff, Decl(conditionalTypes2.ts, 230, 2))

View file

@ -446,3 +446,84 @@ const w: What = { a: 4 };
>a : number
>4 : 4
// Repro from #33568
declare function save(_response: IRootResponse<string>): void;
>save : (_response: IResponse<string>) => void
>_response : IResponse<string>
exportCommand(save);
>exportCommand(save) : void
>exportCommand : <TResponse>(functionToCall: IExportCallback<TResponse>) => void
>save : (_response: IResponse<string>) => void
declare function exportCommand<TResponse>(functionToCall: IExportCallback<TResponse>): void;
>exportCommand : <TResponse>(functionToCall: IExportCallback<TResponse>) => void
>functionToCall : IExportCallback<TResponse>
interface IExportCallback<TResponse> {
(response: IRootResponse<TResponse>): void;
>response : IRootResponse<TResponse>
}
type IRootResponse<TResponse> =
>IRootResponse : IRootResponse<TResponse>
TResponse extends IRecord ? IRecordResponse<TResponse> : IResponse<TResponse>;
interface IRecord {
readonly Id: string;
>Id : string
}
declare type IRecordResponse<T extends IRecord> = IResponse<T> & {
>IRecordResponse : IRecordResponse<T>
sendRecord(): void;
>sendRecord : () => void
};
declare type IResponse<T> = {
>IResponse : IResponse<T>
sendValue(name: keyof GetAllPropertiesOfType<T, string>): void;
>sendValue : (name: { [PropertyName in Extract<keyof T, string>]: Required<T>[PropertyName] extends string ? PropertyName : never; }[Extract<keyof T, string>]) => void
>name : { [PropertyName in Extract<keyof T, string>]: Required<T>[PropertyName] extends string ? PropertyName : never; }[Extract<keyof T, string>]
};
declare type GetPropertyNamesOfType<T, RestrictToType> = {
>GetPropertyNamesOfType : { [PropertyName in Extract<keyof T, string>]: T[PropertyName] extends RestrictToType ? PropertyName : never; }[Extract<keyof T, string>]
[PropertyName in Extract<keyof T, string>]: T[PropertyName] extends RestrictToType ? PropertyName : never
}[Extract<keyof T, string>];
declare type GetAllPropertiesOfType<T, RestrictToType> = Pick<
>GetAllPropertiesOfType : Pick<T, { [PropertyName in Extract<keyof T, string>]: Required<T>[PropertyName] extends RestrictToType ? PropertyName : never; }[Extract<keyof T, string>]>
T,
GetPropertyNamesOfType<Required<T>, RestrictToType>
>;
// Repro from #33568
declare function ff(x: Foo3<string>): void;
>ff : (x: { x: string; }) => void
>x : { x: string; }
declare function gg<T>(f: (x: Foo3<T>) => void): void;
>gg : <T>(f: (x: Foo3<T>) => void) => void
>f : (x: Foo3<T>) => void
>x : Foo3<T>
type Foo3<T> = T extends number ? { n: T } : { x: T };
>Foo3 : Foo3<T>
>n : T
>x : T
gg(ff);
>gg(ff) : void
>gg : <T>(f: (x: Foo3<T>) => void) => void
>ff : (x: { x: string; }) => void

View file

@ -196,3 +196,46 @@ type PCCB = ProductComplementComplement['b'];
type Hmm<T, U extends T> = U extends T ? { [K in keyof U]: number } : never;
type What = Hmm<{}, { a: string }>
const w: What = { a: 4 };
// Repro from #33568
declare function save(_response: IRootResponse<string>): void;
exportCommand(save);
declare function exportCommand<TResponse>(functionToCall: IExportCallback<TResponse>): void;
interface IExportCallback<TResponse> {
(response: IRootResponse<TResponse>): void;
}
type IRootResponse<TResponse> =
TResponse extends IRecord ? IRecordResponse<TResponse> : IResponse<TResponse>;
interface IRecord {
readonly Id: string;
}
declare type IRecordResponse<T extends IRecord> = IResponse<T> & {
sendRecord(): void;
};
declare type IResponse<T> = {
sendValue(name: keyof GetAllPropertiesOfType<T, string>): void;
};
declare type GetPropertyNamesOfType<T, RestrictToType> = {
[PropertyName in Extract<keyof T, string>]: T[PropertyName] extends RestrictToType ? PropertyName : never
}[Extract<keyof T, string>];
declare type GetAllPropertiesOfType<T, RestrictToType> = Pick<
T,
GetPropertyNamesOfType<Required<T>, RestrictToType>
>;
// Repro from #33568
declare function ff(x: Foo3<string>): void;
declare function gg<T>(f: (x: Foo3<T>) => void): void;
type Foo3<T> = T extends number ? { n: T } : { x: T };
gg(ff);