From 6e672b7c9db1fd63dd7be80c4eda649cff24574c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 26 Feb 2018 14:26:15 -0800 Subject: [PATCH] Use '{}' instead of 'never' for no candidates in conditional inference --- src/compiler/checker.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 84355e32a73..dee42764f36 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8188,9 +8188,6 @@ namespace ts { } function getConditionalType(root: ConditionalRoot, mapper: TypeMapper): Type { - let combinedMapper: TypeMapper; - const getTrueType = () => instantiateType(root.trueType, combinedMapper || mapper); - const getFalseType = () => instantiateType(root.falseType, mapper); const checkType = instantiateType(root.checkType, mapper); const extendsType = instantiateType(root.extendsType, mapper); // Return falseType for a definitely false extends check. We check an instantations of the two @@ -8198,9 +8195,10 @@ namespace ts { // possible (the wildcard type is assignable to and from all types). If those are not related, // then no instatiations will be and we can just return the false branch type. if (!typeMaybeAssignableTo(getWildcardInstantiation(checkType), getWildcardInstantiation(extendsType))) { - return getFalseType(); + return instantiateType(root.falseType, mapper); } // The check could be true for some instantiation + let combinedMapper: TypeMapper; if (root.inferTypeParameters) { const inferences = map(root.inferTypeParameters, createInferenceInfo); // We don't want inferences from constraints as they may cause us to eagerly resolve the @@ -8208,12 +8206,12 @@ namespace ts { // types rules (i.e. proper contravariance) for inferences. inferTypes(inferences, checkType, extendsType, InferencePriority.NoConstraints | InferencePriority.AlwaysStrict); // We infer 'never' when there are no candidates for a type parameter - const inferredTypes = map(inferences, inference => getTypeFromInference(inference) || neverType); + const inferredTypes = map(inferences, inference => getTypeFromInference(inference) || emptyObjectType); combinedMapper = combineTypeMappers(mapper, createTypeMapper(root.inferTypeParameters, inferredTypes)); } // Return union of trueType and falseType for any and never since they match anything if (checkType.flags & TypeFlags.Any || (checkType.flags & TypeFlags.Never && !(extendsType.flags & TypeFlags.Never))) { - return getUnionType([getTrueType(), getFalseType()]); + 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; @@ -8222,7 +8220,7 @@ namespace ts { // type Foo = T extends { x: string } ? string : number // would immediately resolve to 'string' instead of being deferred. if (checkTypeRelatedTo(checkType, inferredExtendsType, definitelyAssignableRelation, /*errorNode*/ undefined)) { - return getTrueType(); + return instantiateType(root.trueType, combinedMapper || mapper); } // Return a deferred type for a check that is neither definitely true nor definitely false const erasedCheckType = getActualTypeParameter(checkType);