@@ -2643,10 +2643,11 @@ namespace ts {
26432643 return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode);
26442644 }
26452645 if (type.flags & TypeFlags.Conditional) {
2646- const conditionTypeNode = typeToTypeNodeHelper((<ConditionalType>type).conditionType, context);
2646+ const checkTypeNode = typeToTypeNodeHelper((<ConditionalType>type).checkType, context);
2647+ const extendsTypeNode = typeToTypeNodeHelper((<ConditionalType>type).extendsType, context);
26472648 const trueTypeNode = typeToTypeNodeHelper((<ConditionalType>type).trueType, context);
26482649 const falseTypeNode = typeToTypeNodeHelper((<ConditionalType>type).falseType, context);
2649- return createConditionalTypeNode(conditionTypeNode , trueTypeNode, falseTypeNode);
2650+ return createConditionalTypeNode(checkTypeNode, extendsTypeNode , trueTypeNode, falseTypeNode);
26502651 }
26512652 if (type.flags & TypeFlags.Extends) {
26522653 const leftTypeNode = typeToTypeNodeHelper((<ExtendsType>type).checkType, context);
@@ -3422,7 +3423,11 @@ namespace ts {
34223423 writePunctuation(writer, SyntaxKind.CloseBracketToken);
34233424 }
34243425 else if (type.flags & TypeFlags.Conditional) {
3425- writeType((<ConditionalType>type).conditionType, TypeFormatFlags.InElementType);
3426+ writeType((<ConditionalType>type).checkType, TypeFormatFlags.InElementType);
3427+ writeSpace(writer);
3428+ writer.writeKeyword("extends");
3429+ writeSpace(writer);
3430+ writeType((<ConditionalType>type).extendsType, TypeFormatFlags.InElementType);
34263431 writeSpace(writer);
34273432 writePunctuation(writer, SyntaxKind.QuestionToken);
34283433 writeSpace(writer);
@@ -6396,14 +6401,11 @@ namespace ts {
63966401 // with its constraint. We do this because if the constraint is a union type it will be distributed
63976402 // over the conditional type and possibly reduced. For example, 'T extends undefined ? never : T'
63986403 // removes 'undefined' from T.
6399- const conditionType = type.conditionType;
6400- if (conditionType.flags & TypeFlags.Extends) {
6401- const checkType = (<ExtendsType>conditionType).checkType;
6402- if (checkType.flags & TypeFlags.TypeParameter) {
6403- const constraint = getConstraintOfTypeParameter(<TypeParameter>checkType);
6404- if (constraint) {
6405- return instantiateType(type, createTypeMapper([<TypeParameter>checkType], [constraint]));
6406- }
6404+ const checkType = type.checkType;
6405+ if (checkType.flags & TypeFlags.TypeParameter) {
6406+ const constraint = getConstraintOfTypeParameter(<TypeParameter>checkType);
6407+ if (constraint) {
6408+ return instantiateType(type, createTypeMapper([<TypeParameter>checkType], [constraint]));
64076409 }
64086410 }
64096411 return undefined;
@@ -8387,43 +8389,48 @@ namespace ts {
83878389 return links.resolvedType;
83888390 }
83898391
8390- function isGenericConditionType(type: Type) {
8391- return maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive | TypeFlags.Extends);
8392- }
8393-
8394- function createConditionalType(conditionType: Type, whenTrueType: Type, whenFalseType: Type, aliasSymbol: Symbol, aliasTypeArguments: Type[]) {
8392+ function createConditionalType(checkType: Type, extendsType: Type, trueType: Type, falseType: Type, aliasSymbol: Symbol, aliasTypeArguments: Type[]) {
83958393 const type = <ConditionalType>createType(TypeFlags.Conditional);
8396- type.conditionType = conditionType;
8397- type.trueType = whenTrueType;
8398- type.falseType = whenFalseType;
8394+ type.checkType = checkType;
8395+ type.extendsType = extendsType;
8396+ type.trueType = trueType;
8397+ type.falseType = falseType;
83998398 type.aliasSymbol = aliasSymbol;
84008399 type.aliasTypeArguments = aliasTypeArguments;
84018400 return type;
84028401 }
84038402
8404- function getConditionalType(condition: Type, whenTrue: Type, whenFalse: Type, aliasSymbol: Symbol, aliasTypeArguments: Type[], mapper: TypeMapper): Type {
8405- if (!isGenericConditionType(condition)) {
8406- return condition.flags & TypeFlags.Never ? neverType : getUnionType([
8407- typeMaybeAssignableTo(condition, trueType) ? instantiateType(whenTrue, mapper) : neverType,
8408- typeMaybeAssignableTo(condition, falseType) ? instantiateType(whenFalse, mapper) : neverType]);
8403+ function getConditionalType(checkType: Type, extendsType: Type, mapper: TypeMapper, trueType: Type, falseType: Type, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type {
8404+ // Distribute union types over conditional types
8405+ if (checkType.flags & TypeFlags.Union) {
8406+ return getUnionType(map((<UnionType>checkType).types, t => getConditionalType(t, extendsType, mapper, trueType, falseType)));
8407+ }
8408+ // Return trueType for a definitely true extends check
8409+ if (isTypeAssignableTo(checkType, extendsType)) {
8410+ return instantiateType(trueType, mapper);
84098411 }
8410- const resultTrueType = instantiateType(whenTrue, mapper);
8411- const resultFalseType = instantiateType(whenFalse, mapper);
8412- const resultTypeArguments = instantiateTypes(aliasTypeArguments, mapper);
8413- const id = condition.id + "," + resultTrueType.id + "," + resultFalseType.id;
8412+ // Return falseType for a definitely false extends check
8413+ if (!isTypeAssignableTo(instantiateType(checkType, anyMapper), instantiateType(extendsType, constraintMapper))) {
8414+ return instantiateType(falseType, mapper);
8415+ }
8416+ // Otherwise return a deferred conditional type
8417+ const resTrueType = instantiateType(trueType, mapper);
8418+ const resFalseType = instantiateType(falseType, mapper);
8419+ const resTypeArguments = instantiateTypes(aliasTypeArguments, mapper);
8420+ const id = checkType.id + "," + extendsType.id + "," + resTrueType.id + "," + resFalseType.id;
84148421 let type = conditionalTypes.get(id);
84158422 if (!type) {
8416- conditionalTypes.set(id, type = createConditionalType(condition, resultTrueType, resultFalseType, aliasSymbol, resultTypeArguments ));
8423+ conditionalTypes.set(id, type = createConditionalType(checkType, extendsType, resTrueType, resFalseType, aliasSymbol, resTypeArguments ));
84178424 }
84188425 return type;
84198426 }
84208427
84218428 function getTypeFromConditionalTypeNode(node: ConditionalTypeNode): Type {
84228429 const links = getNodeLinks(node);
84238430 if (!links.resolvedType) {
8424- links.resolvedType = getConditionalType(getTypeFromTypeNode(node.conditionType ),
8425- getTypeFromTypeNode(node.trueType), getTypeFromTypeNode(node.falseType),
8426- getAliasSymbolForTypeNode(node), getAliasTypeArgumentsForTypeNode(node), identityMapper );
8431+ links.resolvedType = getConditionalType(getTypeFromTypeNode(node.checkType), getTypeFromTypeNode(node.extendsType ),
8432+ identityMapper, getTypeFromTypeNode(node.trueType), getTypeFromTypeNode(node.falseType),
8433+ getAliasSymbolForTypeNode(node), getAliasTypeArgumentsForTypeNode(node));
84278434 }
84288435 return links.resolvedType;
84298436 }
@@ -9039,23 +9046,19 @@ namespace ts {
90399046 // Check if we have a conditional type of the form T extends U ? X : Y, where T is a type parameter.
90409047 // If so, the conditional type is distributive over a union type and when T is instantiated to a union
90419048 // type A | B, we produce (A extends U ? X : Y) | (B extends U ? X : Y).
9042- const conditionType = type.conditionType;
9043- if (conditionType.flags & TypeFlags.Extends) {
9044- const checkType = (<ExtendsType>conditionType).checkType;
9045- if (checkType.flags & TypeFlags.TypeParameter) {
9046- const instantiatedType = mapper(<TypeParameter>checkType);
9047- if (checkType !== instantiatedType && instantiatedType.flags & TypeFlags.Union) {
9048- return mapType(instantiatedType, t => instantiateConditionalType(type, createReplacementMapper(checkType, t, mapper)));
9049- }
9049+ const checkType = type.checkType;
9050+ if (checkType.flags & TypeFlags.TypeParameter) {
9051+ const instantiatedType = mapper(<TypeParameter>checkType);
9052+ if (checkType !== instantiatedType && instantiatedType.flags & TypeFlags.Union) {
9053+ return mapType(instantiatedType, t => instantiateConditionalType(type, createReplacementMapper(checkType, t, mapper)));
90509054 }
90519055 }
90529056 return instantiateConditionalType(type, mapper);
90539057 }
90549058
90559059 function instantiateConditionalType(type: ConditionalType, mapper: TypeMapper): Type {
9056- return getConditionalType(instantiateType((<ConditionalType>type).conditionType, mapper),
9057- (<ConditionalType>type).trueType, (<ConditionalType>type).falseType,
9058- type.aliasSymbol, type.aliasTypeArguments, mapper);
9060+ return getConditionalType(instantiateType(type.checkType, mapper), instantiateType(type.extendsType, mapper),
9061+ mapper, type.trueType, type.falseType, type.aliasSymbol, type.aliasTypeArguments);
90599062 }
90609063
90619064 function instantiateType(type: Type, mapper: TypeMapper): Type {
@@ -11644,7 +11647,8 @@ namespace ts {
1164411647 inferFromTypes((<IndexedAccessType>source).indexType, (<IndexedAccessType>target).indexType);
1164511648 }
1164611649 else if (source.flags & TypeFlags.Conditional && target.flags & TypeFlags.Conditional) {
11647- inferFromTypes((<ConditionalType>source).conditionType, (<ConditionalType>target).conditionType);
11650+ inferFromTypes((<ConditionalType>source).checkType, (<ConditionalType>target).checkType);
11651+ inferFromTypes((<ConditionalType>source).extendsType, (<ConditionalType>target).extendsType);
1164811652 inferFromTypes((<ConditionalType>source).trueType, (<ConditionalType>target).trueType);
1164911653 inferFromTypes((<ConditionalType>source).falseType, (<ConditionalType>target).falseType);
1165011654 }
@@ -20358,7 +20362,6 @@ namespace ts {
2035820362
2035920363 function checkConditionalType(node: ConditionalTypeNode) {
2036020364 forEachChild(node, checkSourceElement);
20361- checkTypeAssignableTo(getTypeFromTypeNode(node.conditionType), booleanType, node.conditionType);
2036220365 }
2036320366
2036420367 function isPrivateWithinAmbient(node: Node): boolean {
0 commit comments