Fixed distributive conditional types with never intersections (#57345)

This commit is contained in:
Mateusz Burzyński 2024-02-09 21:25:02 +01:00 committed by GitHub
parent c5db0ac0ef
commit e2bf8b437d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 70 additions and 2 deletions

View File

@ -19877,12 +19877,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (!result) {
const newMapper = createTypeMapper(root.outerTypeParameters, typeArguments);
const checkType = root.checkType;
const distributionType = root.isDistributive ? getMappedType(checkType, newMapper) : undefined;
const distributionType = root.isDistributive ? getReducedType(getMappedType(checkType, newMapper)) : undefined;
// Distributive conditional types are distributed over union types. For example, when the
// distributive conditional type T extends U ? X : Y is instantiated with A | B for T, the
// result is (A extends U ? X : Y) | (B extends U ? X : Y).
result = distributionType && checkType !== distributionType && distributionType.flags & (TypeFlags.Union | TypeFlags.Never) ?
mapTypeWithAlias(getReducedType(distributionType), t => getConditionalType(root, prependTypeMapping(checkType, t, newMapper), forConstraint), aliasSymbol, aliasTypeArguments) :
mapTypeWithAlias(distributionType, t => getConditionalType(root, prependTypeMapping(checkType, t, newMapper), forConstraint), aliasSymbol, aliasTypeArguments) :
getConditionalType(root, newMapper, forConstraint, aliasSymbol, aliasTypeArguments);
root.instantiations!.set(id, result);
}

View File

@ -0,0 +1,30 @@
//// [tests/cases/compiler/distributiveConditionalTypeNeverIntersection1.ts] ////
=== distributiveConditionalTypeNeverIntersection1.ts ===
// https://github.com/microsoft/TypeScript/issues/57343
type IsNumber<T> = T extends number ? true : false;
>IsNumber : Symbol(IsNumber, Decl(distributiveConditionalTypeNeverIntersection1.ts, 0, 0))
>T : Symbol(T, Decl(distributiveConditionalTypeNeverIntersection1.ts, 2, 14))
>T : Symbol(T, Decl(distributiveConditionalTypeNeverIntersection1.ts, 2, 14))
type Conflicted = { x: true } & { x: false };
>Conflicted : Symbol(Conflicted, Decl(distributiveConditionalTypeNeverIntersection1.ts, 2, 51))
>x : Symbol(x, Decl(distributiveConditionalTypeNeverIntersection1.ts, 4, 19))
>x : Symbol(x, Decl(distributiveConditionalTypeNeverIntersection1.ts, 4, 33))
type Ex1 = IsNumber<Conflicted>; // never
>Ex1 : Symbol(Ex1, Decl(distributiveConditionalTypeNeverIntersection1.ts, 4, 45))
>IsNumber : Symbol(IsNumber, Decl(distributiveConditionalTypeNeverIntersection1.ts, 0, 0))
>Conflicted : Symbol(Conflicted, Decl(distributiveConditionalTypeNeverIntersection1.ts, 2, 51))
type Ex2 = IsNumber<"OEEE" | Conflicted>; // false
>Ex2 : Symbol(Ex2, Decl(distributiveConditionalTypeNeverIntersection1.ts, 6, 32))
>IsNumber : Symbol(IsNumber, Decl(distributiveConditionalTypeNeverIntersection1.ts, 0, 0))
>Conflicted : Symbol(Conflicted, Decl(distributiveConditionalTypeNeverIntersection1.ts, 2, 51))
type Ex3 = IsNumber<1 | Conflicted>; // true
>Ex3 : Symbol(Ex3, Decl(distributiveConditionalTypeNeverIntersection1.ts, 7, 41))
>IsNumber : Symbol(IsNumber, Decl(distributiveConditionalTypeNeverIntersection1.ts, 0, 0))
>Conflicted : Symbol(Conflicted, Decl(distributiveConditionalTypeNeverIntersection1.ts, 2, 51))

View File

@ -0,0 +1,26 @@
//// [tests/cases/compiler/distributiveConditionalTypeNeverIntersection1.ts] ////
=== distributiveConditionalTypeNeverIntersection1.ts ===
// https://github.com/microsoft/TypeScript/issues/57343
type IsNumber<T> = T extends number ? true : false;
>IsNumber : IsNumber<T>
>true : true
>false : false
type Conflicted = { x: true } & { x: false };
>Conflicted : never
>x : true
>true : true
>x : false
>false : false
type Ex1 = IsNumber<Conflicted>; // never
>Ex1 : never
type Ex2 = IsNumber<"OEEE" | Conflicted>; // false
>Ex2 : false
type Ex3 = IsNumber<1 | Conflicted>; // true
>Ex3 : true

View File

@ -0,0 +1,12 @@
// @strict: true
// @noEmit: true
// https://github.com/microsoft/TypeScript/issues/57343
type IsNumber<T> = T extends number ? true : false;
type Conflicted = { x: true } & { x: false };
type Ex1 = IsNumber<Conflicted>; // never
type Ex2 = IsNumber<"OEEE" | Conflicted>; // false
type Ex3 = IsNumber<1 | Conflicted>; // true