Constraint of 'T extends U ? T : F' should be 'T & U | F'

This commit is contained in:
Anders Hejlsberg
2018-03-30 15:28:01 -07:00
parent a9aca81601
commit 6f681d276a
2 changed files with 24 additions and 10 deletions

View File

@@ -6233,7 +6233,12 @@ namespace ts {
}
function getDefaultConstraintOfConditionalType(type: ConditionalType) {
return getUnionType([getInferredTrueTypeFromConditionalType(type), getFalseTypeFromConditionalType(type)]);
if (!type.resolvedDefaultConstraint) {
const rootTrueType = type.root.trueType;
const rootTrueConstraint = rootTrueType.flags & TypeFlags.Substitution ? (<SubstitutionType>rootTrueType).substitute : rootTrueType;
type.resolvedDefaultConstraint = getUnionType([instantiateType(rootTrueConstraint, type.combinedMapper || type.mapper), getFalseTypeFromConditionalType(type)]);
}
return type.resolvedDefaultConstraint;
}
function getConstraintOfDistributiveConditionalType(type: ConditionalType): Type {
@@ -6246,7 +6251,10 @@ namespace ts {
const constraint = getConstraintOfType(type.checkType);
if (constraint) {
const mapper = createTypeMapper([<TypeParameter>type.root.checkType], [constraint]);
return getConditionalTypeInstantiation(type, combineTypeMappers(mapper, type.mapper));
const instantiated = getConditionalTypeInstantiation(type, combineTypeMappers(mapper, type.mapper));
if (!(instantiated.flags & TypeFlags.Never)) {
return instantiated;
}
}
}
return undefined;
@@ -8398,12 +8406,6 @@ namespace ts {
return type.resolvedFalseType || (type.resolvedFalseType = instantiateType(type.root.falseType, type.mapper));
}
function getInferredTrueTypeFromConditionalType(type: ConditionalType) {
return type.combinedMapper ?
type.resolvedInferredTrueType || (type.resolvedInferredTrueType = instantiateType(type.root.trueType, type.combinedMapper)) :
getTrueTypeFromConditionalType(type);
}
function getInferTypeParameters(node: ConditionalTypeNode): TypeParameter[] {
let result: TypeParameter[];
if (node.locals) {
@@ -8416,13 +8418,25 @@ namespace ts {
return result;
}
function getTopConditionalType(node: Node): ConditionalTypeNode {
let result: ConditionalTypeNode;
while (node) {
if (node.kind === SyntaxKind.ConditionalType) {
result = <ConditionalTypeNode>node;
}
node = node.parent;
}
return result;
}
function getTypeFromConditionalTypeNode(node: ConditionalTypeNode): Type {
const links = getNodeLinks(node);
if (!links.resolvedType) {
const checkType = getTypeFromTypeNode(node.checkType);
const aliasTypeArguments = getAliasTypeArgumentsForTypeNode(node);
const allOuterTypeParameters = getOuterTypeParameters(node, /*includeThisTypes*/ true);
const outerTypeParameters = aliasTypeArguments ? allOuterTypeParameters : filter(allOuterTypeParameters, tp => isTypeParameterPossiblyReferenced(tp, node));
const topNode = getTopConditionalType(node);
const outerTypeParameters = aliasTypeArguments ? allOuterTypeParameters : filter(allOuterTypeParameters, tp => isTypeParameterPossiblyReferenced(tp, topNode));
const root: ConditionalRoot = {
node,
checkType,

View File

@@ -3878,7 +3878,7 @@ namespace ts {
resolvedTrueType?: Type;
resolvedFalseType?: Type;
/* @internal */
resolvedInferredTrueType?: Type;
resolvedDefaultConstraint?: Type;
/* @internal */
mapper?: TypeMapper;
/* @internal */