From 063eed1a47b873a60e804d748dbe2959f9b51d70 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 8 Dec 2017 10:19:23 -0800 Subject: [PATCH] Add type relationships and distribute over union types --- src/compiler/checker.ts | 43 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cbf31179b92..dc45c7d2f51 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3397,11 +3397,17 @@ namespace ts { } else if (type.flags & TypeFlags.Conditional) { writeType((type).checkType, TypeFormatFlags.InElementType); + writeSpace(writer); writer.writeKeyword("extends"); + writeSpace(writer); writeType((type).extendsType, TypeFormatFlags.InElementType); + writeSpace(writer); writePunctuation(writer, SyntaxKind.QuestionToken); + writeSpace(writer); writeType((type).trueType, TypeFormatFlags.InElementType); + writeSpace(writer); writePunctuation(writer, SyntaxKind.ColonToken); + writeSpace(writer); writeType((type).falseType, TypeFormatFlags.InElementType); } else { @@ -6374,6 +6380,11 @@ namespace ts { const baseIndexedAccess = baseObjectType && baseIndexType ? getIndexedAccessType(baseObjectType, baseIndexType) : undefined; return baseIndexedAccess && baseIndexedAccess !== unknownType ? getBaseConstraint(baseIndexedAccess) : undefined; } + if (t.flags & TypeFlags.Conditional) { + const trueBaseType = getBaseConstraint((t).trueType); + const falseBaseType = getBaseConstraint((t).trueType); + return trueBaseType && falseBaseType ? getUnionType([trueBaseType, falseBaseType]) : undefined; + } if (isGenericMappedType(t)) { return emptyObjectType; } @@ -8221,6 +8232,8 @@ namespace ts { type.extendsType = extendsType; type.trueType = trueType; type.falseType = falseType; + type.aliasSymbol = aliasSymbol; + type.aliasTypeArguments = aliasTypeArguments; return type; } @@ -8793,6 +8806,23 @@ namespace ts { return result; } + function getConditionalTypeInstantiation(type: ConditionalType, mapper: TypeMapper): Type { + const checkType = type.checkType; + if (checkType.flags & TypeFlags.TypeParameter) { + const instantiatedType = mapper(checkType); + if (checkType !== instantiatedType && instantiatedType.flags & TypeFlags.Union) { + return mapType(instantiatedType, t => instantiateConditionalType(type, createReplacementMapper(checkType, t, mapper))); + } + } + return instantiateConditionalType(type, mapper); + } + + function instantiateConditionalType(type: ConditionalType, mapper: TypeMapper): Type { + return getConditionalType(instantiateType((type).checkType, mapper), instantiateType((type).extendsType, mapper), + instantiateType((type).trueType, mapper), instantiateType((type).falseType, mapper), + type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)); + } + function instantiateType(type: Type, mapper: TypeMapper): Type { if (type && mapper !== identityMapper) { if (type.flags & TypeFlags.TypeParameter) { @@ -8826,9 +8856,7 @@ namespace ts { return getIndexedAccessType(instantiateType((type).objectType, mapper), instantiateType((type).indexType, mapper)); } if (type.flags & TypeFlags.Conditional) { - return getConditionalType(instantiateType((type).checkType, mapper), instantiateType((type).extendsType, mapper), - instantiateType((type).trueType, mapper), instantiateType((type).falseType, mapper), - type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)); + return getConditionalTypeInstantiation(type, mapper); } } return type; @@ -9893,6 +9921,15 @@ namespace ts { } } } + else if (source.flags & TypeFlags.Conditional) { + const constraint = getConstraintOfType(source); + if (constraint) { + if (result = isRelatedTo(constraint, target, reportErrors)) { + errorInfo = saveErrorInfo; + return result; + } + } + } else { if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target && !(source.flags & TypeFlags.MarkerType || target.flags & TypeFlags.MarkerType)) {