mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 12:51:30 -05:00
Merge pull request #28851 from Microsoft/deferConditionalTypes
Defer resolution of conditional types with generic check or extends types
This commit is contained in:
@@ -9785,14 +9785,11 @@ namespace ts {
|
||||
if (checkType === wildcardType || extendsType === wildcardType) {
|
||||
return wildcardType;
|
||||
}
|
||||
// If this is a distributive conditional type and the check type is generic we need to defer
|
||||
// resolution of the conditional type such that a later instantiation will properly distribute
|
||||
// over union types.
|
||||
const isDeferred = root.isDistributive && maybeTypeOfKind(checkType, TypeFlags.Instantiable);
|
||||
const checkTypeInstantiable = maybeTypeOfKind(checkType, TypeFlags.Instantiable);
|
||||
let combinedMapper: TypeMapper | undefined;
|
||||
if (root.inferTypeParameters) {
|
||||
const context = createInferenceContext(root.inferTypeParameters, /*signature*/ undefined, InferenceFlags.None);
|
||||
if (!isDeferred) {
|
||||
if (!checkTypeInstantiable) {
|
||||
// We don't want inferences from constraints as they may cause us to eagerly resolve the
|
||||
// conditional type instead of deferring resolution. Also, we always want strict function
|
||||
// types rules (i.e. proper contravariance) for inferences.
|
||||
@@ -9800,16 +9797,17 @@ namespace ts {
|
||||
}
|
||||
combinedMapper = combineTypeMappers(mapper, context);
|
||||
}
|
||||
if (!isDeferred) {
|
||||
if (extendsType.flags & TypeFlags.AnyOrUnknown) {
|
||||
// Instantiate the extends type including inferences for 'infer T' type parameters
|
||||
const inferredExtendsType = combinedMapper ? instantiateType(root.extendsType, combinedMapper) : extendsType;
|
||||
// We attempt to resolve the conditional type only when the check and extends types are non-generic
|
||||
if (!checkTypeInstantiable && !maybeTypeOfKind(inferredExtendsType, TypeFlags.Instantiable)) {
|
||||
if (inferredExtendsType.flags & TypeFlags.AnyOrUnknown) {
|
||||
return instantiateType(root.trueType, mapper);
|
||||
}
|
||||
// Return union of trueType and falseType for 'any' since it matches anything
|
||||
if (checkType.flags & TypeFlags.Any) {
|
||||
return getUnionType([instantiateType(root.trueType, combinedMapper || mapper), instantiateType(root.falseType, mapper)]);
|
||||
}
|
||||
// Instantiate the extends type including inferences for 'infer T' type parameters
|
||||
const inferredExtendsType = combinedMapper ? instantiateType(root.extendsType, combinedMapper) : extendsType;
|
||||
// Return falseType for a definitely false extends check. We check an instantations of the two
|
||||
// types with type parameters mapped to the wildcard type, the most permissive instantiations
|
||||
// possible (the wildcard type is assignable to and from all types). If those are not related,
|
||||
|
||||
@@ -212,4 +212,38 @@ tests/cases/conformance/types/conditional/conditionalTypes2.ts(75,12): error TS2
|
||||
type T1 = MaybeTrue<{ b: false }>; // "no"
|
||||
type T2 = MaybeTrue<{ b: true }>; // "yes"
|
||||
type T3 = MaybeTrue<{ b: boolean }>; // "yes"
|
||||
|
||||
// Repro from #28824
|
||||
|
||||
type Union = 'a' | 'b';
|
||||
type Product<A extends Union, B> = { f1: A, f2: B};
|
||||
type ProductUnion = Product<'a', 0> | Product<'b', 1>;
|
||||
|
||||
// {a: "b"; b: "a"}
|
||||
type UnionComplement = {
|
||||
[K in Union]: Exclude<Union, K>
|
||||
};
|
||||
type UCA = UnionComplement['a'];
|
||||
type UCB = UnionComplement['b'];
|
||||
|
||||
// {a: "a"; b: "b"}
|
||||
type UnionComplementComplement = {
|
||||
[K in Union]: Exclude<Union, Exclude<Union, K>>
|
||||
};
|
||||
type UCCA = UnionComplementComplement['a'];
|
||||
type UCCB = UnionComplementComplement['b'];
|
||||
|
||||
// {a: Product<'b', 1>; b: Product<'a', 0>}
|
||||
type ProductComplement = {
|
||||
[K in Union]: Exclude<ProductUnion, { f1: K }>
|
||||
};
|
||||
type PCA = ProductComplement['a'];
|
||||
type PCB = ProductComplement['b'];
|
||||
|
||||
// {a: Product<'a', 0>; b: Product<'b', 1>}
|
||||
type ProductComplementComplement = {
|
||||
[K in Union]: Exclude<ProductUnion, Exclude<ProductUnion, { f1: K }>>
|
||||
};
|
||||
type PCCA = ProductComplementComplement['a'];
|
||||
type PCCB = ProductComplementComplement['b'];
|
||||
|
||||
@@ -154,6 +154,40 @@ type T0 = MaybeTrue<{ b: never }> // "no"
|
||||
type T1 = MaybeTrue<{ b: false }>; // "no"
|
||||
type T2 = MaybeTrue<{ b: true }>; // "yes"
|
||||
type T3 = MaybeTrue<{ b: boolean }>; // "yes"
|
||||
|
||||
// Repro from #28824
|
||||
|
||||
type Union = 'a' | 'b';
|
||||
type Product<A extends Union, B> = { f1: A, f2: B};
|
||||
type ProductUnion = Product<'a', 0> | Product<'b', 1>;
|
||||
|
||||
// {a: "b"; b: "a"}
|
||||
type UnionComplement = {
|
||||
[K in Union]: Exclude<Union, K>
|
||||
};
|
||||
type UCA = UnionComplement['a'];
|
||||
type UCB = UnionComplement['b'];
|
||||
|
||||
// {a: "a"; b: "b"}
|
||||
type UnionComplementComplement = {
|
||||
[K in Union]: Exclude<Union, Exclude<Union, K>>
|
||||
};
|
||||
type UCCA = UnionComplementComplement['a'];
|
||||
type UCCB = UnionComplementComplement['b'];
|
||||
|
||||
// {a: Product<'b', 1>; b: Product<'a', 0>}
|
||||
type ProductComplement = {
|
||||
[K in Union]: Exclude<ProductUnion, { f1: K }>
|
||||
};
|
||||
type PCA = ProductComplement['a'];
|
||||
type PCB = ProductComplement['b'];
|
||||
|
||||
// {a: Product<'a', 0>; b: Product<'b', 1>}
|
||||
type ProductComplementComplement = {
|
||||
[K in Union]: Exclude<ProductUnion, Exclude<ProductUnion, { f1: K }>>
|
||||
};
|
||||
type PCCA = ProductComplementComplement['a'];
|
||||
type PCCB = ProductComplementComplement['b'];
|
||||
|
||||
|
||||
//// [conditionalTypes2.js]
|
||||
@@ -328,3 +362,33 @@ declare type T2 = MaybeTrue<{
|
||||
declare type T3 = MaybeTrue<{
|
||||
b: boolean;
|
||||
}>;
|
||||
declare type Union = 'a' | 'b';
|
||||
declare type Product<A extends Union, B> = {
|
||||
f1: A;
|
||||
f2: B;
|
||||
};
|
||||
declare type ProductUnion = Product<'a', 0> | Product<'b', 1>;
|
||||
declare type UnionComplement = {
|
||||
[K in Union]: Exclude<Union, K>;
|
||||
};
|
||||
declare type UCA = UnionComplement['a'];
|
||||
declare type UCB = UnionComplement['b'];
|
||||
declare type UnionComplementComplement = {
|
||||
[K in Union]: Exclude<Union, Exclude<Union, K>>;
|
||||
};
|
||||
declare type UCCA = UnionComplementComplement['a'];
|
||||
declare type UCCB = UnionComplementComplement['b'];
|
||||
declare type ProductComplement = {
|
||||
[K in Union]: Exclude<ProductUnion, {
|
||||
f1: K;
|
||||
}>;
|
||||
};
|
||||
declare type PCA = ProductComplement['a'];
|
||||
declare type PCB = ProductComplement['b'];
|
||||
declare type ProductComplementComplement = {
|
||||
[K in Union]: Exclude<ProductUnion, Exclude<ProductUnion, {
|
||||
f1: K;
|
||||
}>>;
|
||||
};
|
||||
declare type PCCA = ProductComplementComplement['a'];
|
||||
declare type PCCB = ProductComplementComplement['b'];
|
||||
|
||||
@@ -579,3 +579,109 @@ type T3 = MaybeTrue<{ b: boolean }>; // "yes"
|
||||
>MaybeTrue : Symbol(MaybeTrue, Decl(conditionalTypes2.ts, 145, 63))
|
||||
>b : Symbol(b, Decl(conditionalTypes2.ts, 154, 21))
|
||||
|
||||
// Repro from #28824
|
||||
|
||||
type Union = 'a' | 'b';
|
||||
>Union : Symbol(Union, Decl(conditionalTypes2.ts, 154, 36))
|
||||
|
||||
type Product<A extends Union, B> = { f1: A, f2: B};
|
||||
>Product : Symbol(Product, Decl(conditionalTypes2.ts, 158, 23))
|
||||
>A : Symbol(A, Decl(conditionalTypes2.ts, 159, 13))
|
||||
>Union : Symbol(Union, Decl(conditionalTypes2.ts, 154, 36))
|
||||
>B : Symbol(B, Decl(conditionalTypes2.ts, 159, 29))
|
||||
>f1 : Symbol(f1, Decl(conditionalTypes2.ts, 159, 36))
|
||||
>A : Symbol(A, Decl(conditionalTypes2.ts, 159, 13))
|
||||
>f2 : Symbol(f2, Decl(conditionalTypes2.ts, 159, 43))
|
||||
>B : Symbol(B, Decl(conditionalTypes2.ts, 159, 29))
|
||||
|
||||
type ProductUnion = Product<'a', 0> | Product<'b', 1>;
|
||||
>ProductUnion : Symbol(ProductUnion, Decl(conditionalTypes2.ts, 159, 51))
|
||||
>Product : Symbol(Product, Decl(conditionalTypes2.ts, 158, 23))
|
||||
>Product : Symbol(Product, Decl(conditionalTypes2.ts, 158, 23))
|
||||
|
||||
// {a: "b"; b: "a"}
|
||||
type UnionComplement = {
|
||||
>UnionComplement : Symbol(UnionComplement, Decl(conditionalTypes2.ts, 160, 54))
|
||||
|
||||
[K in Union]: Exclude<Union, K>
|
||||
>K : Symbol(K, Decl(conditionalTypes2.ts, 164, 3))
|
||||
>Union : Symbol(Union, Decl(conditionalTypes2.ts, 154, 36))
|
||||
>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --))
|
||||
>Union : Symbol(Union, Decl(conditionalTypes2.ts, 154, 36))
|
||||
>K : Symbol(K, Decl(conditionalTypes2.ts, 164, 3))
|
||||
|
||||
};
|
||||
type UCA = UnionComplement['a'];
|
||||
>UCA : Symbol(UCA, Decl(conditionalTypes2.ts, 165, 2))
|
||||
>UnionComplement : Symbol(UnionComplement, Decl(conditionalTypes2.ts, 160, 54))
|
||||
|
||||
type UCB = UnionComplement['b'];
|
||||
>UCB : Symbol(UCB, Decl(conditionalTypes2.ts, 166, 32))
|
||||
>UnionComplement : Symbol(UnionComplement, Decl(conditionalTypes2.ts, 160, 54))
|
||||
|
||||
// {a: "a"; b: "b"}
|
||||
type UnionComplementComplement = {
|
||||
>UnionComplementComplement : Symbol(UnionComplementComplement, Decl(conditionalTypes2.ts, 167, 32))
|
||||
|
||||
[K in Union]: Exclude<Union, Exclude<Union, K>>
|
||||
>K : Symbol(K, Decl(conditionalTypes2.ts, 171, 3))
|
||||
>Union : Symbol(Union, Decl(conditionalTypes2.ts, 154, 36))
|
||||
>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --))
|
||||
>Union : Symbol(Union, Decl(conditionalTypes2.ts, 154, 36))
|
||||
>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --))
|
||||
>Union : Symbol(Union, Decl(conditionalTypes2.ts, 154, 36))
|
||||
>K : Symbol(K, Decl(conditionalTypes2.ts, 171, 3))
|
||||
|
||||
};
|
||||
type UCCA = UnionComplementComplement['a'];
|
||||
>UCCA : Symbol(UCCA, Decl(conditionalTypes2.ts, 172, 2))
|
||||
>UnionComplementComplement : Symbol(UnionComplementComplement, Decl(conditionalTypes2.ts, 167, 32))
|
||||
|
||||
type UCCB = UnionComplementComplement['b'];
|
||||
>UCCB : Symbol(UCCB, Decl(conditionalTypes2.ts, 173, 43))
|
||||
>UnionComplementComplement : Symbol(UnionComplementComplement, Decl(conditionalTypes2.ts, 167, 32))
|
||||
|
||||
// {a: Product<'b', 1>; b: Product<'a', 0>}
|
||||
type ProductComplement = {
|
||||
>ProductComplement : Symbol(ProductComplement, Decl(conditionalTypes2.ts, 174, 43))
|
||||
|
||||
[K in Union]: Exclude<ProductUnion, { f1: K }>
|
||||
>K : Symbol(K, Decl(conditionalTypes2.ts, 178, 3))
|
||||
>Union : Symbol(Union, Decl(conditionalTypes2.ts, 154, 36))
|
||||
>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --))
|
||||
>ProductUnion : Symbol(ProductUnion, Decl(conditionalTypes2.ts, 159, 51))
|
||||
>f1 : Symbol(f1, Decl(conditionalTypes2.ts, 178, 39))
|
||||
>K : Symbol(K, Decl(conditionalTypes2.ts, 178, 3))
|
||||
|
||||
};
|
||||
type PCA = ProductComplement['a'];
|
||||
>PCA : Symbol(PCA, Decl(conditionalTypes2.ts, 179, 2))
|
||||
>ProductComplement : Symbol(ProductComplement, Decl(conditionalTypes2.ts, 174, 43))
|
||||
|
||||
type PCB = ProductComplement['b'];
|
||||
>PCB : Symbol(PCB, Decl(conditionalTypes2.ts, 180, 34))
|
||||
>ProductComplement : Symbol(ProductComplement, Decl(conditionalTypes2.ts, 174, 43))
|
||||
|
||||
// {a: Product<'a', 0>; b: Product<'b', 1>}
|
||||
type ProductComplementComplement = {
|
||||
>ProductComplementComplement : Symbol(ProductComplementComplement, Decl(conditionalTypes2.ts, 181, 34))
|
||||
|
||||
[K in Union]: Exclude<ProductUnion, Exclude<ProductUnion, { f1: K }>>
|
||||
>K : Symbol(K, Decl(conditionalTypes2.ts, 185, 3))
|
||||
>Union : Symbol(Union, Decl(conditionalTypes2.ts, 154, 36))
|
||||
>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --))
|
||||
>ProductUnion : Symbol(ProductUnion, Decl(conditionalTypes2.ts, 159, 51))
|
||||
>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --))
|
||||
>ProductUnion : Symbol(ProductUnion, Decl(conditionalTypes2.ts, 159, 51))
|
||||
>f1 : Symbol(f1, Decl(conditionalTypes2.ts, 185, 61))
|
||||
>K : Symbol(K, Decl(conditionalTypes2.ts, 185, 3))
|
||||
|
||||
};
|
||||
type PCCA = ProductComplementComplement['a'];
|
||||
>PCCA : Symbol(PCCA, Decl(conditionalTypes2.ts, 186, 2))
|
||||
>ProductComplementComplement : Symbol(ProductComplementComplement, Decl(conditionalTypes2.ts, 181, 34))
|
||||
|
||||
type PCCB = ProductComplementComplement['b'];
|
||||
>PCCB : Symbol(PCCB, Decl(conditionalTypes2.ts, 187, 45))
|
||||
>ProductComplementComplement : Symbol(ProductComplementComplement, Decl(conditionalTypes2.ts, 181, 34))
|
||||
|
||||
|
||||
@@ -366,3 +366,68 @@ type T3 = MaybeTrue<{ b: boolean }>; // "yes"
|
||||
>T3 : "yes"
|
||||
>b : boolean
|
||||
|
||||
// Repro from #28824
|
||||
|
||||
type Union = 'a' | 'b';
|
||||
>Union : Union
|
||||
|
||||
type Product<A extends Union, B> = { f1: A, f2: B};
|
||||
>Product : Product<A, B>
|
||||
>f1 : A
|
||||
>f2 : B
|
||||
|
||||
type ProductUnion = Product<'a', 0> | Product<'b', 1>;
|
||||
>ProductUnion : ProductUnion
|
||||
|
||||
// {a: "b"; b: "a"}
|
||||
type UnionComplement = {
|
||||
>UnionComplement : UnionComplement
|
||||
|
||||
[K in Union]: Exclude<Union, K>
|
||||
};
|
||||
type UCA = UnionComplement['a'];
|
||||
>UCA : "b"
|
||||
|
||||
type UCB = UnionComplement['b'];
|
||||
>UCB : "a"
|
||||
|
||||
// {a: "a"; b: "b"}
|
||||
type UnionComplementComplement = {
|
||||
>UnionComplementComplement : UnionComplementComplement
|
||||
|
||||
[K in Union]: Exclude<Union, Exclude<Union, K>>
|
||||
};
|
||||
type UCCA = UnionComplementComplement['a'];
|
||||
>UCCA : "a"
|
||||
|
||||
type UCCB = UnionComplementComplement['b'];
|
||||
>UCCB : "b"
|
||||
|
||||
// {a: Product<'b', 1>; b: Product<'a', 0>}
|
||||
type ProductComplement = {
|
||||
>ProductComplement : ProductComplement
|
||||
|
||||
[K in Union]: Exclude<ProductUnion, { f1: K }>
|
||||
>f1 : K
|
||||
|
||||
};
|
||||
type PCA = ProductComplement['a'];
|
||||
>PCA : Product<"b", 1>
|
||||
|
||||
type PCB = ProductComplement['b'];
|
||||
>PCB : Product<"a", 0>
|
||||
|
||||
// {a: Product<'a', 0>; b: Product<'b', 1>}
|
||||
type ProductComplementComplement = {
|
||||
>ProductComplementComplement : ProductComplementComplement
|
||||
|
||||
[K in Union]: Exclude<ProductUnion, Exclude<ProductUnion, { f1: K }>>
|
||||
>f1 : K
|
||||
|
||||
};
|
||||
type PCCA = ProductComplementComplement['a'];
|
||||
>PCCA : Product<"a", 0>
|
||||
|
||||
type PCCB = ProductComplementComplement['b'];
|
||||
>PCCB : Product<"b", 1>
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ type AProp<T extends { a: string }> = T
|
||||
>a : string
|
||||
|
||||
declare function myBug<
|
||||
>myBug : <T extends { [K in keyof T]: T[K]; }>(arg: T) => T
|
||||
>myBug : <T extends { [K in keyof T]: T[K] extends infer U ? U : never; }>(arg: T) => T
|
||||
|
||||
T extends { [K in keyof T]: T[K] extends AProp<infer U> ? U : never }
|
||||
>(arg: T): T
|
||||
@@ -24,7 +24,7 @@ declare function myBug<
|
||||
const out = myBug({obj1: {a: "test"}})
|
||||
>out : { obj1: { a: string; }; }
|
||||
>myBug({obj1: {a: "test"}}) : { obj1: { a: string; }; }
|
||||
>myBug : <T extends { [K in keyof T]: T[K]; }>(arg: T) => T
|
||||
>myBug : <T extends { [K in keyof T]: T[K] extends infer U ? U : never; }>(arg: T) => T
|
||||
>{obj1: {a: "test"}} : { obj1: { a: string; }; }
|
||||
>obj1 : { a: string; }
|
||||
>{a: "test"} : { a: string; }
|
||||
|
||||
@@ -76,7 +76,7 @@ type T31<T> = T extends unknown ? true : false; // Deferred (so it distributes)
|
||||
>false : false
|
||||
|
||||
type T32<T> = never extends T ? true : false; // true
|
||||
>T32 : true
|
||||
>T32 : T32<T>
|
||||
>true : true
|
||||
>false : false
|
||||
|
||||
|
||||
@@ -156,3 +156,37 @@ type T0 = MaybeTrue<{ b: never }> // "no"
|
||||
type T1 = MaybeTrue<{ b: false }>; // "no"
|
||||
type T2 = MaybeTrue<{ b: true }>; // "yes"
|
||||
type T3 = MaybeTrue<{ b: boolean }>; // "yes"
|
||||
|
||||
// Repro from #28824
|
||||
|
||||
type Union = 'a' | 'b';
|
||||
type Product<A extends Union, B> = { f1: A, f2: B};
|
||||
type ProductUnion = Product<'a', 0> | Product<'b', 1>;
|
||||
|
||||
// {a: "b"; b: "a"}
|
||||
type UnionComplement = {
|
||||
[K in Union]: Exclude<Union, K>
|
||||
};
|
||||
type UCA = UnionComplement['a'];
|
||||
type UCB = UnionComplement['b'];
|
||||
|
||||
// {a: "a"; b: "b"}
|
||||
type UnionComplementComplement = {
|
||||
[K in Union]: Exclude<Union, Exclude<Union, K>>
|
||||
};
|
||||
type UCCA = UnionComplementComplement['a'];
|
||||
type UCCB = UnionComplementComplement['b'];
|
||||
|
||||
// {a: Product<'b', 1>; b: Product<'a', 0>}
|
||||
type ProductComplement = {
|
||||
[K in Union]: Exclude<ProductUnion, { f1: K }>
|
||||
};
|
||||
type PCA = ProductComplement['a'];
|
||||
type PCB = ProductComplement['b'];
|
||||
|
||||
// {a: Product<'a', 0>; b: Product<'b', 1>}
|
||||
type ProductComplementComplement = {
|
||||
[K in Union]: Exclude<ProductUnion, Exclude<ProductUnion, { f1: K }>>
|
||||
};
|
||||
type PCCA = ProductComplementComplement['a'];
|
||||
type PCCB = ProductComplementComplement['b'];
|
||||
|
||||
Reference in New Issue
Block a user