diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 80c8b3dc315..1fbd53c1e40 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -3422,6 +3422,7 @@ namespace ts { case SyntaxKind.TypeAliasDeclaration: case SyntaxKind.ThisType: case SyntaxKind.TypeOperator: + case SyntaxKind.BinaryType: case SyntaxKind.IndexedAccessType: case SyntaxKind.MappedType: case SyntaxKind.LiteralType: diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index dc45c7d2f51..4f002f41c5d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -264,6 +264,8 @@ namespace ts { const intersectionTypes = createMap(); const literalTypes = createMap(); const indexedAccessTypes = createMap(); + const conditionalTypes = createMap(); + const extendsTypes = createMap(); const evolvingArrayTypes: EvolvingArrayType[] = []; const undefinedProperties = createMap() as UnderscoreEscapedMap; @@ -2621,11 +2623,15 @@ namespace ts { return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode); } if (type.flags & TypeFlags.Conditional) { - const checkTypeNode = typeToTypeNodeHelper((type).checkType, context); - const extendskTypeNode = typeToTypeNodeHelper((type).extendsType, context); + const conditionTypeNode = typeToTypeNodeHelper((type).conditionType, context); const trueTypeNode = typeToTypeNodeHelper((type).trueType, context); const falseTypeNode = typeToTypeNodeHelper((type).falseType, context); - return createConditionalTypeNode(checkTypeNode, extendskTypeNode, trueTypeNode, falseTypeNode); + return createConditionalTypeNode(conditionTypeNode, trueTypeNode, falseTypeNode); + } + if (type.flags & TypeFlags.Extends) { + const leftTypeNode = typeToTypeNodeHelper((type).checkType, context); + const rightTypeNode = typeToTypeNodeHelper((type).extendsType, context); + return createBinaryTypeNode(leftTypeNode, SyntaxKind.ExtendsKeyword, rightTypeNode); } Debug.fail("Should be unreachable."); @@ -3396,11 +3402,7 @@ namespace ts { writePunctuation(writer, SyntaxKind.CloseBracketToken); } else if (type.flags & TypeFlags.Conditional) { - writeType((type).checkType, TypeFormatFlags.InElementType); - writeSpace(writer); - writer.writeKeyword("extends"); - writeSpace(writer); - writeType((type).extendsType, TypeFormatFlags.InElementType); + writeType((type).conditionType, TypeFormatFlags.InElementType); writeSpace(writer); writePunctuation(writer, SyntaxKind.QuestionToken); writeSpace(writer); @@ -3410,6 +3412,13 @@ namespace ts { writeSpace(writer); writeType((type).falseType, TypeFormatFlags.InElementType); } + else if (type.flags & TypeFlags.Extends) { + writeType((type).checkType, TypeFormatFlags.InElementType); + writeSpace(writer); + writer.writeKeyword("extends"); + writeSpace(writer); + writeType((type).extendsType, TypeFormatFlags.InElementType); + } else { // Should never get here // { ... } @@ -6385,6 +6394,9 @@ namespace ts { const falseBaseType = getBaseConstraint((t).trueType); return trueBaseType && falseBaseType ? getUnionType([trueBaseType, falseBaseType]) : undefined; } + if (t.flags & TypeFlags.Extends) { + return booleanType; + } if (isGenericMappedType(t)) { return emptyObjectType; } @@ -8109,6 +8121,12 @@ namespace ts { false; } + function isGenericConditionType(type: Type): boolean { + return type.flags & (TypeFlags.TypeVariable | TypeFlags.Extends) ? true : + type.flags & TypeFlags.UnionOrIntersection ? forEach((type).types, isGenericConditionType) : + false; + } + // Return true if the given type is a non-generic object type with a string index signature and no // other members. function isStringIndexOnlyType(type: Type) { @@ -8216,33 +8234,73 @@ namespace ts { return links.resolvedType; } - function getConditionalType(checkType: Type, extendsType: Type, trueType: Type, falseType: Type, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { - if (checkType.flags & TypeFlags.Union) { - return getUnionType(map((checkType).types, t => getConditionalType(t, extendsType, trueType, falseType)), - /*subtypeReduction*/ false, aliasSymbol, aliasTypeArguments); - } - if (isTypeAssignableTo(checkType, extendsType)) { - return trueType; - } - if (!isGenericObjectType(checkType) && !isGenericObjectType(extendsType)) { - return falseType; - } + function createConditionalType(conditionType: Type, whenTrueType: Type, whenFalseType: Type, aliasSymbol: Symbol, aliasTypeArguments: Type[]) { const type = createType(TypeFlags.Conditional); - type.checkType = checkType; - type.extendsType = extendsType; - type.trueType = trueType; - type.falseType = falseType; + type.conditionType = conditionType; + type.trueType = whenTrueType; + type.falseType = whenFalseType; type.aliasSymbol = aliasSymbol; type.aliasTypeArguments = aliasTypeArguments; return type; } + function getConditionalType(condition: Type, whenTrue: Type, whenFalse: Type, aliasSymbol: Symbol, aliasTypeArguments: Type[], mapper: TypeMapper): Type { + if (!isGenericConditionType(condition)) { + return condition.flags & TypeFlags.Never ? neverType : getUnionType([ + typeMaybeAssignableTo(condition, trueType) ? instantiateType(whenTrue, mapper) : neverType, + typeMaybeAssignableTo(condition, falseType) ? instantiateType(whenFalse, mapper) : neverType]); + } + const resultTrueType = instantiateType(whenTrue, mapper); + const resultFalseType = instantiateType(whenFalse, mapper); + const resultTypeArguments = instantiateTypes(aliasTypeArguments, mapper); + const id = condition.id + "," + resultTrueType.id + "," + resultFalseType.id; + let type = conditionalTypes.get(id); + if (!type) { + conditionalTypes.set(id, type = createConditionalType(condition, resultTrueType, resultFalseType, aliasSymbol, resultTypeArguments)); + } + return type; + } + function getTypeFromConditionalTypeNode(node: ConditionalTypeNode): Type { const links = getNodeLinks(node); if (!links.resolvedType) { - links.resolvedType = getConditionalType(getTypeFromTypeNode(node.checkType), getTypeFromTypeNode(node.extendsType), + links.resolvedType = getConditionalType(getTypeFromTypeNode(node.conditionType), getTypeFromTypeNode(node.trueType), getTypeFromTypeNode(node.falseType), - getAliasSymbolForTypeNode(node), getAliasTypeArgumentsForTypeNode(node)); + getAliasSymbolForTypeNode(node), getAliasTypeArgumentsForTypeNode(node), identityMapper); + } + return links.resolvedType; + } + + function createExtendsType(checkType: Type, extendsType: Type) { + const type = createType(TypeFlags.Extends); + type.checkType = checkType; + type.extendsType = extendsType; + return type; + } + + function getExtendsType(checkType: Type, extendsType: Type): Type { + // sys.write(`getExtendsType(${typeToString(checkType)}, ${typeToString(extendsType)})\n`); + if (checkType.flags & TypeFlags.Union) { + return getUnionType(map((checkType).types, t => getExtendsType(t, extendsType)), /*subtypeReduction*/ false); + } + if (checkType.flags & TypeFlags.Any) { + return booleanType; + } + if (!isGenericObjectType(checkType) && !isGenericObjectType(extendsType)) { + return isTypeAssignableTo(checkType, extendsType) ? trueType : falseType; + } + const id = checkType.id + "," + extendsType.id; + let type = extendsTypes.get(id); + if (!type) { + extendsTypes.set(id, type = createExtendsType(checkType, extendsType)); + } + return type; + } + + function getTypeFromBinaryTypeNode(node: BinaryTypeNode): Type { + const links = getNodeLinks(node); + if (!links.resolvedType) { + links.resolvedType = getExtendsType(getTypeFromTypeNode(node.left), getTypeFromTypeNode(node.right)); } return links.resolvedType; } @@ -8541,6 +8599,8 @@ namespace ts { return getTypeFromMappedTypeNode(node); case SyntaxKind.ConditionalType: return getTypeFromConditionalTypeNode(node); + case SyntaxKind.BinaryType: + return getTypeFromBinaryTypeNode(node); // This function assumes that an identifier or qualified name is a type expression // Callers should first ensure this by calling isTypeNode case SyntaxKind.Identifier: @@ -8807,20 +8867,23 @@ namespace ts { } 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))); + const conditionType = type.conditionType; + if (conditionType.flags & TypeFlags.Extends) { + const checkType = (conditionType).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)); + return getConditionalType(instantiateType((type).conditionType, mapper), + (type).trueType, (type).falseType, + type.aliasSymbol, type.aliasTypeArguments, mapper); } function instantiateType(type: Type, mapper: TypeMapper): Type { @@ -8858,6 +8921,9 @@ namespace ts { if (type.flags & TypeFlags.Conditional) { return getConditionalTypeInstantiation(type, mapper); } + if (type.flags & TypeFlags.Extends) { + return getExtendsType(instantiateType((type).checkType, mapper), instantiateType((type).extendsType, mapper)); + } } return type; } @@ -20047,6 +20113,11 @@ namespace ts { checkSourceElement(node.type); } + function checkConditionalType(node: ConditionalTypeNode) { + forEachChild(node, checkSourceElement); + checkTypeAssignableTo(getTypeFromTypeNode(node.conditionType), booleanType, node.conditionType); + } + function isPrivateWithinAmbient(node: Node): boolean { return hasModifier(node, ModifierFlags.Private) && !!(node.flags & NodeFlags.Ambient); } @@ -23687,6 +23758,11 @@ namespace ts { return checkSourceElement((node).type); case SyntaxKind.TypeOperator: return checkTypeOperator(node); + case SyntaxKind.ConditionalType: + return checkConditionalType(node); + case SyntaxKind.BinaryType: + forEachChild(node, checkSourceElement); + return; case SyntaxKind.JSDocAugmentsTag: return checkJSDocAugmentsTag(node as JSDocAugmentsTag); case SyntaxKind.JSDocTypedefTag: diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 4b494bf215e..e61fb4c6e64 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -456,6 +456,8 @@ namespace ts { return emitParenType(type); case SyntaxKind.TypeOperator: return emitTypeOperator(type); + case SyntaxKind.BinaryType: + return emitBinaryType(type); case SyntaxKind.IndexedAccessType: return emitIndexedAccessType(type); case SyntaxKind.MappedType: @@ -548,16 +550,14 @@ namespace ts { } function emitConditionalType(node: ConditionalTypeNode) { - emitType(node.checkType); - write(" extends "); - emitType(node.extendsType); + emitType(node.conditionType); write(" ? "); emitType(node.trueType); write(" : "); emitType(node.falseType); } - function emitParenType(type: ParenthesizedTypeNode) { + function emitParenType(type: ParenthesizedTypeNode) { write("("); emitType(type.type); write(")"); @@ -569,6 +569,12 @@ namespace ts { emitType(type.type); } + function emitBinaryType(node: BinaryTypeNode) { + emitType(node.left); + write(" extends "); + emitType(node.right); + } + function emitIndexedAccessType(node: IndexedAccessTypeNode) { emitType(node.objectType); write("["); diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 10ecd3c8ffe..6b7ae73411c 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -572,6 +572,8 @@ namespace ts { return emitThisType(); case SyntaxKind.TypeOperator: return emitTypeOperator(node); + case SyntaxKind.BinaryType: + return emitBinaryType(node); case SyntaxKind.IndexedAccessType: return emitIndexedAccessType(node); case SyntaxKind.MappedType: @@ -1132,9 +1134,7 @@ namespace ts { } function emitConditionalType(node: ConditionalTypeNode) { - emit(node.checkType); - write(" extends "); - emit(node.extendsType); + emit(node.conditionType); write(" ? "); emit(node.trueType); write(" : "); @@ -1157,6 +1157,12 @@ namespace ts { emit(node.type); } + function emitBinaryType(node: BinaryTypeNode) { + emit(node.left); + write(" extends "); + emit(node.right); + } + function emitIndexedAccessType(node: IndexedAccessTypeNode) { emit(node.objectType); write("["); diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 070715d8ea3..e1cf0d00660 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -720,21 +720,19 @@ namespace ts { : node; } - export function createConditionalTypeNode(checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode) { + export function createConditionalTypeNode(conditionType: TypeNode, trueType: TypeNode, falseType: TypeNode) { const node = createSynthesizedNode(SyntaxKind.ConditionalType) as ConditionalTypeNode; - node.checkType = parenthesizeConditionalTypeMember(checkType); - node.extendsType = parenthesizeConditionalTypeMember(extendsType); + node.conditionType = parenthesizeConditionalTypeMember(conditionType); node.trueType = trueType; node.falseType = falseType; return node; } - export function updateConditionalTypeNode(node: ConditionalTypeNode, checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode) { - return node.checkType !== checkType - || node.extendsType !== extendsType + export function updateConditionalTypeNode(node: ConditionalTypeNode, conditionType: TypeNode, trueType: TypeNode, falseType: TypeNode) { + return node.conditionType !== conditionType || node.trueType !== trueType || node.falseType !== falseType - ? updateNode(createConditionalTypeNode(checkType, extendsType, trueType, falseType), node) + ? updateNode(createConditionalTypeNode(conditionType, trueType, falseType), node) : node; } @@ -767,6 +765,22 @@ namespace ts { return node.type !== type ? updateNode(createTypeOperatorNode(node.operator, type), node) : node; } + export function createBinaryTypeNode(left: TypeNode, operator: SyntaxKind.ExtendsKeyword, right: TypeNode) { + const node = createSynthesizedNode(SyntaxKind.BinaryType) as BinaryTypeNode; + node.left = parenthesizeBinaryTypeMember(left); + node.operator = operator; + node.right = parenthesizeBinaryTypeMember(right); + return node; + } + + export function updateBinaryTypeNode(node: BinaryTypeNode, left: TypeNode, operator: SyntaxKind.ExtendsKeyword, right: TypeNode) { + return node.left !== left + || node.operator !== operator + || node.right !== right + ? updateNode(createBinaryTypeNode(left, operator, right), node) + : node; + } + export function createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode) { const node = createSynthesizedNode(SyntaxKind.IndexedAccessType) as IndexedAccessTypeNode; node.objectType = parenthesizeElementTypeMember(objectType); @@ -4103,6 +4117,10 @@ namespace ts { return member.kind === SyntaxKind.ConditionalType ? createParenthesizedType(member) : member; } + export function parenthesizeBinaryTypeMember(member: TypeNode) { + return member.kind === SyntaxKind.BinaryType ? createParenthesizedType(member) : parenthesizeConditionalTypeMember(member); + } + export function parenthesizeElementTypeMember(member: TypeNode) { switch (member.kind) { case SyntaxKind.UnionType: @@ -4111,7 +4129,7 @@ namespace ts { case SyntaxKind.ConstructorType: return createParenthesizedType(member); } - return parenthesizeConditionalTypeMember(member); + return parenthesizeBinaryTypeMember(member); } export function parenthesizeArrayTypeMember(member: TypeNode) { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 0d8aad97c28..debb4be67ba 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -148,13 +148,15 @@ namespace ts { case SyntaxKind.IntersectionType: return visitNodes(cbNode, cbNodes, (node).types); case SyntaxKind.ConditionalType: - return visitNode(cbNode, (node).checkType) || - visitNode(cbNode, (node).extendsType) || + return visitNode(cbNode, (node).conditionType) || visitNode(cbNode, (node).trueType) || visitNode(cbNode, (node).falseType); case SyntaxKind.ParenthesizedType: case SyntaxKind.TypeOperator: return visitNode(cbNode, (node).type); + case SyntaxKind.BinaryType: + return visitNode(cbNode, (node).left) || + visitNode(cbNode, (node).right); case SyntaxKind.IndexedAccessType: return visitNode(cbNode, (node).objectType) || visitNode(cbNode, (node).indexType); @@ -2848,13 +2850,23 @@ namespace ts { return parseUnionOrIntersectionType(SyntaxKind.UnionType, parseIntersectionTypeOrHigher, SyntaxKind.BarToken); } + function parseBinaryTypeOrHigher(): TypeNode { + let type = parseUnionTypeOrHigher(); + while (parseOptional(SyntaxKind.ExtendsKeyword)) { + const node = createNode(SyntaxKind.BinaryType, type.pos); + node.left = type; + node.operator = SyntaxKind.ExtendsKeyword; + node.right = parseUnionTypeOrHigher(); + type = finishNode(node); + } + return type; + } + function parseConditionalTypeOrHigher(): TypeNode { - const type = parseUnionTypeOrHigher(); - if (parseOptional(SyntaxKind.ExtendsKeyword)) { + const type = parseBinaryTypeOrHigher(); + if (parseOptional(SyntaxKind.QuestionToken)) { const node = createNode(SyntaxKind.ConditionalType, type.pos); - node.checkType = type; - node.extendsType = parseUnionTypeOrHigher(); - parseExpected(SyntaxKind.QuestionToken); + node.conditionType = type; node.trueType = parseConditionalTypeOrHigher(); parseExpected(SyntaxKind.ColonToken); node.falseType = parseConditionalTypeOrHigher(); diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 20bc77c5e17..d29cf209339 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -389,6 +389,7 @@ namespace ts { case SyntaxKind.ParenthesizedType: case SyntaxKind.ThisType: case SyntaxKind.TypeOperator: + case SyntaxKind.BinaryType: case SyntaxKind.IndexedAccessType: case SyntaxKind.MappedType: case SyntaxKind.LiteralType: @@ -1886,6 +1887,7 @@ namespace ts { case SyntaxKind.TypeQuery: case SyntaxKind.TypeOperator: + case SyntaxKind.BinaryType: case SyntaxKind.IndexedAccessType: case SyntaxKind.MappedType: case SyntaxKind.TypeLiteral: diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f1b985f1544..d18181ce1a3 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -252,6 +252,7 @@ namespace ts { ParenthesizedType, ThisType, TypeOperator, + BinaryType, IndexedAccessType, MappedType, LiteralType, @@ -1068,8 +1069,7 @@ namespace ts { export interface ConditionalTypeNode extends TypeNode { kind: SyntaxKind.ConditionalType; - checkType: TypeNode; - extendsType: TypeNode; + conditionType: TypeNode; trueType: TypeNode; falseType: TypeNode; } @@ -1085,6 +1085,13 @@ namespace ts { type: TypeNode; } + export interface BinaryTypeNode extends TypeNode { + kind: SyntaxKind.BinaryType; + left: TypeNode; + operator: SyntaxKind.ExtendsKeyword; + right: TypeNode; + } + /* @internal */ export interface UniqueTypeOperatorNode extends TypeOperatorNode { operator: SyntaxKind.UniqueKeyword; @@ -3348,19 +3355,20 @@ namespace ts { Intersection = 1 << 18, // Intersection (T & U) Index = 1 << 19, // keyof T IndexedAccess = 1 << 20, // T[K] - Conditional = 1 << 21, // A extends B ? T : U + Conditional = 1 << 21, // C ? T : U + Extends = 1 << 22, // T extends U /* @internal */ - FreshLiteral = 1 << 22, // Fresh literal or unique type + FreshLiteral = 1 << 23, // Fresh literal or unique type /* @internal */ - ContainsWideningType = 1 << 23, // Type is or contains undefined or null widening type + ContainsWideningType = 1 << 24, // Type is or contains undefined or null widening type /* @internal */ - ContainsObjectLiteral = 1 << 24, // Type is or contains object literal type + ContainsObjectLiteral = 1 << 25, // Type is or contains object literal type /* @internal */ - ContainsAnyFunctionType = 1 << 25, // Type is or contains the anyFunctionType - NonPrimitive = 1 << 26, // intrinsic object type + ContainsAnyFunctionType = 1 << 26, // Type is or contains the anyFunctionType + NonPrimitive = 1 << 27, // intrinsic object type /* @internal */ - JsxAttributes = 1 << 27, // Jsx attributes type - MarkerType = 1 << 28, // Marker type used for variance probing + JsxAttributes = 1 << 28, // Jsx attributes type + MarkerType = 1 << 29, // Marker type used for variance probing /* @internal */ Nullable = Undefined | Null, @@ -3378,13 +3386,13 @@ namespace ts { Primitive = String | Number | Boolean | Enum | EnumLiteral | ESSymbol | Void | Undefined | Null | Literal | UniqueESSymbol, StringLike = String | StringLiteral | Index, NumberLike = Number | NumberLiteral | Enum, - BooleanLike = Boolean | BooleanLiteral, + BooleanLike = Boolean | BooleanLiteral | Extends, EnumLike = Enum | EnumLiteral, ESSymbolLike = ESSymbol | UniqueESSymbol, UnionOrIntersection = Union | Intersection, StructuredType = Object | Union | Intersection, TypeVariable = TypeParameter | IndexedAccess | Conditional, - StructuredOrTypeVariable = StructuredType | TypeVariable | Index, + StructuredOrTypeVariable = StructuredType | TypeVariable | Index | Extends, // 'Narrowable' types are types where narrowing actually narrows. // This *should* be every type other than null, undefined, void, and never @@ -3637,12 +3645,16 @@ namespace ts { } export interface ConditionalType extends TypeVariable { - checkType: Type; - extendsType: Type; + conditionType: Type; trueType: Type; falseType: Type; } + export interface ExtendsType extends TypeVariable { + checkType: Type; + extendsType: Type; + } + export const enum SignatureKind { Call, Construct, diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 25f16b9a89d..232180901c0 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -4543,6 +4543,10 @@ namespace ts { return node.kind === SyntaxKind.TypeOperator; } + export function isBinaryTypeNode(node: Node): node is BinaryTypeNode { + return node.kind === SyntaxKind.BinaryType; + } + export function isIndexedAccessTypeNode(node: Node): node is IndexedAccessTypeNode { return node.kind === SyntaxKind.IndexedAccessType; } diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index b047a778015..be87c8261f6 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -387,8 +387,7 @@ namespace ts { case SyntaxKind.ConditionalType: return updateConditionalTypeNode(node, - visitNode((node).checkType, visitor, isTypeNode), - visitNode((node).extendsType, visitor, isTypeNode), + visitNode((node).conditionType, visitor, isTypeNode), visitNode((node).trueType, visitor, isTypeNode), visitNode((node).falseType, visitor, isTypeNode)); @@ -400,6 +399,12 @@ namespace ts { return updateTypeOperatorNode(node, visitNode((node).type, visitor, isTypeNode)); + case SyntaxKind.BinaryType: + return updateBinaryTypeNode(node, + visitNode((node).left, visitor, isTypeNode), + (node).operator, + visitNode((node).right, visitor, isTypeNode)); + case SyntaxKind.IndexedAccessType: return updateIndexedAccessTypeNode((node), visitNode((node).objectType, visitor, isTypeNode),