From 57ca7680c9f5ec0d772c9dd94294cbcff2a29129 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 5 Dec 2017 14:18:11 -0800 Subject: [PATCH 01/39] Initial implementation of conditional type operator --- src/compiler/binder.ts | 1 + src/compiler/checker.ts | 52 ++++++++++++++++++++++++++++++ src/compiler/declarationEmitter.ts | 14 +++++++- src/compiler/emitter.ts | 12 +++++++ src/compiler/factory.ts | 24 +++++++++++++- src/compiler/parser.ts | 26 ++++++++++++++- src/compiler/transformers/ts.ts | 1 + src/compiler/types.ts | 37 +++++++++++++++------ src/compiler/utilities.ts | 4 +++ src/compiler/visitor.ts | 7 ++++ 10 files changed, 165 insertions(+), 13 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 71b5e1afbffea..80c8b3dc315b7 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -3416,6 +3416,7 @@ namespace ts { case SyntaxKind.TupleType: case SyntaxKind.UnionType: case SyntaxKind.IntersectionType: + case SyntaxKind.ConditionalType: case SyntaxKind.ParenthesizedType: case SyntaxKind.InterfaceDeclaration: case SyntaxKind.TypeAliasDeclaration: diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2ab67120e4bf5..cbf31179b9272 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2620,6 +2620,13 @@ namespace ts { const indexTypeNode = typeToTypeNodeHelper((type).indexType, context); return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode); } + if (type.flags & TypeFlags.Conditional) { + const checkTypeNode = typeToTypeNodeHelper((type).checkType, context); + const extendskTypeNode = typeToTypeNodeHelper((type).extendsType, context); + const trueTypeNode = typeToTypeNodeHelper((type).trueType, context); + const falseTypeNode = typeToTypeNodeHelper((type).falseType, context); + return createConditionalTypeNode(checkTypeNode, extendskTypeNode, trueTypeNode, falseTypeNode); + } Debug.fail("Should be unreachable."); @@ -3388,6 +3395,15 @@ namespace ts { writeType((type).indexType, TypeFormatFlags.None); writePunctuation(writer, SyntaxKind.CloseBracketToken); } + else if (type.flags & TypeFlags.Conditional) { + writeType((type).checkType, TypeFormatFlags.InElementType); + writer.writeKeyword("extends"); + writeType((type).extendsType, TypeFormatFlags.InElementType); + writePunctuation(writer, SyntaxKind.QuestionToken); + writeType((type).trueType, TypeFormatFlags.InElementType); + writePunctuation(writer, SyntaxKind.ColonToken); + writeType((type).falseType, TypeFormatFlags.InElementType); + } else { // Should never get here // { ... } @@ -8189,6 +8205,35 @@ 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; + } + const type = createType(TypeFlags.Conditional); + type.checkType = checkType; + type.extendsType = extendsType; + type.trueType = trueType; + type.falseType = falseType; + return type; + } + + function getTypeFromConditionalTypeNode(node: ConditionalTypeNode): Type { + const links = getNodeLinks(node); + if (!links.resolvedType) { + links.resolvedType = getConditionalType(getTypeFromTypeNode(node.checkType), getTypeFromTypeNode(node.extendsType), + getTypeFromTypeNode(node.trueType), getTypeFromTypeNode(node.falseType), + getAliasSymbolForTypeNode(node), getAliasTypeArgumentsForTypeNode(node)); + } + return links.resolvedType; + } + function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node: TypeNode): Type { const links = getNodeLinks(node); if (!links.resolvedType) { @@ -8481,6 +8526,8 @@ namespace ts { return getTypeFromIndexedAccessTypeNode(node); case SyntaxKind.MappedType: return getTypeFromMappedTypeNode(node); + case SyntaxKind.ConditionalType: + return getTypeFromConditionalTypeNode(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: @@ -8778,6 +8825,11 @@ namespace ts { if (type.flags & TypeFlags.IndexedAccess) { 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 type; } diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index dc76e0ddf5028..4b494bf215e09 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -450,6 +450,8 @@ namespace ts { return emitUnionType(type); case SyntaxKind.IntersectionType: return emitIntersectionType(type); + case SyntaxKind.ConditionalType: + return emitConditionalType(type); case SyntaxKind.ParenthesizedType: return emitParenType(type); case SyntaxKind.TypeOperator: @@ -545,7 +547,17 @@ namespace ts { emitSeparatedList(type.types, " & ", emitType); } - function emitParenType(type: ParenthesizedTypeNode) { + function emitConditionalType(node: ConditionalTypeNode) { + emitType(node.checkType); + write(" extends "); + emitType(node.extendsType); + write(" ? "); + emitType(node.trueType); + write(" : "); + emitType(node.falseType); + } + + function emitParenType(type: ParenthesizedTypeNode) { write("("); emitType(type.type); write(")"); diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 7a1d88d3bfd71..10ecd3c8ffe74 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -562,6 +562,8 @@ namespace ts { return emitUnionType(node); case SyntaxKind.IntersectionType: return emitIntersectionType(node); + case SyntaxKind.ConditionalType: + return emitConditionalType(node); case SyntaxKind.ParenthesizedType: return emitParenthesizedType(node); case SyntaxKind.ExpressionWithTypeArguments: @@ -1129,6 +1131,16 @@ namespace ts { emitList(node, node.types, ListFormat.IntersectionTypeConstituents); } + function emitConditionalType(node: ConditionalTypeNode) { + emit(node.checkType); + write(" extends "); + emit(node.extendsType); + write(" ? "); + emit(node.trueType); + write(" : "); + emit(node.falseType); + } + function emitParenthesizedType(node: ParenthesizedTypeNode) { write("("); emit(node.type); diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index dfc22e3183374..070715d8ea3fa 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -720,6 +720,24 @@ namespace ts { : node; } + export function createConditionalTypeNode(checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode) { + const node = createSynthesizedNode(SyntaxKind.ConditionalType) as ConditionalTypeNode; + node.checkType = parenthesizeConditionalTypeMember(checkType); + node.extendsType = parenthesizeConditionalTypeMember(extendsType); + 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 + || node.trueType !== trueType + || node.falseType !== falseType + ? updateNode(createConditionalTypeNode(checkType, extendsType, trueType, falseType), node) + : node; + } + export function createParenthesizedType(type: TypeNode) { const node = createSynthesizedNode(SyntaxKind.ParenthesizedType); node.type = type; @@ -4081,6 +4099,10 @@ namespace ts { return expression; } + export function parenthesizeConditionalTypeMember(member: TypeNode) { + return member.kind === SyntaxKind.ConditionalType ? createParenthesizedType(member) : member; + } + export function parenthesizeElementTypeMember(member: TypeNode) { switch (member.kind) { case SyntaxKind.UnionType: @@ -4089,7 +4111,7 @@ namespace ts { case SyntaxKind.ConstructorType: return createParenthesizedType(member); } - return member; + return parenthesizeConditionalTypeMember(member); } export function parenthesizeArrayTypeMember(member: TypeNode) { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index cb28be4677a5b..0d8aad97c289a 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -147,6 +147,11 @@ namespace ts { case SyntaxKind.UnionType: case SyntaxKind.IntersectionType: return visitNodes(cbNode, cbNodes, (node).types); + case SyntaxKind.ConditionalType: + return visitNode(cbNode, (node).checkType) || + visitNode(cbNode, (node).extendsType) || + visitNode(cbNode, (node).trueType) || + visitNode(cbNode, (node).falseType); case SyntaxKind.ParenthesizedType: case SyntaxKind.TypeOperator: return visitNode(cbNode, (node).type); @@ -2760,6 +2765,10 @@ namespace ts { type = createJSDocPostfixType(SyntaxKind.JSDocNonNullableType, type); break; case SyntaxKind.QuestionToken: + // only parse postfix ? inside jsdoc, otherwise it is a conditional type + if (!(contextFlags & NodeFlags.JSDoc)) { + return type; + } type = createJSDocPostfixType(SyntaxKind.JSDocNullableType, type); break; case SyntaxKind.OpenBracketToken: @@ -2839,6 +2848,21 @@ namespace ts { return parseUnionOrIntersectionType(SyntaxKind.UnionType, parseIntersectionTypeOrHigher, SyntaxKind.BarToken); } + function parseConditionalTypeOrHigher(): TypeNode { + const type = parseUnionTypeOrHigher(); + if (parseOptional(SyntaxKind.ExtendsKeyword)) { + const node = createNode(SyntaxKind.ConditionalType, type.pos); + node.checkType = type; + node.extendsType = parseUnionTypeOrHigher(); + parseExpected(SyntaxKind.QuestionToken); + node.trueType = parseConditionalTypeOrHigher(); + parseExpected(SyntaxKind.ColonToken); + node.falseType = parseConditionalTypeOrHigher(); + return finishNode(node); + } + return type; + } + function isStartOfFunctionType(): boolean { if (token() === SyntaxKind.LessThanToken) { return true; @@ -2928,7 +2952,7 @@ namespace ts { if (token() === SyntaxKind.NewKeyword) { return parseFunctionOrConstructorType(SyntaxKind.ConstructorType); } - return parseUnionTypeOrHigher(); + return parseConditionalTypeOrHigher(); } function parseTypeAnnotation(): TypeNode { diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 3c1bba280f0f9..20bc77c5e17e1 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -385,6 +385,7 @@ namespace ts { case SyntaxKind.TypeReference: case SyntaxKind.UnionType: case SyntaxKind.IntersectionType: + case SyntaxKind.ConditionalType: case SyntaxKind.ParenthesizedType: case SyntaxKind.ThisType: case SyntaxKind.TypeOperator: diff --git a/src/compiler/types.ts b/src/compiler/types.ts index af92654c0a538..f1b985f154488 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -248,6 +248,7 @@ namespace ts { TupleType, UnionType, IntersectionType, + ConditionalType, ParenthesizedType, ThisType, TypeOperator, @@ -1065,6 +1066,14 @@ namespace ts { types: NodeArray; } + export interface ConditionalTypeNode extends TypeNode { + kind: SyntaxKind.ConditionalType; + checkType: TypeNode; + extendsType: TypeNode; + trueType: TypeNode; + falseType: TypeNode; + } + export interface ParenthesizedTypeNode extends TypeNode { kind: SyntaxKind.ParenthesizedType; type: TypeNode; @@ -3339,18 +3348,19 @@ 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 /* @internal */ - FreshLiteral = 1 << 21, // Fresh literal or unique type + FreshLiteral = 1 << 22, // Fresh literal or unique type /* @internal */ - ContainsWideningType = 1 << 22, // Type is or contains undefined or null widening type + ContainsWideningType = 1 << 23, // Type is or contains undefined or null widening type /* @internal */ - ContainsObjectLiteral = 1 << 23, // Type is or contains object literal type + ContainsObjectLiteral = 1 << 24, // Type is or contains object literal type /* @internal */ - ContainsAnyFunctionType = 1 << 24, // Type is or contains the anyFunctionType - NonPrimitive = 1 << 25, // intrinsic object type + ContainsAnyFunctionType = 1 << 25, // Type is or contains the anyFunctionType + NonPrimitive = 1 << 26, // intrinsic object type /* @internal */ - JsxAttributes = 1 << 26, // Jsx attributes type - MarkerType = 1 << 27, // Marker type used for variance probing + JsxAttributes = 1 << 27, // Jsx attributes type + MarkerType = 1 << 28, // Marker type used for variance probing /* @internal */ Nullable = Undefined | Null, @@ -3373,12 +3383,12 @@ namespace ts { ESSymbolLike = ESSymbol | UniqueESSymbol, UnionOrIntersection = Union | Intersection, StructuredType = Object | Union | Intersection, - StructuredOrTypeVariable = StructuredType | TypeParameter | Index | IndexedAccess, - TypeVariable = TypeParameter | IndexedAccess, + TypeVariable = TypeParameter | IndexedAccess | Conditional, + StructuredOrTypeVariable = StructuredType | TypeVariable | Index, // 'Narrowable' types are types where narrowing actually narrows. // This *should* be every type other than null, undefined, void, and never - Narrowable = Any | StructuredType | TypeParameter | Index | IndexedAccess | StringLike | NumberLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive, + Narrowable = Any | StructuredOrTypeVariable | StringLike | NumberLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive, NotUnionOrUnit = Any | ESSymbol | Object | NonPrimitive, /* @internal */ RequiresWidening = ContainsWideningType | ContainsObjectLiteral, @@ -3626,6 +3636,13 @@ namespace ts { type: TypeVariable | UnionOrIntersectionType; } + export interface ConditionalType extends TypeVariable { + checkType: Type; + extendsType: Type; + trueType: Type; + falseType: Type; + } + export const enum SignatureKind { Call, Construct, diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 0e62c2d8ceadd..25f16b9a89d1a 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -4527,6 +4527,10 @@ namespace ts { return node.kind === SyntaxKind.IntersectionType; } + export function isConditionalTypeNode(node: Node): node is ConditionalTypeNode { + return node.kind === SyntaxKind.ConditionalType; + } + export function isParenthesizedTypeNode(node: Node): node is ParenthesizedTypeNode { return node.kind === SyntaxKind.ParenthesizedType; } diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 0b40e20a7b7c1..b047a778015b4 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -385,6 +385,13 @@ namespace ts { return updateIntersectionTypeNode(node, nodesVisitor((node).types, visitor, isTypeNode)); + case SyntaxKind.ConditionalType: + return updateConditionalTypeNode(node, + visitNode((node).checkType, visitor, isTypeNode), + visitNode((node).extendsType, visitor, isTypeNode), + visitNode((node).trueType, visitor, isTypeNode), + visitNode((node).falseType, visitor, isTypeNode)); + case SyntaxKind.ParenthesizedType: return updateParenthesizedType(node, visitNode((node).type, visitor, isTypeNode)); From 063eed1a47b873a60e804d748dbe2959f9b51d70 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 8 Dec 2017 10:19:23 -0800 Subject: [PATCH 02/39] 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 cbf31179b9272..dc45c7d2f513c 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)) { From ec2bdfdb8b0b6bb1940d1659e310c6cf858d009c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 12 Dec 2017 09:52:14 -0800 Subject: [PATCH 03/39] Add 'T extends U' type operator --- src/compiler/binder.ts | 1 + src/compiler/checker.ts | 142 ++++++++++++++++++++++------- src/compiler/declarationEmitter.ts | 14 ++- src/compiler/emitter.ts | 12 ++- src/compiler/factory.ts | 34 +++++-- src/compiler/parser.ts | 26 ++++-- src/compiler/transformers/ts.ts | 2 + src/compiler/types.ts | 40 +++++--- src/compiler/utilities.ts | 4 + src/compiler/visitor.ts | 9 +- 10 files changed, 213 insertions(+), 71 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 80c8b3dc315b7..1fbd53c1e4010 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 dc45c7d2f513c..4f002f41c5dd5 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 4b494bf215e09..e61fb4c6e64fe 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 10ecd3c8ffe74..6b7ae73411c47 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 070715d8ea3fa..e1cf0d00660af 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 0d8aad97c289a..debb4be67ba73 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 20bc77c5e17e1..d29cf2093398f 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 f1b985f154488..d18181ce1a3dd 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 25f16b9a89d1a..232180901c0ce 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 b047a778015b4..be87c8261f62e 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), From 43e195d966f65b019f15e2cbc7c16a6e2e47b8d9 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 12 Dec 2017 10:44:43 -0800 Subject: [PATCH 04/39] Clean up isGenericXXXType functions --- src/compiler/checker.ts | 27 ++++++++++++--------------- src/compiler/types.ts | 2 ++ 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4f002f41c5dd5..e2c194ef60bb2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8109,22 +8109,11 @@ namespace ts { } function isGenericObjectType(type: Type): boolean { - return type.flags & TypeFlags.TypeVariable ? true : - getObjectFlags(type) & ObjectFlags.Mapped ? isGenericIndexType(getConstraintTypeFromMappedType(type)) : - type.flags & TypeFlags.UnionOrIntersection ? forEach((type).types, isGenericObjectType) : - false; + return maybeTypeOfKind(type, TypeFlags.TypeVariable | TypeFlags.GenericMappedType); } function isGenericIndexType(type: Type): boolean { - return type.flags & (TypeFlags.TypeVariable | TypeFlags.Index) ? true : - type.flags & TypeFlags.UnionOrIntersection ? forEach((type).types, isGenericIndexType) : - false; - } - - function isGenericConditionType(type: Type): boolean { - return type.flags & (TypeFlags.TypeVariable | TypeFlags.Extends) ? true : - type.flags & TypeFlags.UnionOrIntersection ? forEach((type).types, isGenericConditionType) : - false; + return maybeTypeOfKind(type, TypeFlags.TypeVariable | TypeFlags.Index); } // Return true if the given type is a non-generic object type with a string index signature and no @@ -8234,6 +8223,10 @@ namespace ts { return links.resolvedType; } + function isGenericConditionType(type: Type) { + return maybeTypeOfKind(type, TypeFlags.TypeVariable | TypeFlags.Extends); + } + function createConditionalType(conditionType: Type, whenTrueType: Type, whenFalseType: Type, aliasSymbol: Symbol, aliasTypeArguments: Type[]) { const type = createType(TypeFlags.Conditional); type.conditionType = conditionType; @@ -8271,6 +8264,10 @@ namespace ts { return links.resolvedType; } + function isGenericExtendsType(type: Type) { + return maybeTypeOfKind(type, TypeFlags.TypeVariable | TypeFlags.GenericMappedType | TypeFlags.Index | TypeFlags.Extends); + } + function createExtendsType(checkType: Type, extendsType: Type) { const type = createType(TypeFlags.Extends); type.checkType = checkType; @@ -8286,7 +8283,7 @@ namespace ts { if (checkType.flags & TypeFlags.Any) { return booleanType; } - if (!isGenericObjectType(checkType) && !isGenericObjectType(extendsType)) { + if (!isGenericExtendsType(checkType) && !isGenericExtendsType(extendsType)) { return isTypeAssignableTo(checkType, extendsType) ? trueType : falseType; } const id = checkType.id + "," + extendsType.id; @@ -18459,7 +18456,7 @@ namespace ts { // Return true if type might be of the given kind. A union or intersection type might be of a given // kind if at least one constituent type is of the given kind. function maybeTypeOfKind(type: Type, kind: TypeFlags): boolean { - if (type.flags & kind) { + if (type.flags & kind || kind & TypeFlags.GenericMappedType && isGenericMappedType(type)) { return true; } if (type.flags & TypeFlags.UnionOrIntersection) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index d18181ce1a3dd..7436701cf6400 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3402,6 +3402,8 @@ namespace ts { RequiresWidening = ContainsWideningType | ContainsObjectLiteral, /* @internal */ PropagatingFlags = ContainsWideningType | ContainsObjectLiteral | ContainsAnyFunctionType, + /* @internal */ + GenericMappedType = MarkerType, // Flag used by maybeTypeOfKind } export type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression; From 61225cc57c1ae9c2aea8ecbd15d24b55e9f3d02f Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 13 Dec 2017 09:14:57 -0800 Subject: [PATCH 05/39] Introduce TypeFlags.Instatiable --- src/compiler/checker.ts | 43 ++++++++++++++++++++++------------------- src/compiler/types.ts | 9 ++++++--- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e2c194ef60bb2..f643541a32929 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6099,7 +6099,7 @@ namespace ts { // First, if the constraint type is a type parameter, obtain the base constraint. Then, // if the key type is a 'keyof X', obtain 'keyof C' where C is the base constraint of X. // Finally, iterate over the constituents of the resulting iteration type. - const keyType = constraintType.flags & TypeFlags.TypeVariable ? getApparentType(constraintType) : constraintType; + const keyType = constraintType.flags & TypeFlags.InstantiableNonPrimitive ? getApparentType(constraintType) : constraintType; const iterationType = keyType.flags & TypeFlags.Index ? getIndexType(getApparentType((keyType).type)) : keyType; forEachType(iterationType, addMemberForKeyType); } @@ -6315,7 +6315,7 @@ namespace ts { } function getBaseConstraintOfType(type: Type): Type { - if (type.flags & (TypeFlags.TypeVariable | TypeFlags.UnionOrIntersection)) { + if (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.UnionOrIntersection)) { const constraint = getResolvedBaseConstraint(type); if (constraint !== noConstraintType && constraint !== circularConstraintType) { return constraint; @@ -6324,6 +6324,9 @@ namespace ts { else if (type.flags & TypeFlags.Index) { return stringType; } + else if (type.flags & TypeFlags.Extends) { + return booleanType; + } return undefined; } @@ -6461,7 +6464,7 @@ namespace ts { * type itself. Note that the apparent type of a union type is the union type itself. */ function getApparentType(type: Type): Type { - const t = type.flags & TypeFlags.TypeVariable ? getBaseConstraintOfType(type) || emptyObjectType : type; + const t = type.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(type) || emptyObjectType : type; return t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(t) : t.flags & TypeFlags.StringLike ? globalStringType : t.flags & TypeFlags.NumberLike ? globalNumberType : @@ -8011,10 +8014,10 @@ namespace ts { } function getIndexType(type: Type): Type { - return maybeTypeOfKind(type, TypeFlags.TypeVariable) ? getIndexTypeForGenericType(type) : + return maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive) ? getIndexTypeForGenericType(type) : getObjectFlags(type) & ObjectFlags.Mapped ? getConstraintTypeFromMappedType(type) : - type.flags & TypeFlags.Any || getIndexInfoOfType(type, IndexKind.String) ? stringType : - getLiteralTypeFromPropertyNames(type); + type.flags & TypeFlags.Any || getIndexInfoOfType(type, IndexKind.String) ? stringType : + getLiteralTypeFromPropertyNames(type); } function getIndexTypeOrString(type: Type): Type { @@ -8109,11 +8112,11 @@ namespace ts { } function isGenericObjectType(type: Type): boolean { - return maybeTypeOfKind(type, TypeFlags.TypeVariable | TypeFlags.GenericMappedType); + return maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive | TypeFlags.GenericMappedType); } function isGenericIndexType(type: Type): boolean { - return maybeTypeOfKind(type, TypeFlags.TypeVariable | TypeFlags.Index); + return maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive | TypeFlags.Index); } // Return true if the given type is a non-generic object type with a string index signature and no @@ -8224,7 +8227,7 @@ namespace ts { } function isGenericConditionType(type: Type) { - return maybeTypeOfKind(type, TypeFlags.TypeVariable | TypeFlags.Extends); + return maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive | TypeFlags.Extends); } function createConditionalType(conditionType: Type, whenTrueType: Type, whenFalseType: Type, aliasSymbol: Symbol, aliasTypeArguments: Type[]) { @@ -8265,7 +8268,7 @@ namespace ts { } function isGenericExtendsType(type: Type) { - return maybeTypeOfKind(type, TypeFlags.TypeVariable | TypeFlags.GenericMappedType | TypeFlags.Index | TypeFlags.Extends); + return maybeTypeOfKind(type, TypeFlags.Instantiable | TypeFlags.GenericMappedType); } function createExtendsType(checkType: Type, extendsType: Type) { @@ -9042,7 +9045,7 @@ namespace ts { function isTypeDerivedFrom(source: Type, target: Type): boolean { return source.flags & TypeFlags.Union ? every((source).types, t => isTypeDerivedFrom(t, target)) : target.flags & TypeFlags.Union ? some((target).types, t => isTypeDerivedFrom(source, t)) : - source.flags & TypeFlags.TypeVariable ? isTypeDerivedFrom(getBaseConstraintOfType(source) || emptyObjectType, target) : + source.flags & TypeFlags.InstantiableNonPrimitive ? isTypeDerivedFrom(getBaseConstraintOfType(source) || emptyObjectType, target) : target === globalObjectType || target === globalFunctionType ? isTypeSubtypeOf(source, target) : hasBaseType(source, getTargetType(target)); } @@ -9379,7 +9382,7 @@ namespace ts { return related === RelationComparisonResult.Succeeded; } } - if (source.flags & TypeFlags.StructuredOrTypeVariable || target.flags & TypeFlags.StructuredOrTypeVariable) { + if (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable) { return checkTypeRelatedTo(source, target, relation, /*errorNode*/ undefined); } return false; @@ -9585,7 +9588,7 @@ namespace ts { // breaking the intersection apart. result = someTypeRelatedToType(source, target, /*reportErrors*/ false); } - if (!result && (source.flags & TypeFlags.StructuredOrTypeVariable || target.flags & TypeFlags.StructuredOrTypeVariable)) { + if (!result && (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable)) { if (result = recursiveTypeRelatedTo(source, target, reportErrors)) { errorInfo = saveErrorInfo; } @@ -11230,7 +11233,7 @@ namespace ts { // results for union and intersection types for performance reasons. function couldContainTypeVariables(type: Type): boolean { const objectFlags = getObjectFlags(type); - return !!(type.flags & (TypeFlags.TypeVariable | TypeFlags.Index) || + return !!(type.flags & TypeFlags.Instantiable || objectFlags & ObjectFlags.Reference && forEach((type).typeArguments, couldContainTypeVariables) || objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.Class) || objectFlags & ObjectFlags.Mapped || @@ -12026,7 +12029,7 @@ namespace ts { if (flags & TypeFlags.NonPrimitive) { return strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts; } - if (flags & TypeFlags.TypeVariable) { + if (flags & TypeFlags.Instantiable) { return getTypeFacts(getBaseConstraintOfType(type) || emptyObjectType); } if (flags & TypeFlags.UnionOrIntersection) { @@ -12878,7 +12881,7 @@ namespace ts { if (isTypeSubtypeOf(targetType, type)) { return targetType; } - if (type.flags & TypeFlags.TypeVariable) { + if (type.flags & TypeFlags.Instantiable) { const constraint = getBaseConstraintOfType(type) || anyType; if (isTypeSubtypeOf(targetType, constraint)) { return getIntersectionType([type, targetType]); @@ -13141,7 +13144,7 @@ namespace ts { } function typeHasNullableConstraint(type: Type) { - return type.flags & TypeFlags.TypeVariable && maybeTypeOfKind(getBaseConstraintOfType(type) || emptyObjectType, TypeFlags.Nullable); + return type.flags & TypeFlags.InstantiableNonPrimitive && maybeTypeOfKind(getBaseConstraintOfType(type) || emptyObjectType, TypeFlags.Nullable); } function getDeclaredOrApparentType(symbol: Symbol, node: Node) { @@ -18535,7 +18538,7 @@ namespace ts { if (!(isTypeComparableTo(leftType, stringType) || isTypeAssignableToKind(leftType, TypeFlags.NumberLike | TypeFlags.ESSymbolLike))) { error(left, Diagnostics.The_left_hand_side_of_an_in_expression_must_be_of_type_any_string_number_or_symbol); } - if (!isTypeAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.TypeVariable)) { + if (!isTypeAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive)) { error(right, Diagnostics.The_right_hand_side_of_an_in_expression_must_be_of_type_any_an_object_type_or_a_type_parameter); } return booleanType; @@ -19132,7 +19135,7 @@ namespace ts { !(t.flags & TypeFlags.BooleanLiteral && containsType(types, trueType) && containsType(types, falseType)) && isLiteralOfContextualType(candidateType, t)); } - if (contextualType.flags & TypeFlags.TypeVariable) { + if (contextualType.flags & TypeFlags.InstantiableNonPrimitive) { // If the contextual type is a type variable constrained to a primitive type, consider // this a literal context for literals of that primitive type. For example, given a // type parameter 'T extends string', infer string literal types for T. @@ -21878,7 +21881,7 @@ namespace ts { // unknownType is returned i.e. if node.expression is identifier whose name cannot be resolved // in this case error about missing name is already reported - do not report extra one - if (!isTypeAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.TypeVariable)) { + if (!isTypeAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive)) { error(node.expression, Diagnostics.The_right_hand_side_of_a_for_in_statement_must_be_of_type_any_an_object_type_or_a_type_parameter); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 7436701cf6400..0f7b8aada5bf9 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3391,12 +3391,15 @@ namespace ts { ESSymbolLike = ESSymbol | UniqueESSymbol, UnionOrIntersection = Union | Intersection, StructuredType = Object | Union | Intersection, - TypeVariable = TypeParameter | IndexedAccess | Conditional, - StructuredOrTypeVariable = StructuredType | TypeVariable | Index | Extends, + TypeVariable = TypeParameter | IndexedAccess, + InstantiableNonPrimitive = TypeVariable | Conditional, + InstantiablePrimitive = Index | Extends, + Instantiable = InstantiableNonPrimitive | InstantiablePrimitive, + StructuredOrInstantiable = StructuredType | Instantiable, // 'Narrowable' types are types where narrowing actually narrows. // This *should* be every type other than null, undefined, void, and never - Narrowable = Any | StructuredOrTypeVariable | StringLike | NumberLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive, + Narrowable = Any | StructuredOrInstantiable | StringLike | NumberLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive, NotUnionOrUnit = Any | ESSymbol | Object | NonPrimitive, /* @internal */ RequiresWidening = ContainsWideningType | ContainsObjectLiteral, From 9f74a7a22887a0e5f85171640b01f66df193b37f Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 13 Dec 2017 09:24:14 -0800 Subject: [PATCH 06/39] Rename TypeVariable to InstantiableType --- src/compiler/checker.ts | 16 ++++++++-------- src/compiler/types.ts | 14 +++++++------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f643541a32929..344ad57de33a3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6294,7 +6294,7 @@ namespace ts { return arrayFrom(props.values()); } - function getConstraintOfType(type: TypeVariable | UnionOrIntersectionType): Type { + function getConstraintOfType(type: InstantiableType | UnionOrIntersectionType): Type { return type.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(type) : type.flags & TypeFlags.IndexedAccess ? getConstraintOfIndexedAccess(type) : getBaseConstraintOfType(type); @@ -6316,7 +6316,7 @@ namespace ts { function getBaseConstraintOfType(type: Type): Type { if (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.UnionOrIntersection)) { - const constraint = getResolvedBaseConstraint(type); + const constraint = getResolvedBaseConstraint(type); if (constraint !== noConstraintType && constraint !== circularConstraintType) { return constraint; } @@ -6330,7 +6330,7 @@ namespace ts { return undefined; } - function hasNonCircularBaseConstraint(type: TypeVariable): boolean { + function hasNonCircularBaseConstraint(type: InstantiableType): boolean { return getResolvedBaseConstraint(type) !== circularConstraintType; } @@ -6339,7 +6339,7 @@ namespace ts { * type variable has no constraint, and the circularConstraintType singleton is returned if the constraint * circularly references the type variable. */ - function getResolvedBaseConstraint(type: TypeVariable | UnionOrIntersectionType): Type { + function getResolvedBaseConstraint(type: InstantiableType | UnionOrIntersectionType): Type { let typeStack: Type[]; let circular: boolean; if (!type.resolvedBaseConstraint) { @@ -7995,7 +7995,7 @@ namespace ts { return links.resolvedType; } - function getIndexTypeForGenericType(type: TypeVariable | UnionOrIntersectionType) { + function getIndexTypeForGenericType(type: InstantiableType | UnionOrIntersectionType) { if (!type.resolvedIndexType) { type.resolvedIndexType = createType(TypeFlags.Index); type.resolvedIndexType.type = type; @@ -8014,7 +8014,7 @@ namespace ts { } function getIndexType(type: Type): Type { - return maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive) ? getIndexTypeForGenericType(type) : + return maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive) ? getIndexTypeForGenericType(type) : getObjectFlags(type) & ObjectFlags.Mapped ? getConstraintTypeFromMappedType(type) : type.flags & TypeFlags.Any || getIndexInfoOfType(type, IndexKind.String) ? stringType : getLiteralTypeFromPropertyNames(type); @@ -11449,11 +11449,11 @@ namespace ts { else if (target.flags & TypeFlags.UnionOrIntersection) { const targetTypes = (target).types; let typeVariableCount = 0; - let typeVariable: TypeVariable; + let typeVariable: TypeParameter | IndexedAccessType; // First infer to each type in union or intersection that isn't a type variable for (const t of targetTypes) { if (getInferenceInfoForType(t)) { - typeVariable = t; + typeVariable = t; typeVariableCount++; } else { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0f7b8aada5bf9..2ba528b59f80e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3612,7 +3612,7 @@ namespace ts { syntheticType?: Type; } - export interface TypeVariable extends Type { + export interface InstantiableType extends Type { /* @internal */ resolvedBaseConstraint?: Type; /* @internal */ @@ -3620,7 +3620,7 @@ namespace ts { } // Type parameters (TypeFlags.TypeParameter) - export interface TypeParameter extends TypeVariable { + export interface TypeParameter extends InstantiableType { /** Retrieve using getConstraintFromTypeParameter */ /* @internal */ constraint?: Type; // Constraint @@ -3638,24 +3638,24 @@ namespace ts { // Indexed access types (TypeFlags.IndexedAccess) // Possible forms are T[xxx], xxx[T], or xxx[keyof T], where T is a type variable - export interface IndexedAccessType extends TypeVariable { + export interface IndexedAccessType extends InstantiableType { objectType: Type; indexType: Type; constraint?: Type; } // keyof T types (TypeFlags.Index) - export interface IndexType extends Type { - type: TypeVariable | UnionOrIntersectionType; + export interface IndexType extends InstantiableType { + type: InstantiableType | UnionOrIntersectionType; } - export interface ConditionalType extends TypeVariable { + export interface ConditionalType extends InstantiableType { conditionType: Type; trueType: Type; falseType: Type; } - export interface ExtendsType extends TypeVariable { + export interface ExtendsType extends InstantiableType { checkType: Type; extendsType: Type; } From 20434fabe66cca85208dd7f5be3890a3db29d0c6 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 13 Dec 2017 09:48:51 -0800 Subject: [PATCH 07/39] Inference for conditional and extends type operators --- src/compiler/checker.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 344ad57de33a3..106d6391a9118 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11416,7 +11416,7 @@ namespace ts { return; } } - else if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target) { + if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target) { // If source and target are references to the same generic type, infer from type arguments const sourceTypes = (source).typeArguments || emptyArray; const targetTypes = (target).typeArguments || emptyArray; @@ -11446,6 +11446,15 @@ namespace ts { inferFromTypes((source).objectType, (target).objectType); inferFromTypes((source).indexType, (target).indexType); } + else if (source.flags & TypeFlags.Conditional && target.flags & TypeFlags.Conditional) { + inferFromTypes((source).conditionType, (target).conditionType); + inferFromTypes((source).trueType, (target).trueType); + inferFromTypes((source).falseType, (target).falseType); + } + else if (source.flags & TypeFlags.Extends && target.flags & TypeFlags.Extends) { + inferFromTypes((source).checkType, (target).checkType); + inferFromTypes((source).extendsType, (target).extendsType); + } else if (target.flags & TypeFlags.UnionOrIntersection) { const targetTypes = (target).types; let typeVariableCount = 0; From ddc631c5d47150d5227470d64853a059d839e011 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 13 Dec 2017 13:41:17 -0800 Subject: [PATCH 08/39] Fix typo --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 106d6391a9118..f4e10aac60651 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6394,7 +6394,7 @@ namespace ts { } if (t.flags & TypeFlags.Conditional) { const trueBaseType = getBaseConstraint((t).trueType); - const falseBaseType = getBaseConstraint((t).trueType); + const falseBaseType = getBaseConstraint((t).falseType); return trueBaseType && falseBaseType ? getUnionType([trueBaseType, falseBaseType]) : undefined; } if (t.flags & TypeFlags.Extends) { From 000f121d348913ca13ba1354f21adaf10eabc3c4 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 13 Dec 2017 15:07:16 -0800 Subject: [PATCH 09/39] Improve conditional type constraint checking --- src/compiler/checker.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f4e10aac60651..4f79b94a52098 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6297,7 +6297,8 @@ namespace ts { function getConstraintOfType(type: InstantiableType | UnionOrIntersectionType): Type { return type.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(type) : type.flags & TypeFlags.IndexedAccess ? getConstraintOfIndexedAccess(type) : - getBaseConstraintOfType(type); + type.flags & TypeFlags.Conditional ? getConstraintOfConditionalType(type) : + getBaseConstraintOfType(type); } function getConstraintOfTypeParameter(typeParameter: TypeParameter): Type { @@ -6314,6 +6315,10 @@ namespace ts { return baseObjectType || baseIndexType ? getIndexedAccessType(baseObjectType || type.objectType, baseIndexType || type.indexType) : undefined; } + function getConstraintOfConditionalType(type: ConditionalType) { + return getUnionType([type.trueType, type.falseType]); + } + function getBaseConstraintOfType(type: Type): Type { if (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.UnionOrIntersection)) { const constraint = getResolvedBaseConstraint(type); @@ -6393,9 +6398,7 @@ namespace ts { return baseIndexedAccess && baseIndexedAccess !== unknownType ? getBaseConstraint(baseIndexedAccess) : undefined; } if (t.flags & TypeFlags.Conditional) { - const trueBaseType = getBaseConstraint((t).trueType); - const falseBaseType = getBaseConstraint((t).falseType); - return trueBaseType && falseBaseType ? getUnionType([trueBaseType, falseBaseType]) : undefined; + return getBaseConstraint(getConstraintOfConditionalType(t)); } if (t.flags & TypeFlags.Extends) { return booleanType; @@ -9988,12 +9991,9 @@ namespace ts { } } else if (source.flags & TypeFlags.Conditional) { - const constraint = getConstraintOfType(source); - if (constraint) { - if (result = isRelatedTo(constraint, target, reportErrors)) { - errorInfo = saveErrorInfo; - return result; - } + if (result = isRelatedTo(getConstraintOfConditionalType(source), target, reportErrors)) { + errorInfo = saveErrorInfo; + return result; } } else { From 27b945b898d0ec2bf9914981b38047e8206993ec Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 16 Dec 2017 09:51:18 -0800 Subject: [PATCH 10/39] Handle constraints for distributive conditional types --- src/compiler/checker.ts | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4f79b94a52098..47cc3bbab1fd3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6315,10 +6315,33 @@ namespace ts { return baseObjectType || baseIndexType ? getIndexedAccessType(baseObjectType || type.objectType, baseIndexType || type.indexType) : undefined; } - function getConstraintOfConditionalType(type: ConditionalType) { + function getDefaultConstraintOfConditionalType(type: ConditionalType) { return getUnionType([type.trueType, type.falseType]); } + function getConstraintOfDistributiveConditionalType(type: ConditionalType) { + // Check if we have a conditional type of the form 'T extends U ? X : Y', where T is a constrained + // type parameter. If so, create an instantiation of the conditional type where T is replaced + // with its constraint. We do this because if the constraint is a union type it will be distributed + // over the conditional type and possibly reduced. For example, 'T extends undefined ? never : T' + // removes 'undefined' from T. + const conditionType = type.conditionType; + if (conditionType.flags & TypeFlags.Extends) { + const checkType = (conditionType).checkType; + if (checkType.flags & TypeFlags.TypeParameter) { + const constraint = getConstraintOfTypeParameter(checkType); + if (constraint) { + return instantiateType(type, createTypeMapper([checkType], [constraint])); + } + } + } + return undefined; + } + + function getConstraintOfConditionalType(type: ConditionalType) { + return getConstraintOfDistributiveConditionalType(type) || getDefaultConstraintOfConditionalType(type); + } + function getBaseConstraintOfType(type: Type): Type { if (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.UnionOrIntersection)) { const constraint = getResolvedBaseConstraint(type); @@ -8870,6 +8893,9 @@ namespace ts { } function getConditionalTypeInstantiation(type: ConditionalType, mapper: TypeMapper): Type { + // Check if we have a conditional type of the form T extends U ? X : Y, where T is a type parameter. + // If so, the conditional type is distributive over a union type and when T is instantiated to a union + // type A | B, we produce (A extends U ? X : Y) | (B extends U ? X : Y). const conditionType = type.conditionType; if (conditionType.flags & TypeFlags.Extends) { const checkType = (conditionType).checkType; @@ -9991,7 +10017,14 @@ namespace ts { } } else if (source.flags & TypeFlags.Conditional) { - if (result = isRelatedTo(getConstraintOfConditionalType(source), target, reportErrors)) { + const constraint = getConstraintOfDistributiveConditionalType(source); + if (constraint) { + if (result = isRelatedTo(constraint, target, reportErrors)) { + errorInfo = saveErrorInfo; + return result; + } + } + if (result = isRelatedTo(getDefaultConstraintOfConditionalType(source), target, reportErrors)) { errorInfo = saveErrorInfo; return result; } From f59e2e63316fc826142d88d52f007625ed646c04 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 17 Dec 2017 09:16:12 -0800 Subject: [PATCH 11/39] Accept new baselines --- .../reference/api/tsserverlibrary.d.ts | 322 ++++++++++-------- tests/baselines/reference/api/typescript.d.ts | 322 ++++++++++-------- .../jsdocDisallowedInTypescript.errors.txt | 60 +--- .../jsdocDisallowedInTypescript.types | 4 +- .../reference/recursiveTypeRelations.types | 6 +- 5 files changed, 371 insertions(+), 343 deletions(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index c127232c099d9..eb6557439fe48 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -229,134 +229,136 @@ declare namespace ts { TupleType = 166, UnionType = 167, IntersectionType = 168, - ParenthesizedType = 169, - ThisType = 170, - TypeOperator = 171, - IndexedAccessType = 172, - MappedType = 173, - LiteralType = 174, - ObjectBindingPattern = 175, - ArrayBindingPattern = 176, - BindingElement = 177, - ArrayLiteralExpression = 178, - ObjectLiteralExpression = 179, - PropertyAccessExpression = 180, - ElementAccessExpression = 181, - CallExpression = 182, - NewExpression = 183, - TaggedTemplateExpression = 184, - TypeAssertionExpression = 185, - ParenthesizedExpression = 186, - FunctionExpression = 187, - ArrowFunction = 188, - DeleteExpression = 189, - TypeOfExpression = 190, - VoidExpression = 191, - AwaitExpression = 192, - PrefixUnaryExpression = 193, - PostfixUnaryExpression = 194, - BinaryExpression = 195, - ConditionalExpression = 196, - TemplateExpression = 197, - YieldExpression = 198, - SpreadElement = 199, - ClassExpression = 200, - OmittedExpression = 201, - ExpressionWithTypeArguments = 202, - AsExpression = 203, - NonNullExpression = 204, - MetaProperty = 205, - TemplateSpan = 206, - SemicolonClassElement = 207, - Block = 208, - VariableStatement = 209, - EmptyStatement = 210, - ExpressionStatement = 211, - IfStatement = 212, - DoStatement = 213, - WhileStatement = 214, - ForStatement = 215, - ForInStatement = 216, - ForOfStatement = 217, - ContinueStatement = 218, - BreakStatement = 219, - ReturnStatement = 220, - WithStatement = 221, - SwitchStatement = 222, - LabeledStatement = 223, - ThrowStatement = 224, - TryStatement = 225, - DebuggerStatement = 226, - VariableDeclaration = 227, - VariableDeclarationList = 228, - FunctionDeclaration = 229, - ClassDeclaration = 230, - InterfaceDeclaration = 231, - TypeAliasDeclaration = 232, - EnumDeclaration = 233, - ModuleDeclaration = 234, - ModuleBlock = 235, - CaseBlock = 236, - NamespaceExportDeclaration = 237, - ImportEqualsDeclaration = 238, - ImportDeclaration = 239, - ImportClause = 240, - NamespaceImport = 241, - NamedImports = 242, - ImportSpecifier = 243, - ExportAssignment = 244, - ExportDeclaration = 245, - NamedExports = 246, - ExportSpecifier = 247, - MissingDeclaration = 248, - ExternalModuleReference = 249, - JsxElement = 250, - JsxSelfClosingElement = 251, - JsxOpeningElement = 252, - JsxClosingElement = 253, - JsxFragment = 254, - JsxOpeningFragment = 255, - JsxClosingFragment = 256, - JsxAttribute = 257, - JsxAttributes = 258, - JsxSpreadAttribute = 259, - JsxExpression = 260, - CaseClause = 261, - DefaultClause = 262, - HeritageClause = 263, - CatchClause = 264, - PropertyAssignment = 265, - ShorthandPropertyAssignment = 266, - SpreadAssignment = 267, - EnumMember = 268, - SourceFile = 269, - Bundle = 270, - JSDocTypeExpression = 271, - JSDocAllType = 272, - JSDocUnknownType = 273, - JSDocNullableType = 274, - JSDocNonNullableType = 275, - JSDocOptionalType = 276, - JSDocFunctionType = 277, - JSDocVariadicType = 278, - JSDocComment = 279, - JSDocTypeLiteral = 280, - JSDocTag = 281, - JSDocAugmentsTag = 282, - JSDocClassTag = 283, - JSDocParameterTag = 284, - JSDocReturnTag = 285, - JSDocTypeTag = 286, - JSDocTemplateTag = 287, - JSDocTypedefTag = 288, - JSDocPropertyTag = 289, - SyntaxList = 290, - NotEmittedStatement = 291, - PartiallyEmittedExpression = 292, - CommaListExpression = 293, - MergeDeclarationMarker = 294, - EndOfDeclarationMarker = 295, - Count = 296, + ConditionalType = 169, + ParenthesizedType = 170, + ThisType = 171, + TypeOperator = 172, + BinaryType = 173, + IndexedAccessType = 174, + MappedType = 175, + LiteralType = 176, + ObjectBindingPattern = 177, + ArrayBindingPattern = 178, + BindingElement = 179, + ArrayLiteralExpression = 180, + ObjectLiteralExpression = 181, + PropertyAccessExpression = 182, + ElementAccessExpression = 183, + CallExpression = 184, + NewExpression = 185, + TaggedTemplateExpression = 186, + TypeAssertionExpression = 187, + ParenthesizedExpression = 188, + FunctionExpression = 189, + ArrowFunction = 190, + DeleteExpression = 191, + TypeOfExpression = 192, + VoidExpression = 193, + AwaitExpression = 194, + PrefixUnaryExpression = 195, + PostfixUnaryExpression = 196, + BinaryExpression = 197, + ConditionalExpression = 198, + TemplateExpression = 199, + YieldExpression = 200, + SpreadElement = 201, + ClassExpression = 202, + OmittedExpression = 203, + ExpressionWithTypeArguments = 204, + AsExpression = 205, + NonNullExpression = 206, + MetaProperty = 207, + TemplateSpan = 208, + SemicolonClassElement = 209, + Block = 210, + VariableStatement = 211, + EmptyStatement = 212, + ExpressionStatement = 213, + IfStatement = 214, + DoStatement = 215, + WhileStatement = 216, + ForStatement = 217, + ForInStatement = 218, + ForOfStatement = 219, + ContinueStatement = 220, + BreakStatement = 221, + ReturnStatement = 222, + WithStatement = 223, + SwitchStatement = 224, + LabeledStatement = 225, + ThrowStatement = 226, + TryStatement = 227, + DebuggerStatement = 228, + VariableDeclaration = 229, + VariableDeclarationList = 230, + FunctionDeclaration = 231, + ClassDeclaration = 232, + InterfaceDeclaration = 233, + TypeAliasDeclaration = 234, + EnumDeclaration = 235, + ModuleDeclaration = 236, + ModuleBlock = 237, + CaseBlock = 238, + NamespaceExportDeclaration = 239, + ImportEqualsDeclaration = 240, + ImportDeclaration = 241, + ImportClause = 242, + NamespaceImport = 243, + NamedImports = 244, + ImportSpecifier = 245, + ExportAssignment = 246, + ExportDeclaration = 247, + NamedExports = 248, + ExportSpecifier = 249, + MissingDeclaration = 250, + ExternalModuleReference = 251, + JsxElement = 252, + JsxSelfClosingElement = 253, + JsxOpeningElement = 254, + JsxClosingElement = 255, + JsxFragment = 256, + JsxOpeningFragment = 257, + JsxClosingFragment = 258, + JsxAttribute = 259, + JsxAttributes = 260, + JsxSpreadAttribute = 261, + JsxExpression = 262, + CaseClause = 263, + DefaultClause = 264, + HeritageClause = 265, + CatchClause = 266, + PropertyAssignment = 267, + ShorthandPropertyAssignment = 268, + SpreadAssignment = 269, + EnumMember = 270, + SourceFile = 271, + Bundle = 272, + JSDocTypeExpression = 273, + JSDocAllType = 274, + JSDocUnknownType = 275, + JSDocNullableType = 276, + JSDocNonNullableType = 277, + JSDocOptionalType = 278, + JSDocFunctionType = 279, + JSDocVariadicType = 280, + JSDocComment = 281, + JSDocTypeLiteral = 282, + JSDocTag = 283, + JSDocAugmentsTag = 284, + JSDocClassTag = 285, + JSDocParameterTag = 286, + JSDocReturnTag = 287, + JSDocTypeTag = 288, + JSDocTemplateTag = 289, + JSDocTypedefTag = 290, + JSDocPropertyTag = 291, + SyntaxList = 292, + NotEmittedStatement = 293, + PartiallyEmittedExpression = 294, + CommaListExpression = 295, + MergeDeclarationMarker = 296, + EndOfDeclarationMarker = 297, + Count = 298, FirstAssignment = 58, LastAssignment = 70, FirstCompoundAssignment = 59, @@ -368,7 +370,7 @@ declare namespace ts { FirstFutureReservedWord = 108, LastFutureReservedWord = 116, FirstTypeNode = 159, - LastTypeNode = 174, + LastTypeNode = 176, FirstPunctuation = 17, LastPunctuation = 70, FirstToken = 0, @@ -382,10 +384,10 @@ declare namespace ts { FirstBinaryOperator = 27, LastBinaryOperator = 70, FirstNode = 144, - FirstJSDocNode = 271, - LastJSDocNode = 289, - FirstJSDocTagNode = 281, - LastJSDocTagNode = 289, + FirstJSDocNode = 273, + LastJSDocNode = 291, + FirstJSDocTagNode = 283, + LastJSDocTagNode = 291, } enum NodeFlags { None = 0, @@ -738,6 +740,12 @@ declare namespace ts { kind: SyntaxKind.IntersectionType; types: NodeArray; } + interface ConditionalTypeNode extends TypeNode { + kind: SyntaxKind.ConditionalType; + conditionType: TypeNode; + trueType: TypeNode; + falseType: TypeNode; + } interface ParenthesizedTypeNode extends TypeNode { kind: SyntaxKind.ParenthesizedType; type: TypeNode; @@ -747,6 +755,12 @@ declare namespace ts { operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword; type: TypeNode; } + interface BinaryTypeNode extends TypeNode { + kind: SyntaxKind.BinaryType; + left: TypeNode; + operator: SyntaxKind.ExtendsKeyword; + right: TypeNode; + } interface IndexedAccessTypeNode extends TypeNode { kind: SyntaxKind.IndexedAccessType; objectType: TypeNode; @@ -2017,23 +2031,28 @@ declare namespace ts { Intersection = 262144, Index = 524288, IndexedAccess = 1048576, - NonPrimitive = 33554432, - MarkerType = 134217728, + Conditional = 2097152, + Extends = 4194304, + NonPrimitive = 134217728, + MarkerType = 536870912, Literal = 224, Unit = 13536, StringOrNumberLiteral = 96, PossiblyFalsy = 14574, StringLike = 524322, NumberLike = 84, - BooleanLike = 136, + BooleanLike = 4194440, EnumLike = 272, ESSymbolLike = 1536, UnionOrIntersection = 393216, StructuredType = 458752, - StructuredOrTypeVariable = 2064384, TypeVariable = 1081344, - Narrowable = 35620607, - NotUnionOrUnit = 33620481, + InstantiableNonPrimitive = 3178496, + InstantiablePrimitive = 4718592, + Instantiable = 7897088, + StructuredOrInstantiable = 8355840, + Narrowable = 142575359, + NotUnionOrUnit = 134283777, } type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression; interface Type { @@ -2119,17 +2138,26 @@ declare namespace ts { elementType: Type; finalArrayType?: Type; } - interface TypeVariable extends Type { + interface InstantiableType extends Type { } - interface TypeParameter extends TypeVariable { + interface TypeParameter extends InstantiableType { } - interface IndexedAccessType extends TypeVariable { + interface IndexedAccessType extends InstantiableType { objectType: Type; indexType: Type; constraint?: Type; } - interface IndexType extends Type { - type: TypeVariable | UnionOrIntersectionType; + interface IndexType extends InstantiableType { + type: InstantiableType | UnionOrIntersectionType; + } + interface ConditionalType extends InstantiableType { + conditionType: Type; + trueType: Type; + falseType: Type; + } + interface ExtendsType extends InstantiableType { + checkType: Type; + extendsType: Type; } enum SignatureKind { Call = 0, @@ -2946,9 +2974,11 @@ declare namespace ts { function isTupleTypeNode(node: Node): node is TupleTypeNode; function isUnionTypeNode(node: Node): node is UnionTypeNode; function isIntersectionTypeNode(node: Node): node is IntersectionTypeNode; + function isConditionalTypeNode(node: Node): node is ConditionalTypeNode; function isParenthesizedTypeNode(node: Node): node is ParenthesizedTypeNode; function isThisTypeNode(node: Node): node is ThisTypeNode; function isTypeOperatorNode(node: Node): node is TypeOperatorNode; + function isBinaryTypeNode(node: Node): node is BinaryTypeNode; function isIndexedAccessTypeNode(node: Node): node is IndexedAccessTypeNode; function isMappedTypeNode(node: Node): node is MappedTypeNode; function isLiteralTypeNode(node: Node): node is LiteralTypeNode; @@ -3362,12 +3392,16 @@ declare namespace ts { function createIntersectionTypeNode(types: TypeNode[]): IntersectionTypeNode; function updateIntersectionTypeNode(node: IntersectionTypeNode, types: NodeArray): IntersectionTypeNode; function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: ReadonlyArray): UnionOrIntersectionTypeNode; + function createConditionalTypeNode(conditionType: TypeNode, trueType: TypeNode, falseType: TypeNode): ConditionalTypeNode; + function updateConditionalTypeNode(node: ConditionalTypeNode, conditionType: TypeNode, trueType: TypeNode, falseType: TypeNode): ConditionalTypeNode; function createParenthesizedType(type: TypeNode): ParenthesizedTypeNode; function updateParenthesizedType(node: ParenthesizedTypeNode, type: TypeNode): ParenthesizedTypeNode; function createThisTypeNode(): ThisTypeNode; function createTypeOperatorNode(type: TypeNode): TypeOperatorNode; function createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword, type: TypeNode): TypeOperatorNode; function updateTypeOperatorNode(node: TypeOperatorNode, type: TypeNode): TypeOperatorNode; + function createBinaryTypeNode(left: TypeNode, operator: SyntaxKind.ExtendsKeyword, right: TypeNode): BinaryTypeNode; + function updateBinaryTypeNode(node: BinaryTypeNode, left: TypeNode, operator: SyntaxKind.ExtendsKeyword, right: TypeNode): BinaryTypeNode; function createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode; function updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode; function createMappedTypeNode(readonlyToken: ReadonlyToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | undefined, type: TypeNode | undefined): MappedTypeNode; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 62a3880827c74..8aaf79ce338ee 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -229,134 +229,136 @@ declare namespace ts { TupleType = 166, UnionType = 167, IntersectionType = 168, - ParenthesizedType = 169, - ThisType = 170, - TypeOperator = 171, - IndexedAccessType = 172, - MappedType = 173, - LiteralType = 174, - ObjectBindingPattern = 175, - ArrayBindingPattern = 176, - BindingElement = 177, - ArrayLiteralExpression = 178, - ObjectLiteralExpression = 179, - PropertyAccessExpression = 180, - ElementAccessExpression = 181, - CallExpression = 182, - NewExpression = 183, - TaggedTemplateExpression = 184, - TypeAssertionExpression = 185, - ParenthesizedExpression = 186, - FunctionExpression = 187, - ArrowFunction = 188, - DeleteExpression = 189, - TypeOfExpression = 190, - VoidExpression = 191, - AwaitExpression = 192, - PrefixUnaryExpression = 193, - PostfixUnaryExpression = 194, - BinaryExpression = 195, - ConditionalExpression = 196, - TemplateExpression = 197, - YieldExpression = 198, - SpreadElement = 199, - ClassExpression = 200, - OmittedExpression = 201, - ExpressionWithTypeArguments = 202, - AsExpression = 203, - NonNullExpression = 204, - MetaProperty = 205, - TemplateSpan = 206, - SemicolonClassElement = 207, - Block = 208, - VariableStatement = 209, - EmptyStatement = 210, - ExpressionStatement = 211, - IfStatement = 212, - DoStatement = 213, - WhileStatement = 214, - ForStatement = 215, - ForInStatement = 216, - ForOfStatement = 217, - ContinueStatement = 218, - BreakStatement = 219, - ReturnStatement = 220, - WithStatement = 221, - SwitchStatement = 222, - LabeledStatement = 223, - ThrowStatement = 224, - TryStatement = 225, - DebuggerStatement = 226, - VariableDeclaration = 227, - VariableDeclarationList = 228, - FunctionDeclaration = 229, - ClassDeclaration = 230, - InterfaceDeclaration = 231, - TypeAliasDeclaration = 232, - EnumDeclaration = 233, - ModuleDeclaration = 234, - ModuleBlock = 235, - CaseBlock = 236, - NamespaceExportDeclaration = 237, - ImportEqualsDeclaration = 238, - ImportDeclaration = 239, - ImportClause = 240, - NamespaceImport = 241, - NamedImports = 242, - ImportSpecifier = 243, - ExportAssignment = 244, - ExportDeclaration = 245, - NamedExports = 246, - ExportSpecifier = 247, - MissingDeclaration = 248, - ExternalModuleReference = 249, - JsxElement = 250, - JsxSelfClosingElement = 251, - JsxOpeningElement = 252, - JsxClosingElement = 253, - JsxFragment = 254, - JsxOpeningFragment = 255, - JsxClosingFragment = 256, - JsxAttribute = 257, - JsxAttributes = 258, - JsxSpreadAttribute = 259, - JsxExpression = 260, - CaseClause = 261, - DefaultClause = 262, - HeritageClause = 263, - CatchClause = 264, - PropertyAssignment = 265, - ShorthandPropertyAssignment = 266, - SpreadAssignment = 267, - EnumMember = 268, - SourceFile = 269, - Bundle = 270, - JSDocTypeExpression = 271, - JSDocAllType = 272, - JSDocUnknownType = 273, - JSDocNullableType = 274, - JSDocNonNullableType = 275, - JSDocOptionalType = 276, - JSDocFunctionType = 277, - JSDocVariadicType = 278, - JSDocComment = 279, - JSDocTypeLiteral = 280, - JSDocTag = 281, - JSDocAugmentsTag = 282, - JSDocClassTag = 283, - JSDocParameterTag = 284, - JSDocReturnTag = 285, - JSDocTypeTag = 286, - JSDocTemplateTag = 287, - JSDocTypedefTag = 288, - JSDocPropertyTag = 289, - SyntaxList = 290, - NotEmittedStatement = 291, - PartiallyEmittedExpression = 292, - CommaListExpression = 293, - MergeDeclarationMarker = 294, - EndOfDeclarationMarker = 295, - Count = 296, + ConditionalType = 169, + ParenthesizedType = 170, + ThisType = 171, + TypeOperator = 172, + BinaryType = 173, + IndexedAccessType = 174, + MappedType = 175, + LiteralType = 176, + ObjectBindingPattern = 177, + ArrayBindingPattern = 178, + BindingElement = 179, + ArrayLiteralExpression = 180, + ObjectLiteralExpression = 181, + PropertyAccessExpression = 182, + ElementAccessExpression = 183, + CallExpression = 184, + NewExpression = 185, + TaggedTemplateExpression = 186, + TypeAssertionExpression = 187, + ParenthesizedExpression = 188, + FunctionExpression = 189, + ArrowFunction = 190, + DeleteExpression = 191, + TypeOfExpression = 192, + VoidExpression = 193, + AwaitExpression = 194, + PrefixUnaryExpression = 195, + PostfixUnaryExpression = 196, + BinaryExpression = 197, + ConditionalExpression = 198, + TemplateExpression = 199, + YieldExpression = 200, + SpreadElement = 201, + ClassExpression = 202, + OmittedExpression = 203, + ExpressionWithTypeArguments = 204, + AsExpression = 205, + NonNullExpression = 206, + MetaProperty = 207, + TemplateSpan = 208, + SemicolonClassElement = 209, + Block = 210, + VariableStatement = 211, + EmptyStatement = 212, + ExpressionStatement = 213, + IfStatement = 214, + DoStatement = 215, + WhileStatement = 216, + ForStatement = 217, + ForInStatement = 218, + ForOfStatement = 219, + ContinueStatement = 220, + BreakStatement = 221, + ReturnStatement = 222, + WithStatement = 223, + SwitchStatement = 224, + LabeledStatement = 225, + ThrowStatement = 226, + TryStatement = 227, + DebuggerStatement = 228, + VariableDeclaration = 229, + VariableDeclarationList = 230, + FunctionDeclaration = 231, + ClassDeclaration = 232, + InterfaceDeclaration = 233, + TypeAliasDeclaration = 234, + EnumDeclaration = 235, + ModuleDeclaration = 236, + ModuleBlock = 237, + CaseBlock = 238, + NamespaceExportDeclaration = 239, + ImportEqualsDeclaration = 240, + ImportDeclaration = 241, + ImportClause = 242, + NamespaceImport = 243, + NamedImports = 244, + ImportSpecifier = 245, + ExportAssignment = 246, + ExportDeclaration = 247, + NamedExports = 248, + ExportSpecifier = 249, + MissingDeclaration = 250, + ExternalModuleReference = 251, + JsxElement = 252, + JsxSelfClosingElement = 253, + JsxOpeningElement = 254, + JsxClosingElement = 255, + JsxFragment = 256, + JsxOpeningFragment = 257, + JsxClosingFragment = 258, + JsxAttribute = 259, + JsxAttributes = 260, + JsxSpreadAttribute = 261, + JsxExpression = 262, + CaseClause = 263, + DefaultClause = 264, + HeritageClause = 265, + CatchClause = 266, + PropertyAssignment = 267, + ShorthandPropertyAssignment = 268, + SpreadAssignment = 269, + EnumMember = 270, + SourceFile = 271, + Bundle = 272, + JSDocTypeExpression = 273, + JSDocAllType = 274, + JSDocUnknownType = 275, + JSDocNullableType = 276, + JSDocNonNullableType = 277, + JSDocOptionalType = 278, + JSDocFunctionType = 279, + JSDocVariadicType = 280, + JSDocComment = 281, + JSDocTypeLiteral = 282, + JSDocTag = 283, + JSDocAugmentsTag = 284, + JSDocClassTag = 285, + JSDocParameterTag = 286, + JSDocReturnTag = 287, + JSDocTypeTag = 288, + JSDocTemplateTag = 289, + JSDocTypedefTag = 290, + JSDocPropertyTag = 291, + SyntaxList = 292, + NotEmittedStatement = 293, + PartiallyEmittedExpression = 294, + CommaListExpression = 295, + MergeDeclarationMarker = 296, + EndOfDeclarationMarker = 297, + Count = 298, FirstAssignment = 58, LastAssignment = 70, FirstCompoundAssignment = 59, @@ -368,7 +370,7 @@ declare namespace ts { FirstFutureReservedWord = 108, LastFutureReservedWord = 116, FirstTypeNode = 159, - LastTypeNode = 174, + LastTypeNode = 176, FirstPunctuation = 17, LastPunctuation = 70, FirstToken = 0, @@ -382,10 +384,10 @@ declare namespace ts { FirstBinaryOperator = 27, LastBinaryOperator = 70, FirstNode = 144, - FirstJSDocNode = 271, - LastJSDocNode = 289, - FirstJSDocTagNode = 281, - LastJSDocTagNode = 289, + FirstJSDocNode = 273, + LastJSDocNode = 291, + FirstJSDocTagNode = 283, + LastJSDocTagNode = 291, } enum NodeFlags { None = 0, @@ -738,6 +740,12 @@ declare namespace ts { kind: SyntaxKind.IntersectionType; types: NodeArray; } + interface ConditionalTypeNode extends TypeNode { + kind: SyntaxKind.ConditionalType; + conditionType: TypeNode; + trueType: TypeNode; + falseType: TypeNode; + } interface ParenthesizedTypeNode extends TypeNode { kind: SyntaxKind.ParenthesizedType; type: TypeNode; @@ -747,6 +755,12 @@ declare namespace ts { operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword; type: TypeNode; } + interface BinaryTypeNode extends TypeNode { + kind: SyntaxKind.BinaryType; + left: TypeNode; + operator: SyntaxKind.ExtendsKeyword; + right: TypeNode; + } interface IndexedAccessTypeNode extends TypeNode { kind: SyntaxKind.IndexedAccessType; objectType: TypeNode; @@ -2017,23 +2031,28 @@ declare namespace ts { Intersection = 262144, Index = 524288, IndexedAccess = 1048576, - NonPrimitive = 33554432, - MarkerType = 134217728, + Conditional = 2097152, + Extends = 4194304, + NonPrimitive = 134217728, + MarkerType = 536870912, Literal = 224, Unit = 13536, StringOrNumberLiteral = 96, PossiblyFalsy = 14574, StringLike = 524322, NumberLike = 84, - BooleanLike = 136, + BooleanLike = 4194440, EnumLike = 272, ESSymbolLike = 1536, UnionOrIntersection = 393216, StructuredType = 458752, - StructuredOrTypeVariable = 2064384, TypeVariable = 1081344, - Narrowable = 35620607, - NotUnionOrUnit = 33620481, + InstantiableNonPrimitive = 3178496, + InstantiablePrimitive = 4718592, + Instantiable = 7897088, + StructuredOrInstantiable = 8355840, + Narrowable = 142575359, + NotUnionOrUnit = 134283777, } type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression; interface Type { @@ -2119,17 +2138,26 @@ declare namespace ts { elementType: Type; finalArrayType?: Type; } - interface TypeVariable extends Type { + interface InstantiableType extends Type { } - interface TypeParameter extends TypeVariable { + interface TypeParameter extends InstantiableType { } - interface IndexedAccessType extends TypeVariable { + interface IndexedAccessType extends InstantiableType { objectType: Type; indexType: Type; constraint?: Type; } - interface IndexType extends Type { - type: TypeVariable | UnionOrIntersectionType; + interface IndexType extends InstantiableType { + type: InstantiableType | UnionOrIntersectionType; + } + interface ConditionalType extends InstantiableType { + conditionType: Type; + trueType: Type; + falseType: Type; + } + interface ExtendsType extends InstantiableType { + checkType: Type; + extendsType: Type; } enum SignatureKind { Call = 0, @@ -2999,9 +3027,11 @@ declare namespace ts { function isTupleTypeNode(node: Node): node is TupleTypeNode; function isUnionTypeNode(node: Node): node is UnionTypeNode; function isIntersectionTypeNode(node: Node): node is IntersectionTypeNode; + function isConditionalTypeNode(node: Node): node is ConditionalTypeNode; function isParenthesizedTypeNode(node: Node): node is ParenthesizedTypeNode; function isThisTypeNode(node: Node): node is ThisTypeNode; function isTypeOperatorNode(node: Node): node is TypeOperatorNode; + function isBinaryTypeNode(node: Node): node is BinaryTypeNode; function isIndexedAccessTypeNode(node: Node): node is IndexedAccessTypeNode; function isMappedTypeNode(node: Node): node is MappedTypeNode; function isLiteralTypeNode(node: Node): node is LiteralTypeNode; @@ -3309,12 +3339,16 @@ declare namespace ts { function createIntersectionTypeNode(types: TypeNode[]): IntersectionTypeNode; function updateIntersectionTypeNode(node: IntersectionTypeNode, types: NodeArray): IntersectionTypeNode; function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: ReadonlyArray): UnionOrIntersectionTypeNode; + function createConditionalTypeNode(conditionType: TypeNode, trueType: TypeNode, falseType: TypeNode): ConditionalTypeNode; + function updateConditionalTypeNode(node: ConditionalTypeNode, conditionType: TypeNode, trueType: TypeNode, falseType: TypeNode): ConditionalTypeNode; function createParenthesizedType(type: TypeNode): ParenthesizedTypeNode; function updateParenthesizedType(node: ParenthesizedTypeNode, type: TypeNode): ParenthesizedTypeNode; function createThisTypeNode(): ThisTypeNode; function createTypeOperatorNode(type: TypeNode): TypeOperatorNode; function createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword, type: TypeNode): TypeOperatorNode; function updateTypeOperatorNode(node: TypeOperatorNode, type: TypeNode): TypeOperatorNode; + function createBinaryTypeNode(left: TypeNode, operator: SyntaxKind.ExtendsKeyword, right: TypeNode): BinaryTypeNode; + function updateBinaryTypeNode(node: BinaryTypeNode, left: TypeNode, operator: SyntaxKind.ExtendsKeyword, right: TypeNode): BinaryTypeNode; function createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode; function updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode; function createMappedTypeNode(readonlyToken: ReadonlyToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | undefined, type: TypeNode | undefined): MappedTypeNode; diff --git a/tests/baselines/reference/jsdocDisallowedInTypescript.errors.txt b/tests/baselines/reference/jsdocDisallowedInTypescript.errors.txt index 2823981cc95b0..01b819f13af3f 100644 --- a/tests/baselines/reference/jsdocDisallowedInTypescript.errors.txt +++ b/tests/baselines/reference/jsdocDisallowedInTypescript.errors.txt @@ -1,94 +1,52 @@ -tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(2,15): error TS8020: JSDoc types can only be used inside documentation comments. -tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(4,15): error TS8020: JSDoc types can only be used inside documentation comments. -tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(4,32): error TS8020: JSDoc types can only be used inside documentation comments. -tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(7,20): error TS8020: JSDoc types can only be used inside documentation comments. -tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(10,18): error TS8020: JSDoc types can only be used inside documentation comments. tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(11,12): error TS2554: Expected 1 arguments, but got 2. -tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(13,14): error TS8020: JSDoc types can only be used inside documentation comments. -tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(14,11): error TS8020: JSDoc types can only be used inside documentation comments. -tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(15,8): error TS8020: JSDoc types can only be used inside documentation comments. tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(16,5): error TS2322: Type 'boolean[]' is not assignable to type 'boolean | undefined'. Type 'boolean[]' is not assignable to type 'false'. -tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(16,15): error TS8020: JSDoc types can only be used inside documentation comments. tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(16,15): error TS8028: JSDoc '...' may only appear in the last parameter of a signature. -tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(17,11): error TS8020: JSDoc types can only be used inside documentation comments. -tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(18,17): error TS8020: JSDoc types can only be used inside documentation comments. -tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(19,5): error TS2322: Type 'undefined' is not assignable to type 'number | null'. -tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(19,17): error TS8020: JSDoc types can only be used inside documentation comments. -tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(21,16): error TS8020: JSDoc types can only be used inside documentation comments. -tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(22,16): error TS8020: JSDoc types can only be used inside documentation comments. -tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(23,17): error TS8020: JSDoc types can only be used inside documentation comments. -tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(24,17): error TS8020: JSDoc types can only be used inside documentation comments. +tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(19,5): error TS2322: Type 'undefined' is not assignable to type 'never'. +tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(19,17): error TS2322: Type 'number' is not assignable to type 'boolean'. +tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(19,25): error TS1110: Type expected. tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(24,17): error TS8028: JSDoc '...' may only appear in the last parameter of a signature. -==== tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts (21 errors) ==== +==== tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts (7 errors) ==== // grammar error from checker var ara: Array. = [1,2,3]; - ~ -!!! error TS8020: JSDoc types can only be used inside documentation comments. function f(x: ?number, y: Array.) { - ~~~~~~~ -!!! error TS8020: JSDoc types can only be used inside documentation comments. - ~ -!!! error TS8020: JSDoc types can only be used inside documentation comments. return x ? x + y[1] : y[0]; } function hof(ctor: function(new: number, string)) { - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS8020: JSDoc types can only be used inside documentation comments. return new ctor('hi'); } function hof2(f: function(this: number, string): string) { - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS8020: JSDoc types can only be used inside documentation comments. return f(12, 'hullo'); ~~~~~~~~~~~~~~ !!! error TS2554: Expected 1 arguments, but got 2. } var whatevs: * = 1001; - ~ -!!! error TS8020: JSDoc types can only be used inside documentation comments. var ques: ? = 'what'; - ~ -!!! error TS8020: JSDoc types can only be used inside documentation comments. var g: function(number, number): number = (n,m) => n + m; - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS8020: JSDoc types can only be used inside documentation comments. var variadic: ...boolean = [true, false, true]; ~~~~~~~~ !!! error TS2322: Type 'boolean[]' is not assignable to type 'boolean | undefined'. !!! error TS2322: Type 'boolean[]' is not assignable to type 'false'. ~~~~~~~~~~ -!!! error TS8020: JSDoc types can only be used inside documentation comments. - ~~~~~~~~~~ !!! error TS8028: JSDoc '...' may only appear in the last parameter of a signature. var most: !string = 'definite'; - ~~~~~~~ -!!! error TS8020: JSDoc types can only be used inside documentation comments. var postfixdef: number! = 101; - ~~~~~~~ -!!! error TS8020: JSDoc types can only be used inside documentation comments. var postfixopt: number? = undefined; ~~~~~~~~~~ -!!! error TS2322: Type 'undefined' is not assignable to type 'number | null'. - ~~~~~~~ -!!! error TS8020: JSDoc types can only be used inside documentation comments. +!!! error TS2322: Type 'undefined' is not assignable to type 'never'. + ~~~~~~ +!!! error TS2322: Type 'number' is not assignable to type 'boolean'. + ~ +!!! error TS1110: Type expected. var nns: Array; - ~~~~~~~ -!!! error TS8020: JSDoc types can only be used inside documentation comments. var dns: Array; - ~~~~~~~ -!!! error TS8020: JSDoc types can only be used inside documentation comments. var anys: Array<*>; - ~ -!!! error TS8020: JSDoc types can only be used inside documentation comments. var vars: Array<...number>; ~~~~~~~~~ -!!! error TS8020: JSDoc types can only be used inside documentation comments. - ~~~~~~~~~ !!! error TS8028: JSDoc '...' may only appear in the last parameter of a signature. \ No newline at end of file diff --git a/tests/baselines/reference/jsdocDisallowedInTypescript.types b/tests/baselines/reference/jsdocDisallowedInTypescript.types index 8fe4a032f206b..1028d9300bd54 100644 --- a/tests/baselines/reference/jsdocDisallowedInTypescript.types +++ b/tests/baselines/reference/jsdocDisallowedInTypescript.types @@ -80,7 +80,9 @@ var postfixdef: number! = 101; >101 : 101 var postfixopt: number? = undefined; ->postfixopt : number | null +>postfixopt : never +> : No type information available! +> : No type information available! >undefined : undefined var nns: Array; diff --git a/tests/baselines/reference/recursiveTypeRelations.types b/tests/baselines/reference/recursiveTypeRelations.types index 110ff8175c4d2..636e4db0c87de 100644 --- a/tests/baselines/reference/recursiveTypeRelations.types +++ b/tests/baselines/reference/recursiveTypeRelations.types @@ -97,7 +97,7 @@ export function css(styles: S, ...classNam if (typeof arg == "object") { >typeof arg == "object" : boolean >typeof arg : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function" ->arg : keyof S | (object & { [K in keyof S]?: boolean; }) +>arg : object & { [K in keyof S]?: boolean; } >"object" : "object" return Object.keys(arg).reduce((obj: ClassNameObject, key: keyof S) => { @@ -107,7 +107,7 @@ export function css(styles: S, ...classNam >Object.keys : (o: {}) => string[] >Object : ObjectConstructor >keys : (o: {}) => string[] ->arg : keyof S | (object & { [K in keyof S]?: boolean; }) +>arg : object & { [K in keyof S]?: boolean; } >reduce : { (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string): string; (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string, initialValue: string): string; (callbackfn: (previousValue: U, currentValue: string, currentIndex: number, array: string[]) => U, initialValue: U): U; } >ClassNameObject : No type information available! >(obj: ClassNameObject, key: keyof S) => { const exportedClassName = styles[key]; obj[exportedClassName] = (arg as ClassNameMap)[key]; return obj; } : (obj: any, key: keyof S) => any @@ -130,7 +130,7 @@ export function css(styles: S, ...classNam >(arg as ClassNameMap)[key] : { [K in keyof S]?: boolean; }[keyof S] >(arg as ClassNameMap) : { [K in keyof S]?: boolean; } >arg as ClassNameMap : { [K in keyof S]?: boolean; } ->arg : keyof S | (object & { [K in keyof S]?: boolean; }) +>arg : object & { [K in keyof S]?: boolean; } >ClassNameMap : { [K in keyof S]?: boolean; } >S : S >key : keyof S From 14590f1884c43966c62eb2016845631e7149df5b Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 17 Dec 2017 20:27:04 -0800 Subject: [PATCH 12/39] Move JsxAttributes and MarkerType from TypeFlags to ObjectFlags --- src/compiler/checker.ts | 12 ++++++------ src/compiler/types.ts | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 47cc3bbab1fd3..6f52fcbdbf1ec 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9656,7 +9656,7 @@ namespace ts { function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean { if (maybeTypeOfKind(target, TypeFlags.Object) && !(getObjectFlags(target) & ObjectFlags.ObjectLiteralPatternWithComputedProperties)) { - const isComparingJsxAttributes = !!(source.flags & TypeFlags.JsxAttributes); + const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes); if ((relation === assignableRelation || relation === comparableRelation) && (isTypeSubsetOf(globalObjectType, target) || (!isComparingJsxAttributes && isEmptyObjectType(target)))) { return false; @@ -10031,7 +10031,7 @@ namespace ts { } else { if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target && - !(source.flags & TypeFlags.MarkerType || target.flags & TypeFlags.MarkerType)) { + !(getObjectFlags(source) & ObjectFlags.MarkerType || getObjectFlags(target) & ObjectFlags.MarkerType)) { // We have type references to the same generic type, and the type references are not marker // type references (which are intended by be compared structurally). Obtain the variance // information for the type parameters and relate the type arguments accordingly. @@ -10245,7 +10245,7 @@ namespace ts { } function hasCommonProperties(source: Type, target: Type) { - const isComparingJsxAttributes = !!(source.flags & TypeFlags.JsxAttributes); + const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes); for (const prop of getPropertiesOfType(source)) { if (isKnownProperty(target, prop.escapedName, isComparingJsxAttributes)) { return true; @@ -10489,7 +10489,7 @@ namespace ts { // type, and flag the result as a marker type reference. function getMarkerTypeReference(type: GenericType, source: TypeParameter, target: Type) { const result = createTypeReference(type, map(type.typeParameters, t => t === source ? target : t)); - result.flags |= TypeFlags.MarkerType; + result.objectFlags |= ObjectFlags.MarkerType; return result; } @@ -14983,8 +14983,8 @@ namespace ts { */ function createJsxAttributesType(symbol: Symbol, attributesTable: UnderscoreEscapedMap) { const result = createAnonymousType(symbol, attributesTable, emptyArray, emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined); - result.flags |= TypeFlags.JsxAttributes | TypeFlags.ContainsObjectLiteral; - result.objectFlags |= ObjectFlags.ObjectLiteral; + result.flags |= TypeFlags.ContainsObjectLiteral; + result.objectFlags |= ObjectFlags.ObjectLiteral | ObjectFlags.JsxAttributes; return result; } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 2ba528b59f80e..ee64bfe6e5f2f 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3367,8 +3367,7 @@ namespace ts { ContainsAnyFunctionType = 1 << 26, // Type is or contains the anyFunctionType NonPrimitive = 1 << 27, // intrinsic object type /* @internal */ - JsxAttributes = 1 << 28, // Jsx attributes type - MarkerType = 1 << 29, // Marker type used for variance probing + GenericMappedType = 1 << 29, // Flag used by maybeTypeOfKind /* @internal */ Nullable = Undefined | Null, @@ -3406,7 +3405,6 @@ namespace ts { /* @internal */ PropagatingFlags = ContainsWideningType | ContainsObjectLiteral | ContainsAnyFunctionType, /* @internal */ - GenericMappedType = MarkerType, // Flag used by maybeTypeOfKind } export type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression; @@ -3465,6 +3463,8 @@ namespace ts { EvolvingArray = 1 << 8, // Evolving array type ObjectLiteralPatternWithComputedProperties = 1 << 9, // Object literal pattern with computed properties ContainsSpread = 1 << 10, // Object literal contains spread operation + JsxAttributes = 1 << 11, // Jsx attributes type + MarkerType = 1 << 12, // Marker type used for variance probing ClassOrInterface = Class | Interface } From 100e4f6f3b5e4a06081753d01aaedd303e145a34 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 17 Dec 2017 20:27:26 -0800 Subject: [PATCH 13/39] Accept new baselines --- tests/baselines/reference/api/tsserverlibrary.d.ts | 3 ++- tests/baselines/reference/api/typescript.d.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index eb6557439fe48..eaa73be7287e7 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2034,7 +2034,6 @@ declare namespace ts { Conditional = 2097152, Extends = 4194304, NonPrimitive = 134217728, - MarkerType = 536870912, Literal = 224, Unit = 13536, StringOrNumberLiteral = 96, @@ -2090,6 +2089,8 @@ declare namespace ts { EvolvingArray = 256, ObjectLiteralPatternWithComputedProperties = 512, ContainsSpread = 1024, + JsxAttributes = 2048, + MarkerType = 4096, ClassOrInterface = 3, } interface ObjectType extends Type { diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 8aaf79ce338ee..6041008ce340a 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2034,7 +2034,6 @@ declare namespace ts { Conditional = 2097152, Extends = 4194304, NonPrimitive = 134217728, - MarkerType = 536870912, Literal = 224, Unit = 13536, StringOrNumberLiteral = 96, @@ -2090,6 +2089,8 @@ declare namespace ts { EvolvingArray = 256, ObjectLiteralPatternWithComputedProperties = 512, ContainsSpread = 1024, + JsxAttributes = 2048, + MarkerType = 4096, ClassOrInterface = 3, } interface ObjectType extends Type { From c5fd2f14f38d669f604f8cb40af8f3e0d747c600 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 18 Dec 2017 18:30:34 -0800 Subject: [PATCH 14/39] Parse xxx? as JSDoc type when not followed by token that starts type --- src/compiler/parser.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index debb4be67ba73..9c4aba68a3704 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1477,6 +1477,11 @@ namespace ts { return isStartOfExpression(); } + function nextTokenIsStartOfType() { + nextToken(); + return isStartOfType(); + } + // True if positioned at a list terminator function isListTerminator(kind: ParsingContext): boolean { if (token() === SyntaxKind.EndOfFileToken) { @@ -2767,8 +2772,8 @@ namespace ts { type = createJSDocPostfixType(SyntaxKind.JSDocNonNullableType, type); break; case SyntaxKind.QuestionToken: - // only parse postfix ? inside jsdoc, otherwise it is a conditional type - if (!(contextFlags & NodeFlags.JSDoc)) { + // If not in JSDoc and next token is start of a type we have a conditional type + if (!(contextFlags & NodeFlags.JSDoc) && lookAhead(nextTokenIsStartOfType)) { return type; } type = createJSDocPostfixType(SyntaxKind.JSDocNullableType, type); From 341c3973a33bbf6c6dadc5aa4ae77a6c53813834 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 18 Dec 2017 18:30:50 -0800 Subject: [PATCH 15/39] Accept new baselines --- .../jsdocDisallowedInTypescript.errors.txt | 60 ++++++++++++++++--- .../jsdocDisallowedInTypescript.types | 4 +- 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/tests/baselines/reference/jsdocDisallowedInTypescript.errors.txt b/tests/baselines/reference/jsdocDisallowedInTypescript.errors.txt index 01b819f13af3f..2823981cc95b0 100644 --- a/tests/baselines/reference/jsdocDisallowedInTypescript.errors.txt +++ b/tests/baselines/reference/jsdocDisallowedInTypescript.errors.txt @@ -1,52 +1,94 @@ +tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(2,15): error TS8020: JSDoc types can only be used inside documentation comments. +tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(4,15): error TS8020: JSDoc types can only be used inside documentation comments. +tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(4,32): error TS8020: JSDoc types can only be used inside documentation comments. +tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(7,20): error TS8020: JSDoc types can only be used inside documentation comments. +tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(10,18): error TS8020: JSDoc types can only be used inside documentation comments. tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(11,12): error TS2554: Expected 1 arguments, but got 2. +tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(13,14): error TS8020: JSDoc types can only be used inside documentation comments. +tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(14,11): error TS8020: JSDoc types can only be used inside documentation comments. +tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(15,8): error TS8020: JSDoc types can only be used inside documentation comments. tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(16,5): error TS2322: Type 'boolean[]' is not assignable to type 'boolean | undefined'. Type 'boolean[]' is not assignable to type 'false'. +tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(16,15): error TS8020: JSDoc types can only be used inside documentation comments. tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(16,15): error TS8028: JSDoc '...' may only appear in the last parameter of a signature. -tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(19,5): error TS2322: Type 'undefined' is not assignable to type 'never'. -tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(19,17): error TS2322: Type 'number' is not assignable to type 'boolean'. -tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(19,25): error TS1110: Type expected. +tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(17,11): error TS8020: JSDoc types can only be used inside documentation comments. +tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(18,17): error TS8020: JSDoc types can only be used inside documentation comments. +tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(19,5): error TS2322: Type 'undefined' is not assignable to type 'number | null'. +tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(19,17): error TS8020: JSDoc types can only be used inside documentation comments. +tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(21,16): error TS8020: JSDoc types can only be used inside documentation comments. +tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(22,16): error TS8020: JSDoc types can only be used inside documentation comments. +tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(23,17): error TS8020: JSDoc types can only be used inside documentation comments. +tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(24,17): error TS8020: JSDoc types can only be used inside documentation comments. tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts(24,17): error TS8028: JSDoc '...' may only appear in the last parameter of a signature. -==== tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts (7 errors) ==== +==== tests/cases/conformance/jsdoc/jsdocDisallowedInTypescript.ts (21 errors) ==== // grammar error from checker var ara: Array. = [1,2,3]; + ~ +!!! error TS8020: JSDoc types can only be used inside documentation comments. function f(x: ?number, y: Array.) { + ~~~~~~~ +!!! error TS8020: JSDoc types can only be used inside documentation comments. + ~ +!!! error TS8020: JSDoc types can only be used inside documentation comments. return x ? x + y[1] : y[0]; } function hof(ctor: function(new: number, string)) { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS8020: JSDoc types can only be used inside documentation comments. return new ctor('hi'); } function hof2(f: function(this: number, string): string) { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS8020: JSDoc types can only be used inside documentation comments. return f(12, 'hullo'); ~~~~~~~~~~~~~~ !!! error TS2554: Expected 1 arguments, but got 2. } var whatevs: * = 1001; + ~ +!!! error TS8020: JSDoc types can only be used inside documentation comments. var ques: ? = 'what'; + ~ +!!! error TS8020: JSDoc types can only be used inside documentation comments. var g: function(number, number): number = (n,m) => n + m; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS8020: JSDoc types can only be used inside documentation comments. var variadic: ...boolean = [true, false, true]; ~~~~~~~~ !!! error TS2322: Type 'boolean[]' is not assignable to type 'boolean | undefined'. !!! error TS2322: Type 'boolean[]' is not assignable to type 'false'. ~~~~~~~~~~ +!!! error TS8020: JSDoc types can only be used inside documentation comments. + ~~~~~~~~~~ !!! error TS8028: JSDoc '...' may only appear in the last parameter of a signature. var most: !string = 'definite'; + ~~~~~~~ +!!! error TS8020: JSDoc types can only be used inside documentation comments. var postfixdef: number! = 101; + ~~~~~~~ +!!! error TS8020: JSDoc types can only be used inside documentation comments. var postfixopt: number? = undefined; ~~~~~~~~~~ -!!! error TS2322: Type 'undefined' is not assignable to type 'never'. - ~~~~~~ -!!! error TS2322: Type 'number' is not assignable to type 'boolean'. - ~ -!!! error TS1110: Type expected. +!!! error TS2322: Type 'undefined' is not assignable to type 'number | null'. + ~~~~~~~ +!!! error TS8020: JSDoc types can only be used inside documentation comments. var nns: Array; + ~~~~~~~ +!!! error TS8020: JSDoc types can only be used inside documentation comments. var dns: Array; + ~~~~~~~ +!!! error TS8020: JSDoc types can only be used inside documentation comments. var anys: Array<*>; + ~ +!!! error TS8020: JSDoc types can only be used inside documentation comments. var vars: Array<...number>; ~~~~~~~~~ +!!! error TS8020: JSDoc types can only be used inside documentation comments. + ~~~~~~~~~ !!! error TS8028: JSDoc '...' may only appear in the last parameter of a signature. \ No newline at end of file diff --git a/tests/baselines/reference/jsdocDisallowedInTypescript.types b/tests/baselines/reference/jsdocDisallowedInTypescript.types index 1028d9300bd54..8fe4a032f206b 100644 --- a/tests/baselines/reference/jsdocDisallowedInTypescript.types +++ b/tests/baselines/reference/jsdocDisallowedInTypescript.types @@ -80,9 +80,7 @@ var postfixdef: number! = 101; >101 : 101 var postfixopt: number? = undefined; ->postfixopt : never -> : No type information available! -> : No type information available! +>postfixopt : number | null >undefined : undefined var nns: Array; From 3f4911f44adad5ca4410c2da90a4b8f51a285073 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 19 Dec 2017 17:36:35 -0800 Subject: [PATCH 16/39] Fix linting error --- src/compiler/visitor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index be87c8261f62e..81ae691703707 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -404,7 +404,7 @@ namespace ts { visitNode((node).left, visitor, isTypeNode), (node).operator, visitNode((node).right, visitor, isTypeNode)); - + case SyntaxKind.IndexedAccessType: return updateIndexedAccessTypeNode((node), visitNode((node).objectType, visitor, isTypeNode), From bb23bb2a9248afb8eb357fffe312e8f9313f6649 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 3 Jan 2018 11:29:21 -0800 Subject: [PATCH 17/39] Propagate both TypeFlags and ObjectFlags in getSpreadType --- src/compiler/checker.ts | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 84c5020b12418..d8ca648fdf31d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8442,7 +8442,7 @@ namespace ts { 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); + return getUnionType(map((checkType).types, t => getExtendsType(t, extendsType))); } if (checkType.flags & TypeFlags.Any) { return booleanType; @@ -8501,7 +8501,7 @@ namespace ts { * this function should be called in a left folding style, with left = previous result of getSpreadType * and right = the new element to be spread. */ - function getSpreadType(left: Type, right: Type, symbol: Symbol, propagatedFlags: TypeFlags): Type { + function getSpreadType(left: Type, right: Type, symbol: Symbol, typeFlags: TypeFlags, objectFlags: ObjectFlags): Type { if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; } @@ -8512,10 +8512,10 @@ namespace ts { return left; } if (left.flags & TypeFlags.Union) { - return mapType(left, t => getSpreadType(t, right, symbol, propagatedFlags)); + return mapType(left, t => getSpreadType(t, right, symbol, typeFlags, objectFlags)); } if (right.flags & TypeFlags.Union) { - return mapType(right, t => getSpreadType(left, t, symbol, propagatedFlags)); + return mapType(right, t => getSpreadType(left, t, symbol, typeFlags, objectFlags)); } if (right.flags & (TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive)) { return left; @@ -8578,8 +8578,8 @@ namespace ts { emptyArray, getNonReadonlyIndexSignature(stringIndexInfo), getNonReadonlyIndexSignature(numberIndexInfo)); - spread.flags |= propagatedFlags | TypeFlags.ContainsObjectLiteral; - (spread as ObjectType).objectFlags |= (ObjectFlags.ObjectLiteral | ObjectFlags.ContainsSpread); + spread.flags |= typeFlags | TypeFlags.ContainsObjectLiteral; + (spread as ObjectType).objectFlags |= objectFlags | (ObjectFlags.ObjectLiteral | ObjectFlags.ContainsSpread); return spread; } @@ -9552,7 +9552,7 @@ namespace ts { } function isIgnoredJsxProperty(source: Type, sourceProp: Symbol, targetMemberType: Type | undefined) { - return source.flags & TypeFlags.JsxAttributes && !(isUnhyphenatedJsxName(sourceProp.escapedName) || targetMemberType); + return getObjectFlags(source) & ObjectFlags.JsxAttributes && !(isUnhyphenatedJsxName(sourceProp.escapedName) || targetMemberType); } /** @@ -14905,7 +14905,7 @@ namespace ts { checkExternalEmitHelpers(memberDecl, ExternalEmitHelpers.Assign); } if (propertiesArray.length > 0) { - spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, propagatedFlags); + spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, propagatedFlags, 0); propertiesArray = []; propertiesTable = createSymbolTable(); hasComputedStringProperty = false; @@ -14917,7 +14917,7 @@ namespace ts { error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); return unknownType; } - spread = getSpreadType(spread, type, node.symbol, propagatedFlags); + spread = getSpreadType(spread, type, node.symbol, propagatedFlags, 0); offset = i + 1; continue; } @@ -14962,7 +14962,7 @@ namespace ts { if (spread !== emptyObjectType) { if (propertiesArray.length > 0) { - spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, propagatedFlags); + spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, propagatedFlags, 0); } return spread; } @@ -15095,7 +15095,7 @@ namespace ts { else { Debug.assert(attributeDecl.kind === SyntaxKind.JsxSpreadAttribute); if (attributesTable.size > 0) { - spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, TypeFlags.JsxAttributes); + spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, 0, ObjectFlags.JsxAttributes); attributesTable = createSymbolTable(); } const exprType = checkExpressionCached(attributeDecl.expression, checkMode); @@ -15103,7 +15103,7 @@ namespace ts { hasSpreadAnyType = true; } if (isValidSpreadType(exprType)) { - spread = getSpreadType(spread, exprType, openingLikeElement.symbol, TypeFlags.JsxAttributes); + spread = getSpreadType(spread, exprType, openingLikeElement.symbol, 0, ObjectFlags.JsxAttributes); } else { typeToIntersect = typeToIntersect ? getIntersectionType([typeToIntersect, exprType]) : exprType; @@ -15113,7 +15113,7 @@ namespace ts { if (!hasSpreadAnyType) { if (attributesTable.size > 0) { - spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, TypeFlags.JsxAttributes); + spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, 0, ObjectFlags.JsxAttributes); } } @@ -15138,7 +15138,8 @@ namespace ts { createArrayType(getUnionType(childrenTypes)); const childPropMap = createSymbolTable(); childPropMap.set(jsxChildrenPropertyName, childrenPropSymbol); - spread = getSpreadType(spread, createAnonymousType(attributes.symbol, childPropMap, emptyArray, emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined), attributes.symbol, TypeFlags.JsxAttributes); + spread = getSpreadType(spread, createAnonymousType(attributes.symbol, childPropMap, emptyArray, emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined), + attributes.symbol, 0, ObjectFlags.JsxAttributes); } } From c10a5520e2bd47efdc01ad8ca0fcedcf8a49aaa3 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 14 Jan 2018 14:38:48 -0800 Subject: [PATCH 18/39] Eagerly evaluate S extends T when S is definitely or definitely not assignable to T --- src/compiler/checker.ts | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d8ca648fdf31d..328f37100290c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8428,10 +8428,6 @@ namespace ts { return links.resolvedType; } - function isGenericExtendsType(type: Type) { - return maybeTypeOfKind(type, TypeFlags.Instantiable | TypeFlags.GenericMappedType); - } - function createExtendsType(checkType: Type, extendsType: Type) { const type = createType(TypeFlags.Extends); type.checkType = checkType; @@ -8447,9 +8443,16 @@ namespace ts { if (checkType.flags & TypeFlags.Any) { return booleanType; } - if (!isGenericExtendsType(checkType) && !isGenericExtendsType(extendsType)) { - return isTypeAssignableTo(checkType, extendsType) ? trueType : falseType; + // Return trueType if type is definitely assignable + if (isTypeAssignableTo(checkType, extendsType)) { + return trueType; + } + // Return falseType is type is definitely not assignable + if (!isTypeAssignableTo(instantiateType(checkType, anyMapper), instantiateType(extendsType, constraintMapper))) { + // Type is definitely not assignable + return falseType; } + // Type is possibly assignable, defer the check const id = checkType.id + "," + extendsType.id; let type = extendsTypes.get(id); if (!type) { @@ -8844,6 +8847,14 @@ namespace ts { return t => t === source ? target : baseMapper(t); } + function anyMapper(type: Type) { + return type.flags & TypeFlags.TypeParameter ? anyType : type; + } + + function constraintMapper(type: Type) { + return type.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(type) || anyType : type; + } + function cloneTypeParameter(typeParameter: TypeParameter): TypeParameter { const result = createType(TypeFlags.TypeParameter); result.symbol = typeParameter.symbol; From 53b1572ed60283c765fabf32830608f44b1f4458 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 15 Jan 2018 07:59:46 -0800 Subject: [PATCH 19/39] Revert to extends check being part of conditional type --- src/compiler/checker.ts | 93 +++++++++++++++--------------- src/compiler/declarationEmitter.ts | 4 +- src/compiler/emitter.ts | 4 +- src/compiler/factory.ts | 12 ++-- src/compiler/parser.ts | 23 +++----- src/compiler/types.ts | 8 ++- src/compiler/visitor.ts | 3 +- 7 files changed, 75 insertions(+), 72 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 328f37100290c..de3666b0ad5bd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2643,10 +2643,11 @@ namespace ts { return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode); } if (type.flags & TypeFlags.Conditional) { - const conditionTypeNode = typeToTypeNodeHelper((type).conditionType, context); + const checkTypeNode = typeToTypeNodeHelper((type).checkType, context); + const extendsTypeNode = typeToTypeNodeHelper((type).extendsType, context); const trueTypeNode = typeToTypeNodeHelper((type).trueType, context); const falseTypeNode = typeToTypeNodeHelper((type).falseType, context); - return createConditionalTypeNode(conditionTypeNode, trueTypeNode, falseTypeNode); + return createConditionalTypeNode(checkTypeNode, extendsTypeNode, trueTypeNode, falseTypeNode); } if (type.flags & TypeFlags.Extends) { const leftTypeNode = typeToTypeNodeHelper((type).checkType, context); @@ -3422,7 +3423,11 @@ namespace ts { writePunctuation(writer, SyntaxKind.CloseBracketToken); } else if (type.flags & TypeFlags.Conditional) { - writeType((type).conditionType, TypeFormatFlags.InElementType); + 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); @@ -6396,14 +6401,11 @@ namespace ts { // with its constraint. We do this because if the constraint is a union type it will be distributed // over the conditional type and possibly reduced. For example, 'T extends undefined ? never : T' // removes 'undefined' from T. - const conditionType = type.conditionType; - if (conditionType.flags & TypeFlags.Extends) { - const checkType = (conditionType).checkType; - if (checkType.flags & TypeFlags.TypeParameter) { - const constraint = getConstraintOfTypeParameter(checkType); - if (constraint) { - return instantiateType(type, createTypeMapper([checkType], [constraint])); - } + const checkType = type.checkType; + if (checkType.flags & TypeFlags.TypeParameter) { + const constraint = getConstraintOfTypeParameter(checkType); + if (constraint) { + return instantiateType(type, createTypeMapper([checkType], [constraint])); } } return undefined; @@ -8387,33 +8389,38 @@ namespace ts { return links.resolvedType; } - function isGenericConditionType(type: Type) { - return maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive | TypeFlags.Extends); - } - - function createConditionalType(conditionType: Type, whenTrueType: Type, whenFalseType: Type, aliasSymbol: Symbol, aliasTypeArguments: Type[]) { + function createConditionalType(checkType: Type, extendsType: Type, trueType: Type, falseType: Type, aliasSymbol: Symbol, aliasTypeArguments: Type[]) { const type = createType(TypeFlags.Conditional); - type.conditionType = conditionType; - type.trueType = whenTrueType; - type.falseType = whenFalseType; + type.checkType = checkType; + type.extendsType = extendsType; + type.trueType = trueType; + type.falseType = falseType; 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]); + function getConditionalType(checkType: Type, extendsType: Type, mapper: TypeMapper, trueType: Type, falseType: Type, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { + // Distribute union types over conditional types + if (checkType.flags & TypeFlags.Union) { + return getUnionType(map((checkType).types, t => getConditionalType(t, extendsType, mapper, trueType, falseType))); + } + // Return trueType for a definitely true extends check + if (isTypeAssignableTo(checkType, extendsType)) { + return instantiateType(trueType, mapper); } - const resultTrueType = instantiateType(whenTrue, mapper); - const resultFalseType = instantiateType(whenFalse, mapper); - const resultTypeArguments = instantiateTypes(aliasTypeArguments, mapper); - const id = condition.id + "," + resultTrueType.id + "," + resultFalseType.id; + // Return falseType for a definitely false extends check + if (!isTypeAssignableTo(instantiateType(checkType, anyMapper), instantiateType(extendsType, constraintMapper))) { + return instantiateType(falseType, mapper); + } + // Otherwise return a deferred conditional type + const resTrueType = instantiateType(trueType, mapper); + const resFalseType = instantiateType(falseType, mapper); + const resTypeArguments = instantiateTypes(aliasTypeArguments, mapper); + const id = checkType.id + "," + extendsType.id + "," + resTrueType.id + "," + resFalseType.id; let type = conditionalTypes.get(id); if (!type) { - conditionalTypes.set(id, type = createConditionalType(condition, resultTrueType, resultFalseType, aliasSymbol, resultTypeArguments)); + conditionalTypes.set(id, type = createConditionalType(checkType, extendsType, resTrueType, resFalseType, aliasSymbol, resTypeArguments)); } return type; } @@ -8421,9 +8428,9 @@ namespace ts { function getTypeFromConditionalTypeNode(node: ConditionalTypeNode): Type { const links = getNodeLinks(node); if (!links.resolvedType) { - links.resolvedType = getConditionalType(getTypeFromTypeNode(node.conditionType), - getTypeFromTypeNode(node.trueType), getTypeFromTypeNode(node.falseType), - getAliasSymbolForTypeNode(node), getAliasTypeArgumentsForTypeNode(node), identityMapper); + links.resolvedType = getConditionalType(getTypeFromTypeNode(node.checkType), getTypeFromTypeNode(node.extendsType), + identityMapper, getTypeFromTypeNode(node.trueType), getTypeFromTypeNode(node.falseType), + getAliasSymbolForTypeNode(node), getAliasTypeArgumentsForTypeNode(node)); } return links.resolvedType; } @@ -9039,23 +9046,19 @@ namespace ts { // Check if we have a conditional type of the form T extends U ? X : Y, where T is a type parameter. // If so, the conditional type is distributive over a union type and when T is instantiated to a union // type A | B, we produce (A extends U ? X : Y) | (B extends U ? X : Y). - 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))); - } + 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).conditionType, mapper), - (type).trueType, (type).falseType, - type.aliasSymbol, type.aliasTypeArguments, mapper); + return getConditionalType(instantiateType(type.checkType, mapper), instantiateType(type.extendsType, mapper), + mapper, type.trueType, type.falseType, type.aliasSymbol, type.aliasTypeArguments); } function instantiateType(type: Type, mapper: TypeMapper): Type { @@ -11644,7 +11647,8 @@ namespace ts { inferFromTypes((source).indexType, (target).indexType); } else if (source.flags & TypeFlags.Conditional && target.flags & TypeFlags.Conditional) { - inferFromTypes((source).conditionType, (target).conditionType); + inferFromTypes((source).checkType, (target).checkType); + inferFromTypes((source).extendsType, (target).extendsType); inferFromTypes((source).trueType, (target).trueType); inferFromTypes((source).falseType, (target).falseType); } @@ -20358,7 +20362,6 @@ namespace ts { function checkConditionalType(node: ConditionalTypeNode) { forEachChild(node, checkSourceElement); - checkTypeAssignableTo(getTypeFromTypeNode(node.conditionType), booleanType, node.conditionType); } function isPrivateWithinAmbient(node: Node): boolean { diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index f4266278c756c..73a910f18d4eb 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -550,7 +550,9 @@ namespace ts { } function emitConditionalType(node: ConditionalTypeNode) { - emitType(node.conditionType); + emitType(node.checkType); + write(" extends "); + emitType(node.extendsType); write(" ? "); emitType(node.trueType); write(" : "); diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 6b7ae73411c47..05166ee539c94 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1134,7 +1134,9 @@ namespace ts { } function emitConditionalType(node: ConditionalTypeNode) { - emit(node.conditionType); + emit(node.checkType); + write(" extends "); + emit(node.extendsType); write(" ? "); emit(node.trueType); write(" : "); diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index e1cf0d00660af..86af989f38c10 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -720,19 +720,21 @@ namespace ts { : node; } - export function createConditionalTypeNode(conditionType: TypeNode, trueType: TypeNode, falseType: TypeNode) { + export function createConditionalTypeNode(checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode) { const node = createSynthesizedNode(SyntaxKind.ConditionalType) as ConditionalTypeNode; - node.conditionType = parenthesizeConditionalTypeMember(conditionType); + node.checkType = parenthesizeConditionalTypeMember(checkType); + node.extendsType = parenthesizeConditionalTypeMember(extendsType); node.trueType = trueType; node.falseType = falseType; return node; } - export function updateConditionalTypeNode(node: ConditionalTypeNode, conditionType: TypeNode, trueType: TypeNode, falseType: TypeNode) { - return node.conditionType !== conditionType + export function updateConditionalTypeNode(node: ConditionalTypeNode, checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode) { + return node.checkType !== checkType + || node.extendsType !== extendsType || node.trueType !== trueType || node.falseType !== falseType - ? updateNode(createConditionalTypeNode(conditionType, trueType, falseType), node) + ? updateNode(createConditionalTypeNode(checkType, extendsType, trueType, falseType), node) : node; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 9e130f290f879..4fbf491d2663a 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -176,7 +176,8 @@ namespace ts { case SyntaxKind.IntersectionType: return visitNodes(cbNode, cbNodes, (node).types); case SyntaxKind.ConditionalType: - return visitNode(cbNode, (node).conditionType) || + return visitNode(cbNode, (node).checkType) || + visitNode(cbNode, (node).extendsType) || visitNode(cbNode, (node).trueType) || visitNode(cbNode, (node).falseType); case SyntaxKind.ParenthesizedType: @@ -2883,23 +2884,13 @@ 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 = parseBinaryTypeOrHigher(); - if (parseOptional(SyntaxKind.QuestionToken)) { + const type = parseUnionTypeOrHigher(); + if (parseOptional(SyntaxKind.ExtendsKeyword)) { const node = createNode(SyntaxKind.ConditionalType, type.pos); - node.conditionType = type; + node.checkType = type; + node.extendsType = parseUnionTypeOrHigher(); + parseExpected(SyntaxKind.QuestionToken); node.trueType = parseConditionalTypeOrHigher(); parseExpected(SyntaxKind.ColonToken); node.falseType = parseConditionalTypeOrHigher(); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 10ae9bcc7a2b7..8861d5572942d 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1099,7 +1099,8 @@ namespace ts { export interface ConditionalTypeNode extends TypeNode { kind: SyntaxKind.ConditionalType; - conditionType: TypeNode; + checkType: TypeNode; + extendsType: TypeNode; trueType: TypeNode; falseType: TypeNode; } @@ -3407,7 +3408,7 @@ namespace ts { Intersection = 1 << 18, // Intersection (T & U) Index = 1 << 19, // keyof T IndexedAccess = 1 << 20, // T[K] - Conditional = 1 << 21, // C ? T : U + Conditional = 1 << 21, // T extends U ? X : Y Extends = 1 << 22, // T extends U /* @internal */ FreshLiteral = 1 << 23, // Fresh literal or unique type @@ -3702,7 +3703,8 @@ namespace ts { } export interface ConditionalType extends InstantiableType { - conditionType: Type; + checkType: Type; + extendsType: Type; trueType: Type; falseType: Type; } diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 81ae691703707..d9d7058cdf4f2 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -387,7 +387,8 @@ namespace ts { case SyntaxKind.ConditionalType: return updateConditionalTypeNode(node, - visitNode((node).conditionType, visitor, isTypeNode), + visitNode((node).checkType, visitor, isTypeNode), + visitNode((node).extendsType, visitor, isTypeNode), visitNode((node).trueType, visitor, isTypeNode), visitNode((node).falseType, visitor, isTypeNode)); From 5094f7677cedbfde6548627f8d30b2e673d2584c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 15 Jan 2018 08:11:05 -0800 Subject: [PATCH 20/39] Remove 'T extends U' type constructor --- src/compiler/binder.ts | 1 - src/compiler/checker.ts | 72 ------------------------------ src/compiler/declarationEmitter.ts | 8 ---- src/compiler/emitter.ts | 8 ---- src/compiler/factory.ts | 22 +-------- src/compiler/parser.ts | 3 -- src/compiler/transformers/ts.ts | 2 - src/compiler/types.ts | 28 +++--------- src/compiler/utilities.ts | 4 -- src/compiler/visitor.ts | 6 --- 10 files changed, 8 insertions(+), 146 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index c509d45f5a64a..5836cf0f41265 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -3428,7 +3428,6 @@ 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 de3666b0ad5bd..9c23c97a2a680 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -281,7 +281,6 @@ namespace ts { const literalTypes = createMap(); const indexedAccessTypes = createMap(); const conditionalTypes = createMap(); - const extendsTypes = createMap(); const evolvingArrayTypes: EvolvingArrayType[] = []; const undefinedProperties = createMap() as UnderscoreEscapedMap; @@ -2649,11 +2648,6 @@ namespace ts { const falseTypeNode = typeToTypeNodeHelper((type).falseType, context); return createConditionalTypeNode(checkTypeNode, extendsTypeNode, 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."); @@ -3437,13 +3431,6 @@ 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 // { ... } @@ -6425,9 +6412,6 @@ namespace ts { else if (type.flags & TypeFlags.Index) { return stringType; } - else if (type.flags & TypeFlags.Extends) { - return booleanType; - } return undefined; } @@ -6496,9 +6480,6 @@ namespace ts { if (t.flags & TypeFlags.Conditional) { return getBaseConstraint(getConstraintOfConditionalType(t)); } - if (t.flags & TypeFlags.Extends) { - return booleanType; - } if (isGenericMappedType(t)) { return emptyObjectType; } @@ -8435,47 +8416,6 @@ namespace ts { 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))); - } - if (checkType.flags & TypeFlags.Any) { - return booleanType; - } - // Return trueType if type is definitely assignable - if (isTypeAssignableTo(checkType, extendsType)) { - return trueType; - } - // Return falseType is type is definitely not assignable - if (!isTypeAssignableTo(instantiateType(checkType, anyMapper), instantiateType(extendsType, constraintMapper))) { - // Type is definitely not assignable - return falseType; - } - // Type is possibly assignable, defer the check - 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; - } - function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node: TypeNode): Type { const links = getNodeLinks(node); if (!links.resolvedType) { @@ -8766,8 +8706,6 @@ 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: @@ -9096,9 +9034,6 @@ 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; } @@ -11652,10 +11587,6 @@ namespace ts { inferFromTypes((source).trueType, (target).trueType); inferFromTypes((source).falseType, (target).falseType); } - else if (source.flags & TypeFlags.Extends && target.flags & TypeFlags.Extends) { - inferFromTypes((source).checkType, (target).checkType); - inferFromTypes((source).extendsType, (target).extendsType); - } else if (target.flags & TypeFlags.UnionOrIntersection) { const targetTypes = (target).types; let typeVariableCount = 0; @@ -24015,9 +23946,6 @@ namespace ts { 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 73a910f18d4eb..75b4ccf9ba857 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -456,8 +456,6 @@ 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: @@ -571,12 +569,6 @@ 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 05166ee539c94..10ecd3c8ffe74 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -572,8 +572,6 @@ 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: @@ -1159,12 +1157,6 @@ 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 86af989f38c10..070715d8ea3fa 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -767,22 +767,6 @@ 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); @@ -4119,10 +4103,6 @@ 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: @@ -4131,7 +4111,7 @@ namespace ts { case SyntaxKind.ConstructorType: return createParenthesizedType(member); } - return parenthesizeBinaryTypeMember(member); + return parenthesizeConditionalTypeMember(member); } export function parenthesizeArrayTypeMember(member: TypeNode) { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 4fbf491d2663a..82b85444bc508 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -183,9 +183,6 @@ namespace ts { 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); diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index d29cf2093398f..20bc77c5e17e1 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -389,7 +389,6 @@ namespace ts { case SyntaxKind.ParenthesizedType: case SyntaxKind.ThisType: case SyntaxKind.TypeOperator: - case SyntaxKind.BinaryType: case SyntaxKind.IndexedAccessType: case SyntaxKind.MappedType: case SyntaxKind.LiteralType: @@ -1887,7 +1886,6 @@ 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 8861d5572942d..5acee864e1bbc 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -252,7 +252,6 @@ namespace ts { ParenthesizedType, ThisType, TypeOperator, - BinaryType, IndexedAccessType, MappedType, LiteralType, @@ -1116,13 +1115,6 @@ 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; @@ -3409,16 +3401,15 @@ namespace ts { Index = 1 << 19, // keyof T IndexedAccess = 1 << 20, // T[K] Conditional = 1 << 21, // T extends U ? X : Y - Extends = 1 << 22, // T extends U /* @internal */ - FreshLiteral = 1 << 23, // Fresh literal or unique type + FreshLiteral = 1 << 22, // Fresh literal or unique type /* @internal */ - ContainsWideningType = 1 << 24, // Type is or contains undefined or null widening type + ContainsWideningType = 1 << 23, // Type is or contains undefined or null widening type /* @internal */ - ContainsObjectLiteral = 1 << 25, // Type is or contains object literal type + ContainsObjectLiteral = 1 << 24, // Type is or contains object literal type /* @internal */ - ContainsAnyFunctionType = 1 << 26, // Type is or contains the anyFunctionType - NonPrimitive = 1 << 27, // intrinsic object type + ContainsAnyFunctionType = 1 << 25, // Type is or contains the anyFunctionType + NonPrimitive = 1 << 26, // intrinsic object type /* @internal */ GenericMappedType = 1 << 29, // Flag used by maybeTypeOfKind @@ -3438,14 +3429,14 @@ 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 | Extends, + BooleanLike = Boolean | BooleanLiteral, EnumLike = Enum | EnumLiteral, ESSymbolLike = ESSymbol | UniqueESSymbol, UnionOrIntersection = Union | Intersection, StructuredType = Object | Union | Intersection, TypeVariable = TypeParameter | IndexedAccess, InstantiableNonPrimitive = TypeVariable | Conditional, - InstantiablePrimitive = Index | Extends, + InstantiablePrimitive = Index, Instantiable = InstantiableNonPrimitive | InstantiablePrimitive, StructuredOrInstantiable = StructuredType | Instantiable, @@ -3709,11 +3700,6 @@ namespace ts { falseType: Type; } - export interface ExtendsType extends InstantiableType { - checkType: Type; - extendsType: Type; - } - export const enum SignatureKind { Call, Construct, diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index fb70321e082ee..a111016dd8fa0 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -4549,10 +4549,6 @@ 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 d9d7058cdf4f2..b047a778015b4 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -400,12 +400,6 @@ 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), From 925da864960459f3ffcbf5b5f1400d6e9f9f1cf6 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 15 Jan 2018 08:15:32 -0800 Subject: [PATCH 21/39] Accept new baselines --- .../reference/api/tsserverlibrary.d.ts | 299 +++++++++--------- tests/baselines/reference/api/typescript.d.ts | 299 +++++++++--------- 2 files changed, 286 insertions(+), 312 deletions(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index e11bbb2bf3a0e..257c3339ea9d6 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -233,132 +233,131 @@ declare namespace ts { ParenthesizedType = 170, ThisType = 171, TypeOperator = 172, - BinaryType = 173, - IndexedAccessType = 174, - MappedType = 175, - LiteralType = 176, - ObjectBindingPattern = 177, - ArrayBindingPattern = 178, - BindingElement = 179, - ArrayLiteralExpression = 180, - ObjectLiteralExpression = 181, - PropertyAccessExpression = 182, - ElementAccessExpression = 183, - CallExpression = 184, - NewExpression = 185, - TaggedTemplateExpression = 186, - TypeAssertionExpression = 187, - ParenthesizedExpression = 188, - FunctionExpression = 189, - ArrowFunction = 190, - DeleteExpression = 191, - TypeOfExpression = 192, - VoidExpression = 193, - AwaitExpression = 194, - PrefixUnaryExpression = 195, - PostfixUnaryExpression = 196, - BinaryExpression = 197, - ConditionalExpression = 198, - TemplateExpression = 199, - YieldExpression = 200, - SpreadElement = 201, - ClassExpression = 202, - OmittedExpression = 203, - ExpressionWithTypeArguments = 204, - AsExpression = 205, - NonNullExpression = 206, - MetaProperty = 207, - TemplateSpan = 208, - SemicolonClassElement = 209, - Block = 210, - VariableStatement = 211, - EmptyStatement = 212, - ExpressionStatement = 213, - IfStatement = 214, - DoStatement = 215, - WhileStatement = 216, - ForStatement = 217, - ForInStatement = 218, - ForOfStatement = 219, - ContinueStatement = 220, - BreakStatement = 221, - ReturnStatement = 222, - WithStatement = 223, - SwitchStatement = 224, - LabeledStatement = 225, - ThrowStatement = 226, - TryStatement = 227, - DebuggerStatement = 228, - VariableDeclaration = 229, - VariableDeclarationList = 230, - FunctionDeclaration = 231, - ClassDeclaration = 232, - InterfaceDeclaration = 233, - TypeAliasDeclaration = 234, - EnumDeclaration = 235, - ModuleDeclaration = 236, - ModuleBlock = 237, - CaseBlock = 238, - NamespaceExportDeclaration = 239, - ImportEqualsDeclaration = 240, - ImportDeclaration = 241, - ImportClause = 242, - NamespaceImport = 243, - NamedImports = 244, - ImportSpecifier = 245, - ExportAssignment = 246, - ExportDeclaration = 247, - NamedExports = 248, - ExportSpecifier = 249, - MissingDeclaration = 250, - ExternalModuleReference = 251, - JsxElement = 252, - JsxSelfClosingElement = 253, - JsxOpeningElement = 254, - JsxClosingElement = 255, - JsxFragment = 256, - JsxOpeningFragment = 257, - JsxClosingFragment = 258, - JsxAttribute = 259, - JsxAttributes = 260, - JsxSpreadAttribute = 261, - JsxExpression = 262, - CaseClause = 263, - DefaultClause = 264, - HeritageClause = 265, - CatchClause = 266, - PropertyAssignment = 267, - ShorthandPropertyAssignment = 268, - SpreadAssignment = 269, - EnumMember = 270, - SourceFile = 271, - Bundle = 272, - JSDocTypeExpression = 273, - JSDocAllType = 274, - JSDocUnknownType = 275, - JSDocNullableType = 276, - JSDocNonNullableType = 277, - JSDocOptionalType = 278, - JSDocFunctionType = 279, - JSDocVariadicType = 280, - JSDocComment = 281, - JSDocTypeLiteral = 282, - JSDocTag = 283, - JSDocAugmentsTag = 284, - JSDocClassTag = 285, - JSDocParameterTag = 286, - JSDocReturnTag = 287, - JSDocTypeTag = 288, - JSDocTemplateTag = 289, - JSDocTypedefTag = 290, - JSDocPropertyTag = 291, - SyntaxList = 292, - NotEmittedStatement = 293, - PartiallyEmittedExpression = 294, - CommaListExpression = 295, - MergeDeclarationMarker = 296, - EndOfDeclarationMarker = 297, - Count = 298, + IndexedAccessType = 173, + MappedType = 174, + LiteralType = 175, + ObjectBindingPattern = 176, + ArrayBindingPattern = 177, + BindingElement = 178, + ArrayLiteralExpression = 179, + ObjectLiteralExpression = 180, + PropertyAccessExpression = 181, + ElementAccessExpression = 182, + CallExpression = 183, + NewExpression = 184, + TaggedTemplateExpression = 185, + TypeAssertionExpression = 186, + ParenthesizedExpression = 187, + FunctionExpression = 188, + ArrowFunction = 189, + DeleteExpression = 190, + TypeOfExpression = 191, + VoidExpression = 192, + AwaitExpression = 193, + PrefixUnaryExpression = 194, + PostfixUnaryExpression = 195, + BinaryExpression = 196, + ConditionalExpression = 197, + TemplateExpression = 198, + YieldExpression = 199, + SpreadElement = 200, + ClassExpression = 201, + OmittedExpression = 202, + ExpressionWithTypeArguments = 203, + AsExpression = 204, + NonNullExpression = 205, + MetaProperty = 206, + TemplateSpan = 207, + SemicolonClassElement = 208, + Block = 209, + VariableStatement = 210, + EmptyStatement = 211, + ExpressionStatement = 212, + IfStatement = 213, + DoStatement = 214, + WhileStatement = 215, + ForStatement = 216, + ForInStatement = 217, + ForOfStatement = 218, + ContinueStatement = 219, + BreakStatement = 220, + ReturnStatement = 221, + WithStatement = 222, + SwitchStatement = 223, + LabeledStatement = 224, + ThrowStatement = 225, + TryStatement = 226, + DebuggerStatement = 227, + VariableDeclaration = 228, + VariableDeclarationList = 229, + FunctionDeclaration = 230, + ClassDeclaration = 231, + InterfaceDeclaration = 232, + TypeAliasDeclaration = 233, + EnumDeclaration = 234, + ModuleDeclaration = 235, + ModuleBlock = 236, + CaseBlock = 237, + NamespaceExportDeclaration = 238, + ImportEqualsDeclaration = 239, + ImportDeclaration = 240, + ImportClause = 241, + NamespaceImport = 242, + NamedImports = 243, + ImportSpecifier = 244, + ExportAssignment = 245, + ExportDeclaration = 246, + NamedExports = 247, + ExportSpecifier = 248, + MissingDeclaration = 249, + ExternalModuleReference = 250, + JsxElement = 251, + JsxSelfClosingElement = 252, + JsxOpeningElement = 253, + JsxClosingElement = 254, + JsxFragment = 255, + JsxOpeningFragment = 256, + JsxClosingFragment = 257, + JsxAttribute = 258, + JsxAttributes = 259, + JsxSpreadAttribute = 260, + JsxExpression = 261, + CaseClause = 262, + DefaultClause = 263, + HeritageClause = 264, + CatchClause = 265, + PropertyAssignment = 266, + ShorthandPropertyAssignment = 267, + SpreadAssignment = 268, + EnumMember = 269, + SourceFile = 270, + Bundle = 271, + JSDocTypeExpression = 272, + JSDocAllType = 273, + JSDocUnknownType = 274, + JSDocNullableType = 275, + JSDocNonNullableType = 276, + JSDocOptionalType = 277, + JSDocFunctionType = 278, + JSDocVariadicType = 279, + JSDocComment = 280, + JSDocTypeLiteral = 281, + JSDocTag = 282, + JSDocAugmentsTag = 283, + JSDocClassTag = 284, + JSDocParameterTag = 285, + JSDocReturnTag = 286, + JSDocTypeTag = 287, + JSDocTemplateTag = 288, + JSDocTypedefTag = 289, + JSDocPropertyTag = 290, + SyntaxList = 291, + NotEmittedStatement = 292, + PartiallyEmittedExpression = 293, + CommaListExpression = 294, + MergeDeclarationMarker = 295, + EndOfDeclarationMarker = 296, + Count = 297, FirstAssignment = 58, LastAssignment = 70, FirstCompoundAssignment = 59, @@ -370,7 +369,7 @@ declare namespace ts { FirstFutureReservedWord = 108, LastFutureReservedWord = 116, FirstTypeNode = 159, - LastTypeNode = 176, + LastTypeNode = 175, FirstPunctuation = 17, LastPunctuation = 70, FirstToken = 0, @@ -384,10 +383,10 @@ declare namespace ts { FirstBinaryOperator = 27, LastBinaryOperator = 70, FirstNode = 144, - FirstJSDocNode = 273, - LastJSDocNode = 291, - FirstJSDocTagNode = 283, - LastJSDocTagNode = 291, + FirstJSDocNode = 272, + LastJSDocNode = 290, + FirstJSDocTagNode = 282, + LastJSDocTagNode = 290, } enum NodeFlags { None = 0, @@ -737,7 +736,8 @@ declare namespace ts { } interface ConditionalTypeNode extends TypeNode { kind: SyntaxKind.ConditionalType; - conditionType: TypeNode; + checkType: TypeNode; + extendsType: TypeNode; trueType: TypeNode; falseType: TypeNode; } @@ -750,12 +750,6 @@ declare namespace ts { operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword; type: TypeNode; } - interface BinaryTypeNode extends TypeNode { - kind: SyntaxKind.BinaryType; - left: TypeNode; - operator: SyntaxKind.ExtendsKeyword; - right: TypeNode; - } interface IndexedAccessTypeNode extends TypeNode { kind: SyntaxKind.IndexedAccessType; objectType: TypeNode; @@ -2027,26 +2021,25 @@ declare namespace ts { Index = 524288, IndexedAccess = 1048576, Conditional = 2097152, - Extends = 4194304, - NonPrimitive = 134217728, + NonPrimitive = 67108864, Literal = 224, Unit = 13536, StringOrNumberLiteral = 96, PossiblyFalsy = 14574, StringLike = 524322, NumberLike = 84, - BooleanLike = 4194440, + BooleanLike = 136, EnumLike = 272, ESSymbolLike = 1536, UnionOrIntersection = 393216, StructuredType = 458752, TypeVariable = 1081344, InstantiableNonPrimitive = 3178496, - InstantiablePrimitive = 4718592, - Instantiable = 7897088, - StructuredOrInstantiable = 8355840, - Narrowable = 142575359, - NotUnionOrUnit = 134283777, + InstantiablePrimitive = 524288, + Instantiable = 3702784, + StructuredOrInstantiable = 4161536, + Narrowable = 71272191, + NotUnionOrUnit = 67174913, } type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression; interface Type { @@ -2147,13 +2140,10 @@ declare namespace ts { type: InstantiableType | UnionOrIntersectionType; } interface ConditionalType extends InstantiableType { - conditionType: Type; - trueType: Type; - falseType: Type; - } - interface ExtendsType extends InstantiableType { checkType: Type; extendsType: Type; + trueType: Type; + falseType: Type; } enum SignatureKind { Call = 0, @@ -2974,7 +2964,6 @@ declare namespace ts { function isParenthesizedTypeNode(node: Node): node is ParenthesizedTypeNode; function isThisTypeNode(node: Node): node is ThisTypeNode; function isTypeOperatorNode(node: Node): node is TypeOperatorNode; - function isBinaryTypeNode(node: Node): node is BinaryTypeNode; function isIndexedAccessTypeNode(node: Node): node is IndexedAccessTypeNode; function isMappedTypeNode(node: Node): node is MappedTypeNode; function isLiteralTypeNode(node: Node): node is LiteralTypeNode; @@ -3388,16 +3377,14 @@ declare namespace ts { function createIntersectionTypeNode(types: TypeNode[]): IntersectionTypeNode; function updateIntersectionTypeNode(node: IntersectionTypeNode, types: NodeArray): IntersectionTypeNode; function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: ReadonlyArray): UnionOrIntersectionTypeNode; - function createConditionalTypeNode(conditionType: TypeNode, trueType: TypeNode, falseType: TypeNode): ConditionalTypeNode; - function updateConditionalTypeNode(node: ConditionalTypeNode, conditionType: TypeNode, trueType: TypeNode, falseType: TypeNode): ConditionalTypeNode; + function createConditionalTypeNode(checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode): ConditionalTypeNode; + function updateConditionalTypeNode(node: ConditionalTypeNode, checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode): ConditionalTypeNode; function createParenthesizedType(type: TypeNode): ParenthesizedTypeNode; function updateParenthesizedType(node: ParenthesizedTypeNode, type: TypeNode): ParenthesizedTypeNode; function createThisTypeNode(): ThisTypeNode; function createTypeOperatorNode(type: TypeNode): TypeOperatorNode; function createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword, type: TypeNode): TypeOperatorNode; function updateTypeOperatorNode(node: TypeOperatorNode, type: TypeNode): TypeOperatorNode; - function createBinaryTypeNode(left: TypeNode, operator: SyntaxKind.ExtendsKeyword, right: TypeNode): BinaryTypeNode; - function updateBinaryTypeNode(node: BinaryTypeNode, left: TypeNode, operator: SyntaxKind.ExtendsKeyword, right: TypeNode): BinaryTypeNode; function createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode; function updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode; function createMappedTypeNode(readonlyToken: ReadonlyToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | undefined, type: TypeNode | undefined): MappedTypeNode; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 7635dc581a425..2513867ef29e2 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -233,132 +233,131 @@ declare namespace ts { ParenthesizedType = 170, ThisType = 171, TypeOperator = 172, - BinaryType = 173, - IndexedAccessType = 174, - MappedType = 175, - LiteralType = 176, - ObjectBindingPattern = 177, - ArrayBindingPattern = 178, - BindingElement = 179, - ArrayLiteralExpression = 180, - ObjectLiteralExpression = 181, - PropertyAccessExpression = 182, - ElementAccessExpression = 183, - CallExpression = 184, - NewExpression = 185, - TaggedTemplateExpression = 186, - TypeAssertionExpression = 187, - ParenthesizedExpression = 188, - FunctionExpression = 189, - ArrowFunction = 190, - DeleteExpression = 191, - TypeOfExpression = 192, - VoidExpression = 193, - AwaitExpression = 194, - PrefixUnaryExpression = 195, - PostfixUnaryExpression = 196, - BinaryExpression = 197, - ConditionalExpression = 198, - TemplateExpression = 199, - YieldExpression = 200, - SpreadElement = 201, - ClassExpression = 202, - OmittedExpression = 203, - ExpressionWithTypeArguments = 204, - AsExpression = 205, - NonNullExpression = 206, - MetaProperty = 207, - TemplateSpan = 208, - SemicolonClassElement = 209, - Block = 210, - VariableStatement = 211, - EmptyStatement = 212, - ExpressionStatement = 213, - IfStatement = 214, - DoStatement = 215, - WhileStatement = 216, - ForStatement = 217, - ForInStatement = 218, - ForOfStatement = 219, - ContinueStatement = 220, - BreakStatement = 221, - ReturnStatement = 222, - WithStatement = 223, - SwitchStatement = 224, - LabeledStatement = 225, - ThrowStatement = 226, - TryStatement = 227, - DebuggerStatement = 228, - VariableDeclaration = 229, - VariableDeclarationList = 230, - FunctionDeclaration = 231, - ClassDeclaration = 232, - InterfaceDeclaration = 233, - TypeAliasDeclaration = 234, - EnumDeclaration = 235, - ModuleDeclaration = 236, - ModuleBlock = 237, - CaseBlock = 238, - NamespaceExportDeclaration = 239, - ImportEqualsDeclaration = 240, - ImportDeclaration = 241, - ImportClause = 242, - NamespaceImport = 243, - NamedImports = 244, - ImportSpecifier = 245, - ExportAssignment = 246, - ExportDeclaration = 247, - NamedExports = 248, - ExportSpecifier = 249, - MissingDeclaration = 250, - ExternalModuleReference = 251, - JsxElement = 252, - JsxSelfClosingElement = 253, - JsxOpeningElement = 254, - JsxClosingElement = 255, - JsxFragment = 256, - JsxOpeningFragment = 257, - JsxClosingFragment = 258, - JsxAttribute = 259, - JsxAttributes = 260, - JsxSpreadAttribute = 261, - JsxExpression = 262, - CaseClause = 263, - DefaultClause = 264, - HeritageClause = 265, - CatchClause = 266, - PropertyAssignment = 267, - ShorthandPropertyAssignment = 268, - SpreadAssignment = 269, - EnumMember = 270, - SourceFile = 271, - Bundle = 272, - JSDocTypeExpression = 273, - JSDocAllType = 274, - JSDocUnknownType = 275, - JSDocNullableType = 276, - JSDocNonNullableType = 277, - JSDocOptionalType = 278, - JSDocFunctionType = 279, - JSDocVariadicType = 280, - JSDocComment = 281, - JSDocTypeLiteral = 282, - JSDocTag = 283, - JSDocAugmentsTag = 284, - JSDocClassTag = 285, - JSDocParameterTag = 286, - JSDocReturnTag = 287, - JSDocTypeTag = 288, - JSDocTemplateTag = 289, - JSDocTypedefTag = 290, - JSDocPropertyTag = 291, - SyntaxList = 292, - NotEmittedStatement = 293, - PartiallyEmittedExpression = 294, - CommaListExpression = 295, - MergeDeclarationMarker = 296, - EndOfDeclarationMarker = 297, - Count = 298, + IndexedAccessType = 173, + MappedType = 174, + LiteralType = 175, + ObjectBindingPattern = 176, + ArrayBindingPattern = 177, + BindingElement = 178, + ArrayLiteralExpression = 179, + ObjectLiteralExpression = 180, + PropertyAccessExpression = 181, + ElementAccessExpression = 182, + CallExpression = 183, + NewExpression = 184, + TaggedTemplateExpression = 185, + TypeAssertionExpression = 186, + ParenthesizedExpression = 187, + FunctionExpression = 188, + ArrowFunction = 189, + DeleteExpression = 190, + TypeOfExpression = 191, + VoidExpression = 192, + AwaitExpression = 193, + PrefixUnaryExpression = 194, + PostfixUnaryExpression = 195, + BinaryExpression = 196, + ConditionalExpression = 197, + TemplateExpression = 198, + YieldExpression = 199, + SpreadElement = 200, + ClassExpression = 201, + OmittedExpression = 202, + ExpressionWithTypeArguments = 203, + AsExpression = 204, + NonNullExpression = 205, + MetaProperty = 206, + TemplateSpan = 207, + SemicolonClassElement = 208, + Block = 209, + VariableStatement = 210, + EmptyStatement = 211, + ExpressionStatement = 212, + IfStatement = 213, + DoStatement = 214, + WhileStatement = 215, + ForStatement = 216, + ForInStatement = 217, + ForOfStatement = 218, + ContinueStatement = 219, + BreakStatement = 220, + ReturnStatement = 221, + WithStatement = 222, + SwitchStatement = 223, + LabeledStatement = 224, + ThrowStatement = 225, + TryStatement = 226, + DebuggerStatement = 227, + VariableDeclaration = 228, + VariableDeclarationList = 229, + FunctionDeclaration = 230, + ClassDeclaration = 231, + InterfaceDeclaration = 232, + TypeAliasDeclaration = 233, + EnumDeclaration = 234, + ModuleDeclaration = 235, + ModuleBlock = 236, + CaseBlock = 237, + NamespaceExportDeclaration = 238, + ImportEqualsDeclaration = 239, + ImportDeclaration = 240, + ImportClause = 241, + NamespaceImport = 242, + NamedImports = 243, + ImportSpecifier = 244, + ExportAssignment = 245, + ExportDeclaration = 246, + NamedExports = 247, + ExportSpecifier = 248, + MissingDeclaration = 249, + ExternalModuleReference = 250, + JsxElement = 251, + JsxSelfClosingElement = 252, + JsxOpeningElement = 253, + JsxClosingElement = 254, + JsxFragment = 255, + JsxOpeningFragment = 256, + JsxClosingFragment = 257, + JsxAttribute = 258, + JsxAttributes = 259, + JsxSpreadAttribute = 260, + JsxExpression = 261, + CaseClause = 262, + DefaultClause = 263, + HeritageClause = 264, + CatchClause = 265, + PropertyAssignment = 266, + ShorthandPropertyAssignment = 267, + SpreadAssignment = 268, + EnumMember = 269, + SourceFile = 270, + Bundle = 271, + JSDocTypeExpression = 272, + JSDocAllType = 273, + JSDocUnknownType = 274, + JSDocNullableType = 275, + JSDocNonNullableType = 276, + JSDocOptionalType = 277, + JSDocFunctionType = 278, + JSDocVariadicType = 279, + JSDocComment = 280, + JSDocTypeLiteral = 281, + JSDocTag = 282, + JSDocAugmentsTag = 283, + JSDocClassTag = 284, + JSDocParameterTag = 285, + JSDocReturnTag = 286, + JSDocTypeTag = 287, + JSDocTemplateTag = 288, + JSDocTypedefTag = 289, + JSDocPropertyTag = 290, + SyntaxList = 291, + NotEmittedStatement = 292, + PartiallyEmittedExpression = 293, + CommaListExpression = 294, + MergeDeclarationMarker = 295, + EndOfDeclarationMarker = 296, + Count = 297, FirstAssignment = 58, LastAssignment = 70, FirstCompoundAssignment = 59, @@ -370,7 +369,7 @@ declare namespace ts { FirstFutureReservedWord = 108, LastFutureReservedWord = 116, FirstTypeNode = 159, - LastTypeNode = 176, + LastTypeNode = 175, FirstPunctuation = 17, LastPunctuation = 70, FirstToken = 0, @@ -384,10 +383,10 @@ declare namespace ts { FirstBinaryOperator = 27, LastBinaryOperator = 70, FirstNode = 144, - FirstJSDocNode = 273, - LastJSDocNode = 291, - FirstJSDocTagNode = 283, - LastJSDocTagNode = 291, + FirstJSDocNode = 272, + LastJSDocNode = 290, + FirstJSDocTagNode = 282, + LastJSDocTagNode = 290, } enum NodeFlags { None = 0, @@ -737,7 +736,8 @@ declare namespace ts { } interface ConditionalTypeNode extends TypeNode { kind: SyntaxKind.ConditionalType; - conditionType: TypeNode; + checkType: TypeNode; + extendsType: TypeNode; trueType: TypeNode; falseType: TypeNode; } @@ -750,12 +750,6 @@ declare namespace ts { operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword; type: TypeNode; } - interface BinaryTypeNode extends TypeNode { - kind: SyntaxKind.BinaryType; - left: TypeNode; - operator: SyntaxKind.ExtendsKeyword; - right: TypeNode; - } interface IndexedAccessTypeNode extends TypeNode { kind: SyntaxKind.IndexedAccessType; objectType: TypeNode; @@ -2027,26 +2021,25 @@ declare namespace ts { Index = 524288, IndexedAccess = 1048576, Conditional = 2097152, - Extends = 4194304, - NonPrimitive = 134217728, + NonPrimitive = 67108864, Literal = 224, Unit = 13536, StringOrNumberLiteral = 96, PossiblyFalsy = 14574, StringLike = 524322, NumberLike = 84, - BooleanLike = 4194440, + BooleanLike = 136, EnumLike = 272, ESSymbolLike = 1536, UnionOrIntersection = 393216, StructuredType = 458752, TypeVariable = 1081344, InstantiableNonPrimitive = 3178496, - InstantiablePrimitive = 4718592, - Instantiable = 7897088, - StructuredOrInstantiable = 8355840, - Narrowable = 142575359, - NotUnionOrUnit = 134283777, + InstantiablePrimitive = 524288, + Instantiable = 3702784, + StructuredOrInstantiable = 4161536, + Narrowable = 71272191, + NotUnionOrUnit = 67174913, } type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression; interface Type { @@ -2147,13 +2140,10 @@ declare namespace ts { type: InstantiableType | UnionOrIntersectionType; } interface ConditionalType extends InstantiableType { - conditionType: Type; - trueType: Type; - falseType: Type; - } - interface ExtendsType extends InstantiableType { checkType: Type; extendsType: Type; + trueType: Type; + falseType: Type; } enum SignatureKind { Call = 0, @@ -3027,7 +3017,6 @@ declare namespace ts { function isParenthesizedTypeNode(node: Node): node is ParenthesizedTypeNode; function isThisTypeNode(node: Node): node is ThisTypeNode; function isTypeOperatorNode(node: Node): node is TypeOperatorNode; - function isBinaryTypeNode(node: Node): node is BinaryTypeNode; function isIndexedAccessTypeNode(node: Node): node is IndexedAccessTypeNode; function isMappedTypeNode(node: Node): node is MappedTypeNode; function isLiteralTypeNode(node: Node): node is LiteralTypeNode; @@ -3335,16 +3324,14 @@ declare namespace ts { function createIntersectionTypeNode(types: TypeNode[]): IntersectionTypeNode; function updateIntersectionTypeNode(node: IntersectionTypeNode, types: NodeArray): IntersectionTypeNode; function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: ReadonlyArray): UnionOrIntersectionTypeNode; - function createConditionalTypeNode(conditionType: TypeNode, trueType: TypeNode, falseType: TypeNode): ConditionalTypeNode; - function updateConditionalTypeNode(node: ConditionalTypeNode, conditionType: TypeNode, trueType: TypeNode, falseType: TypeNode): ConditionalTypeNode; + function createConditionalTypeNode(checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode): ConditionalTypeNode; + function updateConditionalTypeNode(node: ConditionalTypeNode, checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode): ConditionalTypeNode; function createParenthesizedType(type: TypeNode): ParenthesizedTypeNode; function updateParenthesizedType(node: ParenthesizedTypeNode, type: TypeNode): ParenthesizedTypeNode; function createThisTypeNode(): ThisTypeNode; function createTypeOperatorNode(type: TypeNode): TypeOperatorNode; function createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword, type: TypeNode): TypeOperatorNode; function updateTypeOperatorNode(node: TypeOperatorNode, type: TypeNode): TypeOperatorNode; - function createBinaryTypeNode(left: TypeNode, operator: SyntaxKind.ExtendsKeyword, right: TypeNode): BinaryTypeNode; - function updateBinaryTypeNode(node: BinaryTypeNode, left: TypeNode, operator: SyntaxKind.ExtendsKeyword, right: TypeNode): BinaryTypeNode; function createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode; function updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode; function createMappedTypeNode(readonlyToken: ReadonlyToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | undefined, type: TypeNode | undefined): MappedTypeNode; From e8d1740da85a0ef75b9e711d9a3f12edd8f25fa7 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 15 Jan 2018 11:06:18 -0800 Subject: [PATCH 22/39] Introduce substitution types to use for constrained type parameters --- src/compiler/checker.ts | 46 ++++++++++++++++++++++++++++++++++++++--- src/compiler/types.ts | 20 ++++++++++++------ 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9c23c97a2a680..41717d4f0f7a0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2648,6 +2648,9 @@ namespace ts { const falseTypeNode = typeToTypeNodeHelper((type).falseType, context); return createConditionalTypeNode(checkTypeNode, extendsTypeNode, trueTypeNode, falseTypeNode); } + if (type.flags & TypeFlags.Substitution) { + return typeToTypeNodeHelper((type).typeParameter, context); + } Debug.fail("Should be unreachable."); @@ -3431,6 +3434,9 @@ namespace ts { writeSpace(writer); writeType((type).falseType, TypeFormatFlags.InElementType); } + else if (type.flags & TypeFlags.Substitution) { + writeType((type).typeParameter, TypeFormatFlags.None); + } else { // Should never get here // { ... } @@ -6480,6 +6486,9 @@ namespace ts { if (t.flags & TypeFlags.Conditional) { return getBaseConstraint(getConstraintOfConditionalType(t)); } + if (t.flags & TypeFlags.Substitution) { + return getBaseConstraint((t).substitute); + } if (isGenericMappedType(t)) { return emptyObjectType; } @@ -7458,7 +7467,7 @@ namespace ts { error(node, Diagnostics.Type_0_is_not_generic, symbolToString(symbol)); return unknownType; } - return res; + return res.flags & TypeFlags.TypeParameter ? getConstrainedTypeParameter(res, node) : res; } if (!(symbol.flags & SymbolFlags.Value && isJSDocTypeReference(node))) { @@ -7497,6 +7506,26 @@ namespace ts { } } + function getConstrainedTypeParameter(typeParameter: TypeParameter, node: Node) { + let constraints: Type[]; + while (isTypeNode(node)) { + const parent = node.parent; + if (parent.kind === SyntaxKind.ConditionalType && node === (parent).trueType) { + if (getTypeFromTypeNode((parent).checkType) === typeParameter) { + constraints = append(constraints, getTypeFromTypeNode((parent).extendsType)); + } + } + node = parent; + } + if (constraints) { + const result = createType(TypeFlags.Substitution); + result.typeParameter = typeParameter; + result.substitute = getIntersectionType(append(constraints, typeParameter)); + return result; + } + return typeParameter; + } + function isJSDocTypeReference(node: TypeReferenceType): node is TypeReferenceNode { return node.flags & NodeFlags.JSDoc && node.kind === SyntaxKind.TypeReference; } @@ -8395,13 +8424,14 @@ namespace ts { return instantiateType(falseType, mapper); } // Otherwise return a deferred conditional type + const resCheckType = checkType.flags & TypeFlags.Substitution ? (checkType).typeParameter : checkType; const resTrueType = instantiateType(trueType, mapper); const resFalseType = instantiateType(falseType, mapper); const resTypeArguments = instantiateTypes(aliasTypeArguments, mapper); - const id = checkType.id + "," + extendsType.id + "," + resTrueType.id + "," + resFalseType.id; + const id = resCheckType.id + "," + extendsType.id + "," + resTrueType.id + "," + resFalseType.id; let type = conditionalTypes.get(id); if (!type) { - conditionalTypes.set(id, type = createConditionalType(checkType, extendsType, resTrueType, resFalseType, aliasSymbol, resTypeArguments)); + conditionalTypes.set(id, type = createConditionalType(resCheckType, extendsType, resTrueType, resFalseType, aliasSymbol, resTypeArguments)); } return type; } @@ -9034,6 +9064,9 @@ namespace ts { if (type.flags & TypeFlags.Conditional) { return getConditionalTypeInstantiation(type, mapper); } + if (type.flags & TypeFlags.Substitution) { + return instantiateType((type).typeParameter, mapper); + } } return type; } @@ -9619,6 +9652,13 @@ namespace ts { if (target.flags & TypeFlags.StringOrNumberLiteral && target.flags & TypeFlags.FreshLiteral) { target = (target).regularType; } + if (source.flags & TypeFlags.Substitution) { + source = (source).substitute; + } + if (target.flags & TypeFlags.Substitution) { + target = (target).typeParameter; + } + // both types are the same - covers 'they are the same primitive type or both are Any' or the same type parameter cases if (source === target) return Ternary.True; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 5acee864e1bbc..f426370002bf1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3401,15 +3401,16 @@ namespace ts { Index = 1 << 19, // keyof T IndexedAccess = 1 << 20, // T[K] Conditional = 1 << 21, // T extends U ? X : Y + Substitution = 1 << 22, // Type parameter substitution /* @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 */ GenericMappedType = 1 << 29, // Flag used by maybeTypeOfKind @@ -3435,7 +3436,7 @@ namespace ts { UnionOrIntersection = Union | Intersection, StructuredType = Object | Union | Intersection, TypeVariable = TypeParameter | IndexedAccess, - InstantiableNonPrimitive = TypeVariable | Conditional, + InstantiableNonPrimitive = TypeVariable | Conditional | Substitution, InstantiablePrimitive = Index, Instantiable = InstantiableNonPrimitive | InstantiablePrimitive, StructuredOrInstantiable = StructuredType | Instantiable, @@ -3693,6 +3694,7 @@ namespace ts { type: InstantiableType | UnionOrIntersectionType; } + // T extends U ? X : Y (TypeFlags.Conditional) export interface ConditionalType extends InstantiableType { checkType: Type; extendsType: Type; @@ -3700,6 +3702,12 @@ namespace ts { falseType: Type; } + // Type parameter substitution (TypeFlags.Substitution) + export interface SubstitutionType extends InstantiableType { + typeParameter: TypeParameter; // Target type parameter + substitute: Type; // Type to substitute for type parameter + } + export const enum SignatureKind { Call, Construct, From 15baf0ead598d302f7dd501c1bbd94c0edbb1f70 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 15 Jan 2018 11:06:40 -0800 Subject: [PATCH 23/39] Accept new baselines --- .../reference/api/tsserverlibrary.d.ts | 17 +++++++++++------ tests/baselines/reference/api/typescript.d.ts | 17 +++++++++++------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 257c3339ea9d6..56c9805b1c604 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2021,7 +2021,8 @@ declare namespace ts { Index = 524288, IndexedAccess = 1048576, Conditional = 2097152, - NonPrimitive = 67108864, + Substitution = 4194304, + NonPrimitive = 134217728, Literal = 224, Unit = 13536, StringOrNumberLiteral = 96, @@ -2034,12 +2035,12 @@ declare namespace ts { UnionOrIntersection = 393216, StructuredType = 458752, TypeVariable = 1081344, - InstantiableNonPrimitive = 3178496, + InstantiableNonPrimitive = 7372800, InstantiablePrimitive = 524288, - Instantiable = 3702784, - StructuredOrInstantiable = 4161536, - Narrowable = 71272191, - NotUnionOrUnit = 67174913, + Instantiable = 7897088, + StructuredOrInstantiable = 8355840, + Narrowable = 142575359, + NotUnionOrUnit = 134283777, } type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression; interface Type { @@ -2145,6 +2146,10 @@ declare namespace ts { trueType: Type; falseType: Type; } + interface SubstitutionType extends InstantiableType { + typeParameter: TypeParameter; + substitute: Type; + } enum SignatureKind { Call = 0, Construct = 1, diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 2513867ef29e2..0c2bdcd88ee5d 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2021,7 +2021,8 @@ declare namespace ts { Index = 524288, IndexedAccess = 1048576, Conditional = 2097152, - NonPrimitive = 67108864, + Substitution = 4194304, + NonPrimitive = 134217728, Literal = 224, Unit = 13536, StringOrNumberLiteral = 96, @@ -2034,12 +2035,12 @@ declare namespace ts { UnionOrIntersection = 393216, StructuredType = 458752, TypeVariable = 1081344, - InstantiableNonPrimitive = 3178496, + InstantiableNonPrimitive = 7372800, InstantiablePrimitive = 524288, - Instantiable = 3702784, - StructuredOrInstantiable = 4161536, - Narrowable = 71272191, - NotUnionOrUnit = 67174913, + Instantiable = 7897088, + StructuredOrInstantiable = 8355840, + Narrowable = 142575359, + NotUnionOrUnit = 134283777, } type DestructuringPattern = BindingPattern | ObjectLiteralExpression | ArrayLiteralExpression; interface Type { @@ -2145,6 +2146,10 @@ declare namespace ts { trueType: Type; falseType: Type; } + interface SubstitutionType extends InstantiableType { + typeParameter: TypeParameter; + substitute: Type; + } enum SignatureKind { Call = 0, Construct = 1, From 9598acd47702e2e8dee9a43d696d88b2730a2c6b Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 15 Jan 2018 15:31:43 -0800 Subject: [PATCH 24/39] Properly handle 'any' and 'never' as conditional check type --- src/compiler/checker.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 41717d4f0f7a0..6abe6ad04b0e5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8415,6 +8415,10 @@ namespace ts { if (checkType.flags & TypeFlags.Union) { return getUnionType(map((checkType).types, t => getConditionalType(t, extendsType, mapper, trueType, falseType))); } + // Return union of trueType and falseType for any and never since they match anything + if (checkType.flags & (TypeFlags.Any | TypeFlags.Never)) { + return getUnionType([instantiateType(trueType, mapper), instantiateType(falseType, mapper)]); + } // Return trueType for a definitely true extends check if (isTypeAssignableTo(checkType, extendsType)) { return instantiateType(trueType, mapper); From e96ec8c2c7bb6ea85610c9462bf6b07ed8b4c7cc Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 16 Jan 2018 12:51:24 -0800 Subject: [PATCH 25/39] Erase substitution types in type references and type alias instantiations --- src/compiler/checker.ts | 10 ++++++++++ src/compiler/types.ts | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6abe6ad04b0e5..4f3a6225d88cc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7316,7 +7316,16 @@ namespace ts { return result & TypeFlags.PropagatingFlags; } + // This function replaces substitution types in the given array with their underlying type parameter. + // We do this when creating type references and type alias instantiations because subsitution types are + // no longer necessary once the type arguments have been validated against their corresponding type + // parameter constraints. + function eraseSubstitutionTypes(types: Type[]) { + return sameMap(types, t => t.flags & TypeFlags.Substitution ? (t).typeParameter : t); + } + function createTypeReference(target: GenericType, typeArguments: Type[]): TypeReference { + typeArguments = eraseSubstitutionTypes(typeArguments); const id = getTypeListId(typeArguments); let type = target.instantiations.get(id); if (!type) { @@ -7383,6 +7392,7 @@ namespace ts { } function getTypeAliasInstantiation(symbol: Symbol, typeArguments: Type[]): Type { + typeArguments = eraseSubstitutionTypes(typeArguments); const type = getDeclaredTypeOfSymbol(symbol); const links = getSymbolLinks(symbol); const typeParameters = links.typeParameters; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f426370002bf1..c544334b7ddbd 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3703,6 +3703,10 @@ namespace ts { } // Type parameter substitution (TypeFlags.Substitution) + // Substitution types are created for type parameter references that occur in the true branch + // of a conditional type. For example, in 'T extends string ? Foo : Bar', the reference to + // T in Foo is resolved as a substitution type that substitutes 'string & T' for T. Thus, if + // Foo has a 'string' constraint on its type parameter, T will satisfy it. export interface SubstitutionType extends InstantiableType { typeParameter: TypeParameter; // Target type parameter substitute: Type; // Type to substitute for type parameter From d52fa71f62dec04e3cdd3b5e4b9016adaf2ddae2 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 16 Jan 2018 12:51:46 -0800 Subject: [PATCH 26/39] Optimize the sameMap function --- src/compiler/core.ts | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index eb0696a1869e1..2d59e9f5dd77b 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -435,23 +435,21 @@ namespace ts { export function sameMap(array: T[], f: (x: T, i: number) => T): T[]; export function sameMap(array: ReadonlyArray, f: (x: T, i: number) => T): ReadonlyArray; export function sameMap(array: T[], f: (x: T, i: number) => T): T[] { - let result: T[]; if (array) { for (let i = 0; i < array.length; i++) { - if (result) { - result.push(f(array[i], i)); - } - else { - const item = array[i]; - const mapped = f(item, i); - if (item !== mapped) { - result = array.slice(0, i); - result.push(mapped); + const item = array[i]; + const mapped = f(item, i); + if (item !== mapped) { + const result = array.slice(0, i); + result.push(mapped); + for (i++; i < array.length; i++) { + result.push(f(array[i], i)); } + return result; } } } - return result || array; + return array; } /** From fd0dd6ed4c27fe5dd83fe78b2b3fb0edbe689606 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 18 Jan 2018 15:00:07 -0800 Subject: [PATCH 27/39] Separate code path for conditional type instantiation --- src/compiler/checker.ts | 88 +++++++++++++++++++++++++---------------- src/compiler/types.ts | 2 + 2 files changed, 56 insertions(+), 34 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0f9bb6d9cff88..2cd8e5e1e3dc4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6964,16 +6964,15 @@ namespace ts { return result & TypeFlags.PropagatingFlags; } - // This function replaces substitution types in the given array with their underlying type parameter. - // We do this when creating type references and type alias instantiations because subsitution types are - // no longer necessary once the type arguments have been validated against their corresponding type - // parameter constraints. - function eraseSubstitutionTypes(types: Type[]) { - return sameMap(types, t => t.flags & TypeFlags.Substitution ? (t).typeParameter : t); + // This function replaces substitution types with their underlying type parameters. We erase when creating + // type references and type alias instantiations because subsitution types are no longer necessary once + // the type arguments have been validated against their corresponding type parameter constraints. + function eraseSubstitutionType(type: Type) { + return type.flags & TypeFlags.Substitution ? (type).typeParameter : type } function createTypeReference(target: GenericType, typeArguments: Type[]): TypeReference { - typeArguments = eraseSubstitutionTypes(typeArguments); + typeArguments = sameMap(typeArguments, eraseSubstitutionType); const id = getTypeListId(typeArguments); let type = target.instantiations.get(id); if (!type) { @@ -7040,7 +7039,7 @@ namespace ts { } function getTypeAliasInstantiation(symbol: Symbol, typeArguments: Type[]): Type { - typeArguments = eraseSubstitutionTypes(typeArguments); + typeArguments = sameMap(typeArguments, eraseSubstitutionType); const type = getDeclaredTypeOfSymbol(symbol); const links = getSymbolLinks(symbol); const typeParameters = links.typeParameters; @@ -8083,52 +8082,47 @@ namespace ts { return links.resolvedType; } - function createConditionalType(checkType: Type, extendsType: Type, trueType: Type, falseType: Type, aliasSymbol: Symbol, aliasTypeArguments: Type[]) { + function createConditionalType(checkType: Type, extendsType: Type, trueType: Type, falseType: Type, target: ConditionalType, mapper: TypeMapper, aliasSymbol: Symbol, aliasTypeArguments: Type[]) { const type = createType(TypeFlags.Conditional); type.checkType = checkType; type.extendsType = extendsType; type.trueType = trueType; type.falseType = falseType; + type.target = target; + type.mapper = mapper; type.aliasSymbol = aliasSymbol; type.aliasTypeArguments = aliasTypeArguments; return type; } - function getConditionalType(checkType: Type, extendsType: Type, mapper: TypeMapper, trueType: Type, falseType: Type, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { + function getConditionalType(checkType: Type, extendsType: Type, trueType: Type, falseType: Type, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { // Distribute union types over conditional types if (checkType.flags & TypeFlags.Union) { - return getUnionType(map((checkType).types, t => getConditionalType(t, extendsType, mapper, trueType, falseType))); + return getUnionType(map((checkType).types, t => getConditionalType(t, extendsType, trueType, falseType))); } // Return union of trueType and falseType for any and never since they match anything if (checkType.flags & (TypeFlags.Any | TypeFlags.Never)) { - return getUnionType([instantiateType(trueType, mapper), instantiateType(falseType, mapper)]); + return getUnionType([trueType, falseType]); } // Return trueType for a definitely true extends check if (isTypeAssignableTo(checkType, extendsType)) { - return instantiateType(trueType, mapper); + return trueType; } // Return falseType for a definitely false extends check - if (!isTypeAssignableTo(instantiateType(checkType, anyMapper), instantiateType(extendsType, constraintMapper))) { - return instantiateType(falseType, mapper); - } - // Otherwise return a deferred conditional type - const resCheckType = checkType.flags & TypeFlags.Substitution ? (checkType).typeParameter : checkType; - const resTrueType = instantiateType(trueType, mapper); - const resFalseType = instantiateType(falseType, mapper); - const resTypeArguments = instantiateTypes(aliasTypeArguments, mapper); - const id = resCheckType.id + "," + extendsType.id + "," + resTrueType.id + "," + resFalseType.id; - let type = conditionalTypes.get(id); - if (!type) { - conditionalTypes.set(id, type = createConditionalType(resCheckType, extendsType, resTrueType, resFalseType, aliasSymbol, resTypeArguments)); + if (!typeMaybeAssignableTo(instantiateType(checkType, anyMapper), instantiateType(extendsType, constraintMapper))) { + return falseType; } - return type; + // Return a deferred type for a check that is neither definitely true nor definitely false + return createConditionalType(eraseSubstitutionType(checkType), extendsType, trueType, falseType, + /*target*/ undefined, /*mapper*/ undefined, aliasSymbol, aliasTypeArguments); } function getTypeFromConditionalTypeNode(node: ConditionalTypeNode): Type { const links = getNodeLinks(node); if (!links.resolvedType) { - links.resolvedType = getConditionalType(getTypeFromTypeNode(node.checkType), getTypeFromTypeNode(node.extendsType), - identityMapper, getTypeFromTypeNode(node.trueType), getTypeFromTypeNode(node.falseType), + links.resolvedType = getConditionalType( + getTypeFromTypeNode(node.checkType), getTypeFromTypeNode(node.extendsType), + getTypeFromTypeNode(node.trueType), getTypeFromTypeNode(node.falseType), getAliasSymbolForTypeNode(node), getAliasTypeArgumentsForTypeNode(node)); } return links.resolvedType; @@ -8699,22 +8693,48 @@ namespace ts { } function getConditionalTypeInstantiation(type: ConditionalType, mapper: TypeMapper): Type { + const target = type.target || type; + const combinedMapper = type.mapper ? combineTypeMappers(type.mapper, mapper) : mapper; // Check if we have a conditional type of the form T extends U ? X : Y, where T is a type parameter. // If so, the conditional type is distributive over a union type and when T is instantiated to a union // type A | B, we produce (A extends U ? X : Y) | (B extends U ? X : Y). - const checkType = type.checkType; + const checkType = target.checkType; if (checkType.flags & TypeFlags.TypeParameter) { - const instantiatedType = mapper(checkType); + const instantiatedType = combinedMapper(checkType); if (checkType !== instantiatedType && instantiatedType.flags & TypeFlags.Union) { - return mapType(instantiatedType, t => instantiateConditionalType(type, createReplacementMapper(checkType, t, mapper))); + return mapType(instantiatedType, t => instantiateConditionalType(target, createReplacementMapper(checkType, t, combinedMapper))); } } - return instantiateConditionalType(type, mapper); + return instantiateConditionalType(target, combinedMapper); } function instantiateConditionalType(type: ConditionalType, mapper: TypeMapper): Type { - return getConditionalType(instantiateType(type.checkType, mapper), instantiateType(type.extendsType, mapper), - mapper, type.trueType, type.falseType, type.aliasSymbol, type.aliasTypeArguments); + const checkType = instantiateType(type.checkType, mapper); + // Return union of trueType and falseType for any and never since they match anything + if (checkType.flags & (TypeFlags.Any | TypeFlags.Never)) { + return getUnionType([instantiateType(type.trueType, mapper), instantiateType(type.falseType, mapper)]); + } + const extendsType = instantiateType(type.extendsType, mapper); + // Return trueType for a definitely true extends check + if (isTypeAssignableTo(checkType, extendsType)) { + return instantiateType(type.trueType, mapper); + } + // Return falseType for a definitely false extends check + if (!typeMaybeAssignableTo(instantiateType(checkType, anyMapper), instantiateType(extendsType, constraintMapper))) { + return instantiateType(type.falseType, mapper); + } + // Return a deferred type for a check that is neither definitely true nor definitely false + const erasedCheckType = eraseSubstitutionType(checkType); + const trueType = instantiateType(type.trueType, mapper); + const falseType = instantiateType(type.falseType, mapper); + const id = type.id + "," + erasedCheckType.id + "," + extendsType.id + "," + trueType.id + "," + falseType.id; + let result = conditionalTypes.get(id); + if (!result) { + result = createConditionalType(erasedCheckType, extendsType, trueType, falseType, + type, mapper, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)); + conditionalTypes.set(id, result); + } + return result; } function instantiateType(type: Type, mapper: TypeMapper): Type { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index d32176d7be966..3b00e81456f03 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3794,6 +3794,8 @@ namespace ts { extendsType: Type; trueType: Type; falseType: Type; + target?: ConditionalType; + mapper?: TypeMapper; } // Type parameter substitution (TypeFlags.Substitution) From c360c24b9b6e054f3bb4dd5cced7b1d161fd5d1a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 19 Jan 2018 13:01:27 -0800 Subject: [PATCH 28/39] Fix parsing --- src/compiler/parser.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index ed286891dedcd..3e0898b366049 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2887,11 +2887,11 @@ namespace ts { if (parseOptional(SyntaxKind.ExtendsKeyword)) { const node = createNode(SyntaxKind.ConditionalType, type.pos); node.checkType = type; - node.extendsType = parseUnionTypeOrHigher(); + node.extendsType = parseType(); parseExpected(SyntaxKind.QuestionToken); - node.trueType = parseConditionalTypeOrHigher(); + node.trueType = parseType(); parseExpected(SyntaxKind.ColonToken); - node.falseType = parseConditionalTypeOrHigher(); + node.falseType = parseType(); return finishNode(node); } return type; From 0e73240ea41e2c8bd46f6580579f599e8e6f3b34 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 19 Jan 2018 14:44:48 -0800 Subject: [PATCH 29/39] Disallow conditional type following 'extends' --- src/compiler/parser.ts | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 3e0898b366049..733bcd02040e1 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2882,21 +2882,6 @@ namespace ts { return parseUnionOrIntersectionType(SyntaxKind.UnionType, parseIntersectionTypeOrHigher, SyntaxKind.BarToken); } - function parseConditionalTypeOrHigher(): TypeNode { - const type = parseUnionTypeOrHigher(); - if (parseOptional(SyntaxKind.ExtendsKeyword)) { - const node = createNode(SyntaxKind.ConditionalType, type.pos); - node.checkType = type; - node.extendsType = parseType(); - parseExpected(SyntaxKind.QuestionToken); - node.trueType = parseType(); - parseExpected(SyntaxKind.ColonToken); - node.falseType = parseType(); - return finishNode(node); - } - return type; - } - function isStartOfFunctionType(): boolean { if (token() === SyntaxKind.LessThanToken) { return true; @@ -2979,14 +2964,26 @@ namespace ts { return doOutsideOfContext(NodeFlags.TypeExcludesFlags, parseTypeWorker); } - function parseTypeWorker(): TypeNode { + function parseTypeWorker(noConditionalTypes?: boolean): TypeNode { if (isStartOfFunctionType()) { return parseFunctionOrConstructorType(SyntaxKind.FunctionType); } if (token() === SyntaxKind.NewKeyword) { return parseFunctionOrConstructorType(SyntaxKind.ConstructorType); } - return parseConditionalTypeOrHigher(); + const type = parseUnionTypeOrHigher(); + if (!noConditionalTypes && parseOptional(SyntaxKind.ExtendsKeyword)) { + const node = createNode(SyntaxKind.ConditionalType, type.pos); + node.checkType = type; + // The type following 'extends' is not permitted to be another conditional type + node.extendsType = parseTypeWorker(/*noConditionalTypes*/ true); + parseExpected(SyntaxKind.QuestionToken); + node.trueType = parseTypeWorker(); + parseExpected(SyntaxKind.ColonToken); + node.falseType = parseTypeWorker(); + return finishNode(node); + } + return type; } function parseTypeAnnotation(): TypeNode { From 5204fd5c5f7b881ee12d4632d893ede2e96c40a3 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 19 Jan 2018 17:06:09 -0800 Subject: [PATCH 30/39] Add T is related to { [P in xxx]: T[P] } type relationship --- src/compiler/checker.ts | 22 +++++++++++++++------- src/compiler/types.ts | 2 ++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2cd8e5e1e3dc4..d0fe701760dee 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6968,7 +6968,7 @@ namespace ts { // type references and type alias instantiations because subsitution types are no longer necessary once // the type arguments have been validated against their corresponding type parameter constraints. function eraseSubstitutionType(type: Type) { - return type.flags & TypeFlags.Substitution ? (type).typeParameter : type + return type.flags & TypeFlags.Substitution ? (type).typeParameter : type; } function createTypeReference(target: GenericType, typeArguments: Type[]): TypeReference { @@ -9821,13 +9821,21 @@ namespace ts { } } } - else if (isGenericMappedType(target) && !isGenericMappedType(source) && getConstraintTypeFromMappedType(target) === getIndexType(source)) { + else if (isGenericMappedType(target)) { + // A source type T is related to a target type { [P in X]: T[P] } + const template = getTemplateTypeFromMappedType(target); + if (template.flags & TypeFlags.IndexedAccess && (template).objectType === source && + (template).indexType === getTypeParameterFromMappedType(target)) { + return Ternary.True; + } // A source type T is related to a target type { [P in keyof T]: X } if T[P] is related to X. - const indexedAccessType = getIndexedAccessType(source, getTypeParameterFromMappedType(target)); - const templateType = getTemplateTypeFromMappedType(target); - if (result = isRelatedTo(indexedAccessType, templateType, reportErrors)) { - errorInfo = saveErrorInfo; - return result; + if (!isGenericMappedType(source) && getConstraintTypeFromMappedType(target) === getIndexType(source)) { + const indexedAccessType = getIndexedAccessType(source, getTypeParameterFromMappedType(target)); + const templateType = getTemplateTypeFromMappedType(target); + if (result = isRelatedTo(indexedAccessType, templateType, reportErrors)) { + errorInfo = saveErrorInfo; + return result; + } } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 3b00e81456f03..b9f3638724355 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3794,7 +3794,9 @@ namespace ts { extendsType: Type; trueType: Type; falseType: Type; + /* @internal */ target?: ConditionalType; + /* @internal */ mapper?: TypeMapper; } From eb314d00fc92aaf0374192475bde1bdeb7502266 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 20 Jan 2018 08:17:59 -0800 Subject: [PATCH 31/39] Add tests --- .../types/conditional/conditionalTypes1.ts | 198 ++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 tests/cases/conformance/types/conditional/conditionalTypes1.ts diff --git a/tests/cases/conformance/types/conditional/conditionalTypes1.ts b/tests/cases/conformance/types/conditional/conditionalTypes1.ts new file mode 100644 index 0000000000000..d882b4c8bf305 --- /dev/null +++ b/tests/cases/conformance/types/conditional/conditionalTypes1.ts @@ -0,0 +1,198 @@ +// @strict: true +// @declaration: true + +type Diff = T extends U ? never : T; +type Filter = T extends U ? T : never; +type NonNullable = Diff; + +type T00 = Diff<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "b" | "d" +type T01 = Filter<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "a" | "c" + +type T02 = Diff void), Function>; // string | number +type T03 = Filter void), Function>; // () => void + +type T04 = NonNullable; // string | number +type T05 = NonNullable<(() => string) | string[] | null | undefined>; // (() => string) | string[] + +function f1(x: T, y: NonNullable) { + x = y; + y = x; // Error +} + +function f2(x: T, y: NonNullable) { + x = y; + y = x; // Error + let s1: string = x; // Error + let s2: string = y; +} + +function f3(x: Partial[keyof T], y: NonNullable[keyof T]>) { + x = y; + y = x; // Error +} + +type Options = { k: "a", a: number } | { k: "b", b: string } | { k: "c", c: boolean }; + +type T10 = Diff; // { k: "c", c: boolean } +type T11 = Filter; // { k: "a", a: number } | { k: "b", b: string } + +type T12 = Diff; // { k: "c", c: boolean } +type T13 = Filter; // { k: "a", a: number } | { k: "b", b: string } + +type T14 = Diff; // Options +type T15 = Filter; // never + +declare function f4(p: K): Filter; +let x0 = f4("a"); // { k: "a", a: number } + +type OptionsOfKind = Filter; + +type T16 = OptionsOfKind<"a" | "b">; // { k: "a", a: number } | { k: "b", b: string } + +type Select = Filter; + +type T17 = Select; // // { k: "a", a: number } | { k: "b", b: string } + +type TypeName = + T extends string ? "string" : + T extends number ? "number" : + T extends boolean ? "boolean" : + T extends undefined ? "undefined" : + T extends Function ? "function" : + "object"; + +type T20 = TypeName void)>; // "string" | "function" +type T21 = TypeName; // "string" | "number" | "boolean" | "undefined" | "function" | "object" +type T22 = TypeName; // "string" | "number" | "boolean" | "undefined" | "function" | "object" +type T23 = TypeName<{}>; // "object" + +type KnockoutObservable = { object: T }; +type KnockoutObservableArray = { array: T }; + +type KnockedOut = T extends any[] ? KnockoutObservableArray : KnockoutObservable; + +type KnockedOutObj = { + [P in keyof T]: KnockedOut; +} + +interface Item { + id: number; + name: string; + subitems: string[]; +} + +type KOItem = KnockedOutObj; + +interface Part { + id: number; + name: string; + subparts: Part[]; + updatePart(newName: string): void; +} + +type FunctionPropertyNames = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T]; +type FunctionProperties = Pick>; + +type NonFunctionPropertyNames = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T]; +type NonFunctionProperties = Pick>; + +type T30 = FunctionProperties; +type T31 = NonFunctionProperties; + +function f7(x: T, y: FunctionProperties, z: NonFunctionProperties) { + x = y; // Error + x = z; // Error + y = x; + y = z; // Error + z = x; + z = y; // Error +} + +function f8(x: keyof T, y: FunctionPropertyNames, z: NonFunctionPropertyNames) { + x = y; + x = z; + y = x; // Error + y = z; // Error + z = x; // Error + z = y; // Error +} + +type DeepReadonly = + T extends any[] ? DeepReadonlyArray : + T extends object ? DeepReadonlyObject : + T; + +interface DeepReadonlyArray extends ReadonlyArray> {} + +type DeepReadonlyObject = { + readonly [P in NonFunctionPropertyNames]: DeepReadonly; +}; + +function f10(part: DeepReadonly) { + let name: string = part.name; + let id: number = part.subparts[0].id; + part.id = part.id; // Error + part.subparts[0] = part.subparts[0]; // Error + part.subparts[0].id = part.subparts[0].id; // Error + part.updatePart("hello"); // Error +} + +type ZeroOf = T extends number ? 0 : T extends string ? "" : false; + +function zeroOf(value: T) { + return >(typeof value === "number" ? 0 : typeof value === "string" ? "" : false); +} + +function f20(n: number, b: boolean, x: number | boolean, y: T) { + zeroOf(5); // 0 + zeroOf("hello"); // "" + zeroOf(true); // false + zeroOf(n); // 0 + zeroOf(b); // False + zeroOf(x); // 0 | false + zeroOf(y); // ZeroOf +} + +function f21(x: T, y: ZeroOf) { + let z1: number | string = y; + let z2: 0 | "" = y; + x = y; // Error + y = x; // Error +} + +type Extends = T extends U ? true : false; +type If = C extends true ? T : F; +type Not = If; +type And = If; +type Or = If; + +type isString = Extends; + +type Q1 = isString; // false +type Q2 = isString<"abc">; // true +type Q3 = isString; // boolean +type Q4 = isString; // boolean + +type N1 = Not; // true +type N2 = Not; // false +type N3 = Not; // boolean + +type A1 = And; // false +type A2 = And; // false +type A3 = And; // false +type A4 = And; // true +type A5 = And; // false +type A6 = And; // false +type A7 = And; // boolean +type A8 = And; // boolean +type A9 = And; // boolean + +type O1 = Or; // false +type O2 = Or; // true +type O3 = Or; // true +type O4 = Or; // true +type O5 = Or; // boolean +type O6 = Or; // boolean +type O7 = Or; // true +type O8 = Or; // true +type O9 = Or; // boolean From cdd50d4d9674788653fcef2529979330f35a784c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 20 Jan 2018 08:18:08 -0800 Subject: [PATCH 32/39] Accept new baselines --- .../reference/conditionalTypes1.errors.txt | 337 +++++++ .../baselines/reference/conditionalTypes1.js | 400 ++++++++ .../reference/conditionalTypes1.symbols | 753 ++++++++++++++++ .../reference/conditionalTypes1.types | 851 ++++++++++++++++++ 4 files changed, 2341 insertions(+) create mode 100644 tests/baselines/reference/conditionalTypes1.errors.txt create mode 100644 tests/baselines/reference/conditionalTypes1.js create mode 100644 tests/baselines/reference/conditionalTypes1.symbols create mode 100644 tests/baselines/reference/conditionalTypes1.types diff --git a/tests/baselines/reference/conditionalTypes1.errors.txt b/tests/baselines/reference/conditionalTypes1.errors.txt new file mode 100644 index 0000000000000..900925052acdf --- /dev/null +++ b/tests/baselines/reference/conditionalTypes1.errors.txt @@ -0,0 +1,337 @@ +tests/cases/conformance/types/conditional/conditionalTypes1.ts(16,5): error TS2322: Type 'T' is not assignable to type 'Diff'. +tests/cases/conformance/types/conditional/conditionalTypes1.ts(21,5): error TS2322: Type 'T' is not assignable to type 'Diff'. + Type 'string | undefined' is not assignable to type 'Diff'. + Type 'undefined' is not assignable to type 'Diff'. +tests/cases/conformance/types/conditional/conditionalTypes1.ts(22,9): error TS2322: Type 'T' is not assignable to type 'string'. + Type 'string | undefined' is not assignable to type 'string'. + Type 'undefined' is not assignable to type 'string'. +tests/cases/conformance/types/conditional/conditionalTypes1.ts(28,5): error TS2322: Type 'Partial[keyof T]' is not assignable to type 'Diff[keyof T], null | undefined>'. + Type 'T[keyof T] | undefined' is not assignable to type 'Diff[keyof T], null | undefined>'. + Type 'undefined' is not assignable to type 'Diff[keyof T], null | undefined>'. +tests/cases/conformance/types/conditional/conditionalTypes1.ts(100,5): error TS2322: Type 'Pick' is not assignable to type 'T'. +tests/cases/conformance/types/conditional/conditionalTypes1.ts(101,5): error TS2322: Type 'Pick' is not assignable to type 'T'. +tests/cases/conformance/types/conditional/conditionalTypes1.ts(103,5): error TS2322: Type 'Pick' is not assignable to type 'Pick'. + Type '{ [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]'. + Type 'T[keyof T] extends Function ? keyof T : never' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]'. + Type 'keyof T' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]'. + Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. + Type 'T[keyof T] extends Function ? keyof T : never' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. + Type '{ [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. + Type 'T[keyof T] extends Function ? keyof T : never' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. + Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. +tests/cases/conformance/types/conditional/conditionalTypes1.ts(105,5): error TS2322: Type 'Pick' is not assignable to type 'Pick'. + Type '{ [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]'. + Type 'T[keyof T] extends Function ? never : keyof T' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]'. + Type 'keyof T' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]'. + Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. + Type 'T[keyof T] extends Function ? never : keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. + Type '{ [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. + Type 'T[keyof T] extends Function ? never : keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. + Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. +tests/cases/conformance/types/conditional/conditionalTypes1.ts(111,5): error TS2322: Type 'keyof T' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]'. + Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. +tests/cases/conformance/types/conditional/conditionalTypes1.ts(112,5): error TS2322: Type '{ [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]'. + Type 'T[keyof T] extends Function ? never : keyof T' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]'. + Type 'keyof T' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]'. + Type 'T[keyof T] extends Function ? never : keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. + Type '{ [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. + Type 'T[keyof T] extends Function ? never : keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. + Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. +tests/cases/conformance/types/conditional/conditionalTypes1.ts(113,5): error TS2322: Type 'keyof T' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]'. + Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. +tests/cases/conformance/types/conditional/conditionalTypes1.ts(114,5): error TS2322: Type '{ [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]'. + Type 'T[keyof T] extends Function ? keyof T : never' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]'. + Type 'keyof T' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]'. + Type 'T[keyof T] extends Function ? keyof T : never' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. + Type '{ [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. + Type 'T[keyof T] extends Function ? keyof T : never' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. + Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. +tests/cases/conformance/types/conditional/conditionalTypes1.ts(131,10): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property. +tests/cases/conformance/types/conditional/conditionalTypes1.ts(132,5): error TS2542: Index signature in type 'DeepReadonlyArray' only permits reading. +tests/cases/conformance/types/conditional/conditionalTypes1.ts(133,22): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property. +tests/cases/conformance/types/conditional/conditionalTypes1.ts(134,10): error TS2339: Property 'updatePart' does not exist on type 'DeepReadonlyObject'. +tests/cases/conformance/types/conditional/conditionalTypes1.ts(156,5): error TS2322: Type 'ZeroOf' is not assignable to type 'T'. + Type '0 | (T extends string ? "" : false)' is not assignable to type 'T'. + Type '0' is not assignable to type 'T'. + Type '"" | 0' is not assignable to type 'T'. + Type '""' is not assignable to type 'T'. +tests/cases/conformance/types/conditional/conditionalTypes1.ts(157,5): error TS2322: Type 'T' is not assignable to type 'ZeroOf'. + Type 'string | number' is not assignable to type 'ZeroOf'. + Type 'string' is not assignable to type 'ZeroOf'. + + +==== tests/cases/conformance/types/conditional/conditionalTypes1.ts (18 errors) ==== + type Diff = T extends U ? never : T; + type Filter = T extends U ? T : never; + type NonNullable = Diff; + + type T00 = Diff<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "b" | "d" + type T01 = Filter<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "a" | "c" + + type T02 = Diff void), Function>; // string | number + type T03 = Filter void), Function>; // () => void + + type T04 = NonNullable; // string | number + type T05 = NonNullable<(() => string) | string[] | null | undefined>; // (() => string) | string[] + + function f1(x: T, y: NonNullable) { + x = y; + y = x; // Error + ~ +!!! error TS2322: Type 'T' is not assignable to type 'Diff'. + } + + function f2(x: T, y: NonNullable) { + x = y; + y = x; // Error + ~ +!!! error TS2322: Type 'T' is not assignable to type 'Diff'. +!!! error TS2322: Type 'string | undefined' is not assignable to type 'Diff'. +!!! error TS2322: Type 'undefined' is not assignable to type 'Diff'. + let s1: string = x; // Error + ~~ +!!! error TS2322: Type 'T' is not assignable to type 'string'. +!!! error TS2322: Type 'string | undefined' is not assignable to type 'string'. +!!! error TS2322: Type 'undefined' is not assignable to type 'string'. + let s2: string = y; + } + + function f3(x: Partial[keyof T], y: NonNullable[keyof T]>) { + x = y; + y = x; // Error + ~ +!!! error TS2322: Type 'Partial[keyof T]' is not assignable to type 'Diff[keyof T], null | undefined>'. +!!! error TS2322: Type 'T[keyof T] | undefined' is not assignable to type 'Diff[keyof T], null | undefined>'. +!!! error TS2322: Type 'undefined' is not assignable to type 'Diff[keyof T], null | undefined>'. + } + + type Options = { k: "a", a: number } | { k: "b", b: string } | { k: "c", c: boolean }; + + type T10 = Diff; // { k: "c", c: boolean } + type T11 = Filter; // { k: "a", a: number } | { k: "b", b: string } + + type T12 = Diff; // { k: "c", c: boolean } + type T13 = Filter; // { k: "a", a: number } | { k: "b", b: string } + + type T14 = Diff; // Options + type T15 = Filter; // never + + declare function f4(p: K): Filter; + let x0 = f4("a"); // { k: "a", a: number } + + type OptionsOfKind = Filter; + + type T16 = OptionsOfKind<"a" | "b">; // { k: "a", a: number } | { k: "b", b: string } + + type Select = Filter; + + type T17 = Select; // // { k: "a", a: number } | { k: "b", b: string } + + type TypeName = + T extends string ? "string" : + T extends number ? "number" : + T extends boolean ? "boolean" : + T extends undefined ? "undefined" : + T extends Function ? "function" : + "object"; + + type T20 = TypeName void)>; // "string" | "function" + type T21 = TypeName; // "string" | "number" | "boolean" | "undefined" | "function" | "object" + type T22 = TypeName; // "string" | "number" | "boolean" | "undefined" | "function" | "object" + type T23 = TypeName<{}>; // "object" + + type KnockoutObservable = { object: T }; + type KnockoutObservableArray = { array: T }; + + type KnockedOut = T extends any[] ? KnockoutObservableArray : KnockoutObservable; + + type KnockedOutObj = { + [P in keyof T]: KnockedOut; + } + + interface Item { + id: number; + name: string; + subitems: string[]; + } + + type KOItem = KnockedOutObj; + + interface Part { + id: number; + name: string; + subparts: Part[]; + updatePart(newName: string): void; + } + + type FunctionPropertyNames = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T]; + type FunctionProperties = Pick>; + + type NonFunctionPropertyNames = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T]; + type NonFunctionProperties = Pick>; + + type T30 = FunctionProperties; + type T31 = NonFunctionProperties; + + function f7(x: T, y: FunctionProperties, z: NonFunctionProperties) { + x = y; // Error + ~ +!!! error TS2322: Type 'Pick' is not assignable to type 'T'. + x = z; // Error + ~ +!!! error TS2322: Type 'Pick' is not assignable to type 'T'. + y = x; + y = z; // Error + ~ +!!! error TS2322: Type 'Pick' is not assignable to type 'Pick'. +!!! error TS2322: Type '{ [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]'. +!!! error TS2322: Type 'T[keyof T] extends Function ? keyof T : never' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]'. +!!! error TS2322: Type 'keyof T' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]'. +!!! error TS2322: Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. +!!! error TS2322: Type 'T[keyof T] extends Function ? keyof T : never' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. +!!! error TS2322: Type '{ [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. +!!! error TS2322: Type 'T[keyof T] extends Function ? keyof T : never' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. +!!! error TS2322: Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. + z = x; + z = y; // Error + ~ +!!! error TS2322: Type 'Pick' is not assignable to type 'Pick'. +!!! error TS2322: Type '{ [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]'. +!!! error TS2322: Type 'T[keyof T] extends Function ? never : keyof T' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]'. +!!! error TS2322: Type 'keyof T' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]'. +!!! error TS2322: Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. +!!! error TS2322: Type 'T[keyof T] extends Function ? never : keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. +!!! error TS2322: Type '{ [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. +!!! error TS2322: Type 'T[keyof T] extends Function ? never : keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. +!!! error TS2322: Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. + } + + function f8(x: keyof T, y: FunctionPropertyNames, z: NonFunctionPropertyNames) { + x = y; + x = z; + y = x; // Error + ~ +!!! error TS2322: Type 'keyof T' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]'. +!!! error TS2322: Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. + y = z; // Error + ~ +!!! error TS2322: Type '{ [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]'. +!!! error TS2322: Type 'T[keyof T] extends Function ? never : keyof T' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]'. +!!! error TS2322: Type 'keyof T' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]'. +!!! error TS2322: Type 'T[keyof T] extends Function ? never : keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. +!!! error TS2322: Type '{ [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. +!!! error TS2322: Type 'T[keyof T] extends Function ? never : keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. +!!! error TS2322: Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'. + z = x; // Error + ~ +!!! error TS2322: Type 'keyof T' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]'. +!!! error TS2322: Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. + z = y; // Error + ~ +!!! error TS2322: Type '{ [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]'. +!!! error TS2322: Type 'T[keyof T] extends Function ? keyof T : never' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]'. +!!! error TS2322: Type 'keyof T' is not assignable to type '{ [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]'. +!!! error TS2322: Type 'T[keyof T] extends Function ? keyof T : never' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. +!!! error TS2322: Type '{ [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. +!!! error TS2322: Type 'T[keyof T] extends Function ? keyof T : never' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. +!!! error TS2322: Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'. + } + + type DeepReadonly = + T extends any[] ? DeepReadonlyArray : + T extends object ? DeepReadonlyObject : + T; + + interface DeepReadonlyArray extends ReadonlyArray> {} + + type DeepReadonlyObject = { + readonly [P in NonFunctionPropertyNames]: DeepReadonly; + }; + + function f10(part: DeepReadonly) { + let name: string = part.name; + let id: number = part.subparts[0].id; + part.id = part.id; // Error + ~~ +!!! error TS2540: Cannot assign to 'id' because it is a constant or a read-only property. + part.subparts[0] = part.subparts[0]; // Error + ~~~~~~~~~~~~~~~~ +!!! error TS2542: Index signature in type 'DeepReadonlyArray' only permits reading. + part.subparts[0].id = part.subparts[0].id; // Error + ~~ +!!! error TS2540: Cannot assign to 'id' because it is a constant or a read-only property. + part.updatePart("hello"); // Error + ~~~~~~~~~~ +!!! error TS2339: Property 'updatePart' does not exist on type 'DeepReadonlyObject'. + } + + type ZeroOf = T extends number ? 0 : T extends string ? "" : false; + + function zeroOf(value: T) { + return >(typeof value === "number" ? 0 : typeof value === "string" ? "" : false); + } + + function f20(n: number, b: boolean, x: number | boolean, y: T) { + zeroOf(5); // 0 + zeroOf("hello"); // "" + zeroOf(true); // false + zeroOf(n); // 0 + zeroOf(b); // False + zeroOf(x); // 0 | false + zeroOf(y); // ZeroOf + } + + function f21(x: T, y: ZeroOf) { + let z1: number | string = y; + let z2: 0 | "" = y; + x = y; // Error + ~ +!!! error TS2322: Type 'ZeroOf' is not assignable to type 'T'. +!!! error TS2322: Type '0 | (T extends string ? "" : false)' is not assignable to type 'T'. +!!! error TS2322: Type '0' is not assignable to type 'T'. +!!! error TS2322: Type '"" | 0' is not assignable to type 'T'. +!!! error TS2322: Type '""' is not assignable to type 'T'. + y = x; // Error + ~ +!!! error TS2322: Type 'T' is not assignable to type 'ZeroOf'. +!!! error TS2322: Type 'string | number' is not assignable to type 'ZeroOf'. +!!! error TS2322: Type 'string' is not assignable to type 'ZeroOf'. + } + + type Extends = T extends U ? true : false; + type If = C extends true ? T : F; + type Not = If; + type And = If; + type Or = If; + + type isString = Extends; + + type Q1 = isString; // false + type Q2 = isString<"abc">; // true + type Q3 = isString; // boolean + type Q4 = isString; // boolean + + type N1 = Not; // true + type N2 = Not; // false + type N3 = Not; // boolean + + type A1 = And; // false + type A2 = And; // false + type A3 = And; // false + type A4 = And; // true + type A5 = And; // false + type A6 = And; // false + type A7 = And; // boolean + type A8 = And; // boolean + type A9 = And; // boolean + + type O1 = Or; // false + type O2 = Or; // true + type O3 = Or; // true + type O4 = Or; // true + type O5 = Or; // boolean + type O6 = Or; // boolean + type O7 = Or; // true + type O8 = Or; // true + type O9 = Or; // boolean + \ No newline at end of file diff --git a/tests/baselines/reference/conditionalTypes1.js b/tests/baselines/reference/conditionalTypes1.js new file mode 100644 index 0000000000000..54241bb553aa5 --- /dev/null +++ b/tests/baselines/reference/conditionalTypes1.js @@ -0,0 +1,400 @@ +//// [conditionalTypes1.ts] +type Diff = T extends U ? never : T; +type Filter = T extends U ? T : never; +type NonNullable = Diff; + +type T00 = Diff<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "b" | "d" +type T01 = Filter<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "a" | "c" + +type T02 = Diff void), Function>; // string | number +type T03 = Filter void), Function>; // () => void + +type T04 = NonNullable; // string | number +type T05 = NonNullable<(() => string) | string[] | null | undefined>; // (() => string) | string[] + +function f1(x: T, y: NonNullable) { + x = y; + y = x; // Error +} + +function f2(x: T, y: NonNullable) { + x = y; + y = x; // Error + let s1: string = x; // Error + let s2: string = y; +} + +function f3(x: Partial[keyof T], y: NonNullable[keyof T]>) { + x = y; + y = x; // Error +} + +type Options = { k: "a", a: number } | { k: "b", b: string } | { k: "c", c: boolean }; + +type T10 = Diff; // { k: "c", c: boolean } +type T11 = Filter; // { k: "a", a: number } | { k: "b", b: string } + +type T12 = Diff; // { k: "c", c: boolean } +type T13 = Filter; // { k: "a", a: number } | { k: "b", b: string } + +type T14 = Diff; // Options +type T15 = Filter; // never + +declare function f4(p: K): Filter; +let x0 = f4("a"); // { k: "a", a: number } + +type OptionsOfKind = Filter; + +type T16 = OptionsOfKind<"a" | "b">; // { k: "a", a: number } | { k: "b", b: string } + +type Select = Filter; + +type T17 = Select; // // { k: "a", a: number } | { k: "b", b: string } + +type TypeName = + T extends string ? "string" : + T extends number ? "number" : + T extends boolean ? "boolean" : + T extends undefined ? "undefined" : + T extends Function ? "function" : + "object"; + +type T20 = TypeName void)>; // "string" | "function" +type T21 = TypeName; // "string" | "number" | "boolean" | "undefined" | "function" | "object" +type T22 = TypeName; // "string" | "number" | "boolean" | "undefined" | "function" | "object" +type T23 = TypeName<{}>; // "object" + +type KnockoutObservable = { object: T }; +type KnockoutObservableArray = { array: T }; + +type KnockedOut = T extends any[] ? KnockoutObservableArray : KnockoutObservable; + +type KnockedOutObj = { + [P in keyof T]: KnockedOut; +} + +interface Item { + id: number; + name: string; + subitems: string[]; +} + +type KOItem = KnockedOutObj; + +interface Part { + id: number; + name: string; + subparts: Part[]; + updatePart(newName: string): void; +} + +type FunctionPropertyNames = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T]; +type FunctionProperties = Pick>; + +type NonFunctionPropertyNames = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T]; +type NonFunctionProperties = Pick>; + +type T30 = FunctionProperties; +type T31 = NonFunctionProperties; + +function f7(x: T, y: FunctionProperties, z: NonFunctionProperties) { + x = y; // Error + x = z; // Error + y = x; + y = z; // Error + z = x; + z = y; // Error +} + +function f8(x: keyof T, y: FunctionPropertyNames, z: NonFunctionPropertyNames) { + x = y; + x = z; + y = x; // Error + y = z; // Error + z = x; // Error + z = y; // Error +} + +type DeepReadonly = + T extends any[] ? DeepReadonlyArray : + T extends object ? DeepReadonlyObject : + T; + +interface DeepReadonlyArray extends ReadonlyArray> {} + +type DeepReadonlyObject = { + readonly [P in NonFunctionPropertyNames]: DeepReadonly; +}; + +function f10(part: DeepReadonly) { + let name: string = part.name; + let id: number = part.subparts[0].id; + part.id = part.id; // Error + part.subparts[0] = part.subparts[0]; // Error + part.subparts[0].id = part.subparts[0].id; // Error + part.updatePart("hello"); // Error +} + +type ZeroOf = T extends number ? 0 : T extends string ? "" : false; + +function zeroOf(value: T) { + return >(typeof value === "number" ? 0 : typeof value === "string" ? "" : false); +} + +function f20(n: number, b: boolean, x: number | boolean, y: T) { + zeroOf(5); // 0 + zeroOf("hello"); // "" + zeroOf(true); // false + zeroOf(n); // 0 + zeroOf(b); // False + zeroOf(x); // 0 | false + zeroOf(y); // ZeroOf +} + +function f21(x: T, y: ZeroOf) { + let z1: number | string = y; + let z2: 0 | "" = y; + x = y; // Error + y = x; // Error +} + +type Extends = T extends U ? true : false; +type If = C extends true ? T : F; +type Not = If; +type And = If; +type Or = If; + +type isString = Extends; + +type Q1 = isString; // false +type Q2 = isString<"abc">; // true +type Q3 = isString; // boolean +type Q4 = isString; // boolean + +type N1 = Not; // true +type N2 = Not; // false +type N3 = Not; // boolean + +type A1 = And; // false +type A2 = And; // false +type A3 = And; // false +type A4 = And; // true +type A5 = And; // false +type A6 = And; // false +type A7 = And; // boolean +type A8 = And; // boolean +type A9 = And; // boolean + +type O1 = Or; // false +type O2 = Or; // true +type O3 = Or; // true +type O4 = Or; // true +type O5 = Or; // boolean +type O6 = Or; // boolean +type O7 = Or; // true +type O8 = Or; // true +type O9 = Or; // boolean + + +//// [conditionalTypes1.js] +"use strict"; +function f1(x, y) { + x = y; + y = x; // Error +} +function f2(x, y) { + x = y; + y = x; // Error + var s1 = x; // Error + var s2 = y; +} +function f3(x, y) { + x = y; + y = x; // Error +} +var x0 = f4("a"); // { k: "a", a: number } +function f7(x, y, z) { + x = y; // Error + x = z; // Error + y = x; + y = z; // Error + z = x; + z = y; // Error +} +function f8(x, y, z) { + x = y; + x = z; + y = x; // Error + y = z; // Error + z = x; // Error + z = y; // Error +} +function f10(part) { + var name = part.name; + var id = part.subparts[0].id; + part.id = part.id; // Error + part.subparts[0] = part.subparts[0]; // Error + part.subparts[0].id = part.subparts[0].id; // Error + part.updatePart("hello"); // Error +} +function zeroOf(value) { + return (typeof value === "number" ? 0 : typeof value === "string" ? "" : false); +} +function f20(n, b, x, y) { + zeroOf(5); // 0 + zeroOf("hello"); // "" + zeroOf(true); // false + zeroOf(n); // 0 + zeroOf(b); // False + zeroOf(x); // 0 | false + zeroOf(y); // ZeroOf +} +function f21(x, y) { + var z1 = y; + var z2 = y; + x = y; // Error + y = x; // Error +} + + +//// [conditionalTypes1.d.ts] +declare type Diff = T extends U ? never : T; +declare type Filter = T extends U ? T : never; +declare type NonNullable = Diff; +declare type T00 = Diff<"a" | "b" | "c" | "d", "a" | "c" | "f">; +declare type T01 = Filter<"a" | "b" | "c" | "d", "a" | "c" | "f">; +declare type T02 = Diff void), Function>; +declare type T03 = Filter void), Function>; +declare type T04 = NonNullable; +declare type T05 = NonNullable<(() => string) | string[] | null | undefined>; +declare function f1(x: T, y: NonNullable): void; +declare function f2(x: T, y: NonNullable): void; +declare function f3(x: Partial[keyof T], y: NonNullable[keyof T]>): void; +declare type Options = { + k: "a"; + a: number; +} | { + k: "b"; + b: string; +} | { + k: "c"; + c: boolean; +}; +declare type T10 = Diff; +declare type T11 = Filter; +declare type T12 = Diff; +declare type T13 = Filter; +declare type T14 = Diff; +declare type T15 = Filter; +declare function f4(p: K): Filter; +declare let x0: { + k: "a"; + a: number; +}; +declare type OptionsOfKind = Filter; +declare type T16 = OptionsOfKind<"a" | "b">; +declare type Select = Filter; +declare type T17 = Select; +declare type TypeName = T extends string ? "string" : T extends number ? "number" : T extends boolean ? "boolean" : T extends undefined ? "undefined" : T extends Function ? "function" : "object"; +declare type T20 = TypeName void)>; +declare type T21 = TypeName; +declare type T22 = TypeName; +declare type T23 = TypeName<{}>; +declare type KnockoutObservable = { + object: T; +}; +declare type KnockoutObservableArray = { + array: T; +}; +declare type KnockedOut = T extends any[] ? KnockoutObservableArray : KnockoutObservable; +declare type KnockedOutObj = { + [P in keyof T]: KnockedOut; +}; +interface Item { + id: number; + name: string; + subitems: string[]; +} +declare type KOItem = KnockedOutObj; +interface Part { + id: number; + name: string; + subparts: Part[]; + updatePart(newName: string): void; +} +declare type FunctionPropertyNames = { + [K in keyof T]: T[K] extends Function ? K : never; +}[keyof T]; +declare type FunctionProperties = Pick>; +declare type NonFunctionPropertyNames = { + [K in keyof T]: T[K] extends Function ? never : K; +}[keyof T]; +declare type NonFunctionProperties = Pick>; +declare type T30 = FunctionProperties; +declare type T31 = NonFunctionProperties; +declare function f7(x: T, y: FunctionProperties, z: NonFunctionProperties): void; +declare function f8(x: keyof T, y: FunctionPropertyNames, z: NonFunctionPropertyNames): void; +declare type DeepReadonly = T extends any[] ? DeepReadonlyArray : T extends object ? DeepReadonlyObject : T; +interface DeepReadonlyArray extends ReadonlyArray> { +} +declare type DeepReadonlyObject = { + readonly [P in NonFunctionPropertyNames]: DeepReadonly; +}; +declare function f10(part: DeepReadonly): void; +declare type ZeroOf = T extends number ? 0 : T extends string ? "" : false; +declare function zeroOf(value: T): ZeroOf; +declare function f20(n: number, b: boolean, x: number | boolean, y: T): void; +declare function f21(x: T, y: ZeroOf): void; +declare type Extends = T extends U ? true : false; +declare type If = C extends true ? T : F; +declare type Not = If; +declare type And = If; +declare type Or = If; +declare type isString = Extends; +declare type Q1 = isString; +declare type Q2 = isString<"abc">; +declare type Q3 = isString; +declare type Q4 = isString; +declare type N1 = Not; +declare type N2 = Not; +declare type N3 = Not; +declare type A1 = And; +declare type A2 = And; +declare type A3 = And; +declare type A4 = And; +declare type A5 = And; +declare type A6 = And; +declare type A7 = And; +declare type A8 = And; +declare type A9 = And; +declare type O1 = Or; +declare type O2 = Or; +declare type O3 = Or; +declare type O4 = Or; +declare type O5 = Or; +declare type O6 = Or; +declare type O7 = Or; +declare type O8 = Or; +declare type O9 = Or; diff --git a/tests/baselines/reference/conditionalTypes1.symbols b/tests/baselines/reference/conditionalTypes1.symbols new file mode 100644 index 0000000000000..16322f4c1517c --- /dev/null +++ b/tests/baselines/reference/conditionalTypes1.symbols @@ -0,0 +1,753 @@ +=== tests/cases/conformance/types/conditional/conditionalTypes1.ts === +type Diff = T extends U ? never : T; +>Diff : Symbol(Diff, Decl(conditionalTypes1.ts, 0, 0)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 0, 10)) +>U : Symbol(U, Decl(conditionalTypes1.ts, 0, 12)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 0, 10)) +>U : Symbol(U, Decl(conditionalTypes1.ts, 0, 12)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 0, 10)) + +type Filter = T extends U ? T : never; +>Filter : Symbol(Filter, Decl(conditionalTypes1.ts, 0, 42)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 1, 12)) +>U : Symbol(U, Decl(conditionalTypes1.ts, 1, 14)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 1, 12)) +>U : Symbol(U, Decl(conditionalTypes1.ts, 1, 14)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 1, 12)) + +type NonNullable = Diff; +>NonNullable : Symbol(NonNullable, Decl(conditionalTypes1.ts, 1, 44)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 2, 17)) +>Diff : Symbol(Diff, Decl(conditionalTypes1.ts, 0, 0)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 2, 17)) + +type T00 = Diff<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "b" | "d" +>T00 : Symbol(T00, Decl(conditionalTypes1.ts, 2, 48)) +>Diff : Symbol(Diff, Decl(conditionalTypes1.ts, 0, 0)) + +type T01 = Filter<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "a" | "c" +>T01 : Symbol(T01, Decl(conditionalTypes1.ts, 4, 56)) +>Filter : Symbol(Filter, Decl(conditionalTypes1.ts, 0, 42)) + +type T02 = Diff void), Function>; // string | number +>T02 : Symbol(T02, Decl(conditionalTypes1.ts, 5, 58)) +>Diff : Symbol(Diff, Decl(conditionalTypes1.ts, 0, 0)) +>Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +type T03 = Filter void), Function>; // () => void +>T03 : Symbol(T03, Decl(conditionalTypes1.ts, 7, 58)) +>Filter : Symbol(Filter, Decl(conditionalTypes1.ts, 0, 42)) +>Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +type T04 = NonNullable; // string | number +>T04 : Symbol(T04, Decl(conditionalTypes1.ts, 8, 60)) +>NonNullable : Symbol(NonNullable, Decl(conditionalTypes1.ts, 1, 44)) + +type T05 = NonNullable<(() => string) | string[] | null | undefined>; // (() => string) | string[] +>T05 : Symbol(T05, Decl(conditionalTypes1.ts, 10, 52)) +>NonNullable : Symbol(NonNullable, Decl(conditionalTypes1.ts, 1, 44)) + +function f1(x: T, y: NonNullable) { +>f1 : Symbol(f1, Decl(conditionalTypes1.ts, 11, 69)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 13, 12)) +>x : Symbol(x, Decl(conditionalTypes1.ts, 13, 15)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 13, 12)) +>y : Symbol(y, Decl(conditionalTypes1.ts, 13, 20)) +>NonNullable : Symbol(NonNullable, Decl(conditionalTypes1.ts, 1, 44)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 13, 12)) + + x = y; +>x : Symbol(x, Decl(conditionalTypes1.ts, 13, 15)) +>y : Symbol(y, Decl(conditionalTypes1.ts, 13, 20)) + + y = x; // Error +>y : Symbol(y, Decl(conditionalTypes1.ts, 13, 20)) +>x : Symbol(x, Decl(conditionalTypes1.ts, 13, 15)) +} + +function f2(x: T, y: NonNullable) { +>f2 : Symbol(f2, Decl(conditionalTypes1.ts, 16, 1)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 18, 12)) +>x : Symbol(x, Decl(conditionalTypes1.ts, 18, 42)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 18, 12)) +>y : Symbol(y, Decl(conditionalTypes1.ts, 18, 47)) +>NonNullable : Symbol(NonNullable, Decl(conditionalTypes1.ts, 1, 44)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 18, 12)) + + x = y; +>x : Symbol(x, Decl(conditionalTypes1.ts, 18, 42)) +>y : Symbol(y, Decl(conditionalTypes1.ts, 18, 47)) + + y = x; // Error +>y : Symbol(y, Decl(conditionalTypes1.ts, 18, 47)) +>x : Symbol(x, Decl(conditionalTypes1.ts, 18, 42)) + + let s1: string = x; // Error +>s1 : Symbol(s1, Decl(conditionalTypes1.ts, 21, 7)) +>x : Symbol(x, Decl(conditionalTypes1.ts, 18, 42)) + + let s2: string = y; +>s2 : Symbol(s2, Decl(conditionalTypes1.ts, 22, 7)) +>y : Symbol(y, Decl(conditionalTypes1.ts, 18, 47)) +} + +function f3(x: Partial[keyof T], y: NonNullable[keyof T]>) { +>f3 : Symbol(f3, Decl(conditionalTypes1.ts, 23, 1)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 25, 12)) +>x : Symbol(x, Decl(conditionalTypes1.ts, 25, 15)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 25, 12)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 25, 12)) +>y : Symbol(y, Decl(conditionalTypes1.ts, 25, 38)) +>NonNullable : Symbol(NonNullable, Decl(conditionalTypes1.ts, 1, 44)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 25, 12)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 25, 12)) + + x = y; +>x : Symbol(x, Decl(conditionalTypes1.ts, 25, 15)) +>y : Symbol(y, Decl(conditionalTypes1.ts, 25, 38)) + + y = x; // Error +>y : Symbol(y, Decl(conditionalTypes1.ts, 25, 38)) +>x : Symbol(x, Decl(conditionalTypes1.ts, 25, 15)) +} + +type Options = { k: "a", a: number } | { k: "b", b: string } | { k: "c", c: boolean }; +>Options : Symbol(Options, Decl(conditionalTypes1.ts, 28, 1)) +>k : Symbol(k, Decl(conditionalTypes1.ts, 30, 16)) +>a : Symbol(a, Decl(conditionalTypes1.ts, 30, 24)) +>k : Symbol(k, Decl(conditionalTypes1.ts, 30, 40)) +>b : Symbol(b, Decl(conditionalTypes1.ts, 30, 48)) +>k : Symbol(k, Decl(conditionalTypes1.ts, 30, 64)) +>c : Symbol(c, Decl(conditionalTypes1.ts, 30, 72)) + +type T10 = Diff; // { k: "c", c: boolean } +>T10 : Symbol(T10, Decl(conditionalTypes1.ts, 30, 86)) +>Diff : Symbol(Diff, Decl(conditionalTypes1.ts, 0, 0)) +>Options : Symbol(Options, Decl(conditionalTypes1.ts, 28, 1)) +>k : Symbol(k, Decl(conditionalTypes1.ts, 32, 26)) + +type T11 = Filter; // { k: "a", a: number } | { k: "b", b: string } +>T11 : Symbol(T11, Decl(conditionalTypes1.ts, 32, 43)) +>Filter : Symbol(Filter, Decl(conditionalTypes1.ts, 0, 42)) +>Options : Symbol(Options, Decl(conditionalTypes1.ts, 28, 1)) +>k : Symbol(k, Decl(conditionalTypes1.ts, 33, 28)) + +type T12 = Diff; // { k: "c", c: boolean } +>T12 : Symbol(T12, Decl(conditionalTypes1.ts, 33, 45)) +>Diff : Symbol(Diff, Decl(conditionalTypes1.ts, 0, 0)) +>Options : Symbol(Options, Decl(conditionalTypes1.ts, 28, 1)) +>k : Symbol(k, Decl(conditionalTypes1.ts, 35, 26)) +>k : Symbol(k, Decl(conditionalTypes1.ts, 35, 39)) + +type T13 = Filter; // { k: "a", a: number } | { k: "b", b: string } +>T13 : Symbol(T13, Decl(conditionalTypes1.ts, 35, 50)) +>Filter : Symbol(Filter, Decl(conditionalTypes1.ts, 0, 42)) +>Options : Symbol(Options, Decl(conditionalTypes1.ts, 28, 1)) +>k : Symbol(k, Decl(conditionalTypes1.ts, 36, 28)) +>k : Symbol(k, Decl(conditionalTypes1.ts, 36, 41)) + +type T14 = Diff; // Options +>T14 : Symbol(T14, Decl(conditionalTypes1.ts, 36, 52)) +>Diff : Symbol(Diff, Decl(conditionalTypes1.ts, 0, 0)) +>Options : Symbol(Options, Decl(conditionalTypes1.ts, 28, 1)) +>q : Symbol(q, Decl(conditionalTypes1.ts, 38, 26)) + +type T15 = Filter; // never +>T15 : Symbol(T15, Decl(conditionalTypes1.ts, 38, 37)) +>Filter : Symbol(Filter, Decl(conditionalTypes1.ts, 0, 42)) +>Options : Symbol(Options, Decl(conditionalTypes1.ts, 28, 1)) +>q : Symbol(q, Decl(conditionalTypes1.ts, 39, 28)) + +declare function f4(p: K): Filter; +>f4 : Symbol(f4, Decl(conditionalTypes1.ts, 39, 39)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 41, 20)) +>Options : Symbol(Options, Decl(conditionalTypes1.ts, 28, 1)) +>K : Symbol(K, Decl(conditionalTypes1.ts, 41, 38)) +>p : Symbol(p, Decl(conditionalTypes1.ts, 41, 57)) +>K : Symbol(K, Decl(conditionalTypes1.ts, 41, 38)) +>Filter : Symbol(Filter, Decl(conditionalTypes1.ts, 0, 42)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 41, 20)) +>k : Symbol(k, Decl(conditionalTypes1.ts, 41, 75)) +>K : Symbol(K, Decl(conditionalTypes1.ts, 41, 38)) + +let x0 = f4("a"); // { k: "a", a: number } +>x0 : Symbol(x0, Decl(conditionalTypes1.ts, 42, 3)) +>f4 : Symbol(f4, Decl(conditionalTypes1.ts, 39, 39)) + +type OptionsOfKind = Filter; +>OptionsOfKind : Symbol(OptionsOfKind, Decl(conditionalTypes1.ts, 42, 17)) +>K : Symbol(K, Decl(conditionalTypes1.ts, 44, 19)) +>Options : Symbol(Options, Decl(conditionalTypes1.ts, 28, 1)) +>Filter : Symbol(Filter, Decl(conditionalTypes1.ts, 0, 42)) +>Options : Symbol(Options, Decl(conditionalTypes1.ts, 28, 1)) +>k : Symbol(k, Decl(conditionalTypes1.ts, 44, 62)) +>K : Symbol(K, Decl(conditionalTypes1.ts, 44, 19)) + +type T16 = OptionsOfKind<"a" | "b">; // { k: "a", a: number } | { k: "b", b: string } +>T16 : Symbol(T16, Decl(conditionalTypes1.ts, 44, 71)) +>OptionsOfKind : Symbol(OptionsOfKind, Decl(conditionalTypes1.ts, 42, 17)) + +type Select = Filter; +>Select : Symbol(Select, Decl(conditionalTypes1.ts, 46, 36)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 48, 12)) +>K : Symbol(K, Decl(conditionalTypes1.ts, 48, 14)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 48, 12)) +>V : Symbol(V, Decl(conditionalTypes1.ts, 48, 33)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 48, 12)) +>K : Symbol(K, Decl(conditionalTypes1.ts, 48, 14)) +>Filter : Symbol(Filter, Decl(conditionalTypes1.ts, 0, 42)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 48, 12)) +>P : Symbol(P, Decl(conditionalTypes1.ts, 48, 65)) +>K : Symbol(K, Decl(conditionalTypes1.ts, 48, 14)) +>V : Symbol(V, Decl(conditionalTypes1.ts, 48, 33)) + +type T17 = Select; // // { k: "a", a: number } | { k: "b", b: string } +>T17 : Symbol(T17, Decl(conditionalTypes1.ts, 48, 79)) +>Select : Symbol(Select, Decl(conditionalTypes1.ts, 46, 36)) +>Options : Symbol(Options, Decl(conditionalTypes1.ts, 28, 1)) + +type TypeName = +>TypeName : Symbol(TypeName, Decl(conditionalTypes1.ts, 50, 43)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 52, 14)) + + T extends string ? "string" : +>T : Symbol(T, Decl(conditionalTypes1.ts, 52, 14)) + + T extends number ? "number" : +>T : Symbol(T, Decl(conditionalTypes1.ts, 52, 14)) + + T extends boolean ? "boolean" : +>T : Symbol(T, Decl(conditionalTypes1.ts, 52, 14)) + + T extends undefined ? "undefined" : +>T : Symbol(T, Decl(conditionalTypes1.ts, 52, 14)) + + T extends Function ? "function" : +>T : Symbol(T, Decl(conditionalTypes1.ts, 52, 14)) +>Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + + "object"; + +type T20 = TypeName void)>; // "string" | "function" +>T20 : Symbol(T20, Decl(conditionalTypes1.ts, 58, 13)) +>TypeName : Symbol(TypeName, Decl(conditionalTypes1.ts, 50, 43)) + +type T21 = TypeName; // "string" | "number" | "boolean" | "undefined" | "function" | "object" +>T21 : Symbol(T21, Decl(conditionalTypes1.ts, 60, 43)) +>TypeName : Symbol(TypeName, Decl(conditionalTypes1.ts, 50, 43)) + +type T22 = TypeName; // "string" | "number" | "boolean" | "undefined" | "function" | "object" +>T22 : Symbol(T22, Decl(conditionalTypes1.ts, 61, 25)) +>TypeName : Symbol(TypeName, Decl(conditionalTypes1.ts, 50, 43)) + +type T23 = TypeName<{}>; // "object" +>T23 : Symbol(T23, Decl(conditionalTypes1.ts, 62, 27)) +>TypeName : Symbol(TypeName, Decl(conditionalTypes1.ts, 50, 43)) + +type KnockoutObservable = { object: T }; +>KnockoutObservable : Symbol(KnockoutObservable, Decl(conditionalTypes1.ts, 63, 24)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 65, 24)) +>object : Symbol(object, Decl(conditionalTypes1.ts, 65, 30)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 65, 24)) + +type KnockoutObservableArray = { array: T }; +>KnockoutObservableArray : Symbol(KnockoutObservableArray, Decl(conditionalTypes1.ts, 65, 43)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 66, 29)) +>array : Symbol(array, Decl(conditionalTypes1.ts, 66, 35)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 66, 29)) + +type KnockedOut = T extends any[] ? KnockoutObservableArray : KnockoutObservable; +>KnockedOut : Symbol(KnockedOut, Decl(conditionalTypes1.ts, 66, 47)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 68, 16)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 68, 16)) +>KnockoutObservableArray : Symbol(KnockoutObservableArray, Decl(conditionalTypes1.ts, 65, 43)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 68, 16)) +>KnockoutObservable : Symbol(KnockoutObservable, Decl(conditionalTypes1.ts, 63, 24)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 68, 16)) + +type KnockedOutObj = { +>KnockedOutObj : Symbol(KnockedOutObj, Decl(conditionalTypes1.ts, 68, 98)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 70, 19)) + + [P in keyof T]: KnockedOut; +>P : Symbol(P, Decl(conditionalTypes1.ts, 71, 5)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 70, 19)) +>KnockedOut : Symbol(KnockedOut, Decl(conditionalTypes1.ts, 66, 47)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 70, 19)) +>P : Symbol(P, Decl(conditionalTypes1.ts, 71, 5)) +} + +interface Item { +>Item : Symbol(Item, Decl(conditionalTypes1.ts, 72, 1)) + + id: number; +>id : Symbol(Item.id, Decl(conditionalTypes1.ts, 74, 16)) + + name: string; +>name : Symbol(Item.name, Decl(conditionalTypes1.ts, 75, 15)) + + subitems: string[]; +>subitems : Symbol(Item.subitems, Decl(conditionalTypes1.ts, 76, 17)) +} + +type KOItem = KnockedOutObj; +>KOItem : Symbol(KOItem, Decl(conditionalTypes1.ts, 78, 1)) +>KnockedOutObj : Symbol(KnockedOutObj, Decl(conditionalTypes1.ts, 68, 98)) +>Item : Symbol(Item, Decl(conditionalTypes1.ts, 72, 1)) + +interface Part { +>Part : Symbol(Part, Decl(conditionalTypes1.ts, 80, 34)) + + id: number; +>id : Symbol(Part.id, Decl(conditionalTypes1.ts, 82, 16)) + + name: string; +>name : Symbol(Part.name, Decl(conditionalTypes1.ts, 83, 15)) + + subparts: Part[]; +>subparts : Symbol(Part.subparts, Decl(conditionalTypes1.ts, 84, 17)) +>Part : Symbol(Part, Decl(conditionalTypes1.ts, 80, 34)) + + updatePart(newName: string): void; +>updatePart : Symbol(Part.updatePart, Decl(conditionalTypes1.ts, 85, 21)) +>newName : Symbol(newName, Decl(conditionalTypes1.ts, 86, 15)) +} + +type FunctionPropertyNames = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T]; +>FunctionPropertyNames : Symbol(FunctionPropertyNames, Decl(conditionalTypes1.ts, 87, 1)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 89, 27)) +>K : Symbol(K, Decl(conditionalTypes1.ts, 89, 35)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 89, 27)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 89, 27)) +>K : Symbol(K, Decl(conditionalTypes1.ts, 89, 35)) +>Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>K : Symbol(K, Decl(conditionalTypes1.ts, 89, 35)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 89, 27)) + +type FunctionProperties = Pick>; +>FunctionProperties : Symbol(FunctionProperties, Decl(conditionalTypes1.ts, 89, 95)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 90, 24)) +>Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 90, 24)) +>FunctionPropertyNames : Symbol(FunctionPropertyNames, Decl(conditionalTypes1.ts, 87, 1)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 90, 24)) + +type NonFunctionPropertyNames = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T]; +>NonFunctionPropertyNames : Symbol(NonFunctionPropertyNames, Decl(conditionalTypes1.ts, 90, 63)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 92, 30)) +>K : Symbol(K, Decl(conditionalTypes1.ts, 92, 38)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 92, 30)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 92, 30)) +>K : Symbol(K, Decl(conditionalTypes1.ts, 92, 38)) +>Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>K : Symbol(K, Decl(conditionalTypes1.ts, 92, 38)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 92, 30)) + +type NonFunctionProperties = Pick>; +>NonFunctionProperties : Symbol(NonFunctionProperties, Decl(conditionalTypes1.ts, 92, 98)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 93, 27)) +>Pick : Symbol(Pick, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 93, 27)) +>NonFunctionPropertyNames : Symbol(NonFunctionPropertyNames, Decl(conditionalTypes1.ts, 90, 63)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 93, 27)) + +type T30 = FunctionProperties; +>T30 : Symbol(T30, Decl(conditionalTypes1.ts, 93, 69)) +>FunctionProperties : Symbol(FunctionProperties, Decl(conditionalTypes1.ts, 89, 95)) +>Part : Symbol(Part, Decl(conditionalTypes1.ts, 80, 34)) + +type T31 = NonFunctionProperties; +>T31 : Symbol(T31, Decl(conditionalTypes1.ts, 95, 36)) +>NonFunctionProperties : Symbol(NonFunctionProperties, Decl(conditionalTypes1.ts, 92, 98)) +>Part : Symbol(Part, Decl(conditionalTypes1.ts, 80, 34)) + +function f7(x: T, y: FunctionProperties, z: NonFunctionProperties) { +>f7 : Symbol(f7, Decl(conditionalTypes1.ts, 96, 39)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 98, 12)) +>x : Symbol(x, Decl(conditionalTypes1.ts, 98, 15)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 98, 12)) +>y : Symbol(y, Decl(conditionalTypes1.ts, 98, 20)) +>FunctionProperties : Symbol(FunctionProperties, Decl(conditionalTypes1.ts, 89, 95)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 98, 12)) +>z : Symbol(z, Decl(conditionalTypes1.ts, 98, 46)) +>NonFunctionProperties : Symbol(NonFunctionProperties, Decl(conditionalTypes1.ts, 92, 98)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 98, 12)) + + x = y; // Error +>x : Symbol(x, Decl(conditionalTypes1.ts, 98, 15)) +>y : Symbol(y, Decl(conditionalTypes1.ts, 98, 20)) + + x = z; // Error +>x : Symbol(x, Decl(conditionalTypes1.ts, 98, 15)) +>z : Symbol(z, Decl(conditionalTypes1.ts, 98, 46)) + + y = x; +>y : Symbol(y, Decl(conditionalTypes1.ts, 98, 20)) +>x : Symbol(x, Decl(conditionalTypes1.ts, 98, 15)) + + y = z; // Error +>y : Symbol(y, Decl(conditionalTypes1.ts, 98, 20)) +>z : Symbol(z, Decl(conditionalTypes1.ts, 98, 46)) + + z = x; +>z : Symbol(z, Decl(conditionalTypes1.ts, 98, 46)) +>x : Symbol(x, Decl(conditionalTypes1.ts, 98, 15)) + + z = y; // Error +>z : Symbol(z, Decl(conditionalTypes1.ts, 98, 46)) +>y : Symbol(y, Decl(conditionalTypes1.ts, 98, 20)) +} + +function f8(x: keyof T, y: FunctionPropertyNames, z: NonFunctionPropertyNames) { +>f8 : Symbol(f8, Decl(conditionalTypes1.ts, 105, 1)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 107, 12)) +>x : Symbol(x, Decl(conditionalTypes1.ts, 107, 15)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 107, 12)) +>y : Symbol(y, Decl(conditionalTypes1.ts, 107, 26)) +>FunctionPropertyNames : Symbol(FunctionPropertyNames, Decl(conditionalTypes1.ts, 87, 1)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 107, 12)) +>z : Symbol(z, Decl(conditionalTypes1.ts, 107, 55)) +>NonFunctionPropertyNames : Symbol(NonFunctionPropertyNames, Decl(conditionalTypes1.ts, 90, 63)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 107, 12)) + + x = y; +>x : Symbol(x, Decl(conditionalTypes1.ts, 107, 15)) +>y : Symbol(y, Decl(conditionalTypes1.ts, 107, 26)) + + x = z; +>x : Symbol(x, Decl(conditionalTypes1.ts, 107, 15)) +>z : Symbol(z, Decl(conditionalTypes1.ts, 107, 55)) + + y = x; // Error +>y : Symbol(y, Decl(conditionalTypes1.ts, 107, 26)) +>x : Symbol(x, Decl(conditionalTypes1.ts, 107, 15)) + + y = z; // Error +>y : Symbol(y, Decl(conditionalTypes1.ts, 107, 26)) +>z : Symbol(z, Decl(conditionalTypes1.ts, 107, 55)) + + z = x; // Error +>z : Symbol(z, Decl(conditionalTypes1.ts, 107, 55)) +>x : Symbol(x, Decl(conditionalTypes1.ts, 107, 15)) + + z = y; // Error +>z : Symbol(z, Decl(conditionalTypes1.ts, 107, 55)) +>y : Symbol(y, Decl(conditionalTypes1.ts, 107, 26)) +} + +type DeepReadonly = +>DeepReadonly : Symbol(DeepReadonly, Decl(conditionalTypes1.ts, 114, 1)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 116, 18)) + + T extends any[] ? DeepReadonlyArray : +>T : Symbol(T, Decl(conditionalTypes1.ts, 116, 18)) +>DeepReadonlyArray : Symbol(DeepReadonlyArray, Decl(conditionalTypes1.ts, 119, 6)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 116, 18)) + + T extends object ? DeepReadonlyObject : +>T : Symbol(T, Decl(conditionalTypes1.ts, 116, 18)) +>DeepReadonlyObject : Symbol(DeepReadonlyObject, Decl(conditionalTypes1.ts, 121, 72)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 116, 18)) + + T; +>T : Symbol(T, Decl(conditionalTypes1.ts, 116, 18)) + +interface DeepReadonlyArray extends ReadonlyArray> {} +>DeepReadonlyArray : Symbol(DeepReadonlyArray, Decl(conditionalTypes1.ts, 119, 6)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 121, 28)) +>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.d.ts, --, --)) +>DeepReadonly : Symbol(DeepReadonly, Decl(conditionalTypes1.ts, 114, 1)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 121, 28)) + +type DeepReadonlyObject = { +>DeepReadonlyObject : Symbol(DeepReadonlyObject, Decl(conditionalTypes1.ts, 121, 72)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 123, 24)) + + readonly [P in NonFunctionPropertyNames]: DeepReadonly; +>P : Symbol(P, Decl(conditionalTypes1.ts, 124, 14)) +>NonFunctionPropertyNames : Symbol(NonFunctionPropertyNames, Decl(conditionalTypes1.ts, 90, 63)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 123, 24)) +>DeepReadonly : Symbol(DeepReadonly, Decl(conditionalTypes1.ts, 114, 1)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 123, 24)) +>P : Symbol(P, Decl(conditionalTypes1.ts, 124, 14)) + +}; + +function f10(part: DeepReadonly) { +>f10 : Symbol(f10, Decl(conditionalTypes1.ts, 125, 2)) +>part : Symbol(part, Decl(conditionalTypes1.ts, 127, 13)) +>DeepReadonly : Symbol(DeepReadonly, Decl(conditionalTypes1.ts, 114, 1)) +>Part : Symbol(Part, Decl(conditionalTypes1.ts, 80, 34)) + + let name: string = part.name; +>name : Symbol(name, Decl(conditionalTypes1.ts, 128, 7)) +>part.name : Symbol(name) +>part : Symbol(part, Decl(conditionalTypes1.ts, 127, 13)) +>name : Symbol(name) + + let id: number = part.subparts[0].id; +>id : Symbol(id, Decl(conditionalTypes1.ts, 129, 7)) +>part.subparts[0].id : Symbol(id) +>part.subparts : Symbol(subparts) +>part : Symbol(part, Decl(conditionalTypes1.ts, 127, 13)) +>subparts : Symbol(subparts) +>id : Symbol(id) + + part.id = part.id; // Error +>part.id : Symbol(id) +>part : Symbol(part, Decl(conditionalTypes1.ts, 127, 13)) +>id : Symbol(id) +>part.id : Symbol(id) +>part : Symbol(part, Decl(conditionalTypes1.ts, 127, 13)) +>id : Symbol(id) + + part.subparts[0] = part.subparts[0]; // Error +>part.subparts : Symbol(subparts) +>part : Symbol(part, Decl(conditionalTypes1.ts, 127, 13)) +>subparts : Symbol(subparts) +>part.subparts : Symbol(subparts) +>part : Symbol(part, Decl(conditionalTypes1.ts, 127, 13)) +>subparts : Symbol(subparts) + + part.subparts[0].id = part.subparts[0].id; // Error +>part.subparts[0].id : Symbol(id) +>part.subparts : Symbol(subparts) +>part : Symbol(part, Decl(conditionalTypes1.ts, 127, 13)) +>subparts : Symbol(subparts) +>id : Symbol(id) +>part.subparts[0].id : Symbol(id) +>part.subparts : Symbol(subparts) +>part : Symbol(part, Decl(conditionalTypes1.ts, 127, 13)) +>subparts : Symbol(subparts) +>id : Symbol(id) + + part.updatePart("hello"); // Error +>part : Symbol(part, Decl(conditionalTypes1.ts, 127, 13)) +} + +type ZeroOf = T extends number ? 0 : T extends string ? "" : false; +>ZeroOf : Symbol(ZeroOf, Decl(conditionalTypes1.ts, 134, 1)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 136, 12)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 136, 12)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 136, 12)) + +function zeroOf(value: T) { +>zeroOf : Symbol(zeroOf, Decl(conditionalTypes1.ts, 136, 104)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 138, 16)) +>value : Symbol(value, Decl(conditionalTypes1.ts, 138, 53)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 138, 16)) + + return >(typeof value === "number" ? 0 : typeof value === "string" ? "" : false); +>ZeroOf : Symbol(ZeroOf, Decl(conditionalTypes1.ts, 134, 1)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 138, 16)) +>value : Symbol(value, Decl(conditionalTypes1.ts, 138, 53)) +>value : Symbol(value, Decl(conditionalTypes1.ts, 138, 53)) +} + +function f20(n: number, b: boolean, x: number | boolean, y: T) { +>f20 : Symbol(f20, Decl(conditionalTypes1.ts, 140, 1)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 142, 13)) +>n : Symbol(n, Decl(conditionalTypes1.ts, 142, 31)) +>b : Symbol(b, Decl(conditionalTypes1.ts, 142, 41)) +>x : Symbol(x, Decl(conditionalTypes1.ts, 142, 53)) +>y : Symbol(y, Decl(conditionalTypes1.ts, 142, 74)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 142, 13)) + + zeroOf(5); // 0 +>zeroOf : Symbol(zeroOf, Decl(conditionalTypes1.ts, 136, 104)) + + zeroOf("hello"); // "" +>zeroOf : Symbol(zeroOf, Decl(conditionalTypes1.ts, 136, 104)) + + zeroOf(true); // false +>zeroOf : Symbol(zeroOf, Decl(conditionalTypes1.ts, 136, 104)) + + zeroOf(n); // 0 +>zeroOf : Symbol(zeroOf, Decl(conditionalTypes1.ts, 136, 104)) +>n : Symbol(n, Decl(conditionalTypes1.ts, 142, 31)) + + zeroOf(b); // False +>zeroOf : Symbol(zeroOf, Decl(conditionalTypes1.ts, 136, 104)) +>b : Symbol(b, Decl(conditionalTypes1.ts, 142, 41)) + + zeroOf(x); // 0 | false +>zeroOf : Symbol(zeroOf, Decl(conditionalTypes1.ts, 136, 104)) +>x : Symbol(x, Decl(conditionalTypes1.ts, 142, 53)) + + zeroOf(y); // ZeroOf +>zeroOf : Symbol(zeroOf, Decl(conditionalTypes1.ts, 136, 104)) +>y : Symbol(y, Decl(conditionalTypes1.ts, 142, 74)) +} + +function f21(x: T, y: ZeroOf) { +>f21 : Symbol(f21, Decl(conditionalTypes1.ts, 150, 1)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 152, 13)) +>x : Symbol(x, Decl(conditionalTypes1.ts, 152, 40)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 152, 13)) +>y : Symbol(y, Decl(conditionalTypes1.ts, 152, 45)) +>ZeroOf : Symbol(ZeroOf, Decl(conditionalTypes1.ts, 134, 1)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 152, 13)) + + let z1: number | string = y; +>z1 : Symbol(z1, Decl(conditionalTypes1.ts, 153, 7)) +>y : Symbol(y, Decl(conditionalTypes1.ts, 152, 45)) + + let z2: 0 | "" = y; +>z2 : Symbol(z2, Decl(conditionalTypes1.ts, 154, 7)) +>y : Symbol(y, Decl(conditionalTypes1.ts, 152, 45)) + + x = y; // Error +>x : Symbol(x, Decl(conditionalTypes1.ts, 152, 40)) +>y : Symbol(y, Decl(conditionalTypes1.ts, 152, 45)) + + y = x; // Error +>y : Symbol(y, Decl(conditionalTypes1.ts, 152, 45)) +>x : Symbol(x, Decl(conditionalTypes1.ts, 152, 40)) +} + +type Extends = T extends U ? true : false; +>Extends : Symbol(Extends, Decl(conditionalTypes1.ts, 157, 1)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 159, 13)) +>U : Symbol(U, Decl(conditionalTypes1.ts, 159, 15)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 159, 13)) +>U : Symbol(U, Decl(conditionalTypes1.ts, 159, 15)) + +type If = C extends true ? T : F; +>If : Symbol(If, Decl(conditionalTypes1.ts, 159, 48)) +>C : Symbol(C, Decl(conditionalTypes1.ts, 160, 8)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 160, 26)) +>F : Symbol(F, Decl(conditionalTypes1.ts, 160, 29)) +>C : Symbol(C, Decl(conditionalTypes1.ts, 160, 8)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 160, 26)) +>F : Symbol(F, Decl(conditionalTypes1.ts, 160, 29)) + +type Not = If; +>Not : Symbol(Not, Decl(conditionalTypes1.ts, 160, 58)) +>C : Symbol(C, Decl(conditionalTypes1.ts, 161, 9)) +>If : Symbol(If, Decl(conditionalTypes1.ts, 159, 48)) +>C : Symbol(C, Decl(conditionalTypes1.ts, 161, 9)) + +type And = If; +>And : Symbol(And, Decl(conditionalTypes1.ts, 161, 49)) +>A : Symbol(A, Decl(conditionalTypes1.ts, 162, 9)) +>B : Symbol(B, Decl(conditionalTypes1.ts, 162, 27)) +>If : Symbol(If, Decl(conditionalTypes1.ts, 159, 48)) +>A : Symbol(A, Decl(conditionalTypes1.ts, 162, 9)) +>B : Symbol(B, Decl(conditionalTypes1.ts, 162, 27)) + +type Or = If; +>Or : Symbol(Or, Decl(conditionalTypes1.ts, 162, 65)) +>A : Symbol(A, Decl(conditionalTypes1.ts, 163, 8)) +>B : Symbol(B, Decl(conditionalTypes1.ts, 163, 26)) +>If : Symbol(If, Decl(conditionalTypes1.ts, 159, 48)) +>A : Symbol(A, Decl(conditionalTypes1.ts, 163, 8)) +>B : Symbol(B, Decl(conditionalTypes1.ts, 163, 26)) + +type isString = Extends; +>isString : Symbol(isString, Decl(conditionalTypes1.ts, 163, 63)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 165, 14)) +>Extends : Symbol(Extends, Decl(conditionalTypes1.ts, 157, 1)) +>T : Symbol(T, Decl(conditionalTypes1.ts, 165, 14)) + +type Q1 = isString; // false +>Q1 : Symbol(Q1, Decl(conditionalTypes1.ts, 165, 38)) +>isString : Symbol(isString, Decl(conditionalTypes1.ts, 163, 63)) + +type Q2 = isString<"abc">; // true +>Q2 : Symbol(Q2, Decl(conditionalTypes1.ts, 167, 27)) +>isString : Symbol(isString, Decl(conditionalTypes1.ts, 163, 63)) + +type Q3 = isString; // boolean +>Q3 : Symbol(Q3, Decl(conditionalTypes1.ts, 168, 26)) +>isString : Symbol(isString, Decl(conditionalTypes1.ts, 163, 63)) + +type Q4 = isString; // boolean +>Q4 : Symbol(Q4, Decl(conditionalTypes1.ts, 169, 24)) +>isString : Symbol(isString, Decl(conditionalTypes1.ts, 163, 63)) + +type N1 = Not; // true +>N1 : Symbol(N1, Decl(conditionalTypes1.ts, 170, 26)) +>Not : Symbol(Not, Decl(conditionalTypes1.ts, 160, 58)) + +type N2 = Not; // false +>N2 : Symbol(N2, Decl(conditionalTypes1.ts, 172, 21)) +>Not : Symbol(Not, Decl(conditionalTypes1.ts, 160, 58)) + +type N3 = Not; // boolean +>N3 : Symbol(N3, Decl(conditionalTypes1.ts, 173, 20)) +>Not : Symbol(Not, Decl(conditionalTypes1.ts, 160, 58)) + +type A1 = And; // false +>A1 : Symbol(A1, Decl(conditionalTypes1.ts, 174, 23)) +>And : Symbol(And, Decl(conditionalTypes1.ts, 161, 49)) + +type A2 = And; // false +>A2 : Symbol(A2, Decl(conditionalTypes1.ts, 176, 28)) +>And : Symbol(And, Decl(conditionalTypes1.ts, 161, 49)) + +type A3 = And; // false +>A3 : Symbol(A3, Decl(conditionalTypes1.ts, 177, 27)) +>And : Symbol(And, Decl(conditionalTypes1.ts, 161, 49)) + +type A4 = And; // true +>A4 : Symbol(A4, Decl(conditionalTypes1.ts, 178, 27)) +>And : Symbol(And, Decl(conditionalTypes1.ts, 161, 49)) + +type A5 = And; // false +>A5 : Symbol(A5, Decl(conditionalTypes1.ts, 179, 26)) +>And : Symbol(And, Decl(conditionalTypes1.ts, 161, 49)) + +type A6 = And; // false +>A6 : Symbol(A6, Decl(conditionalTypes1.ts, 180, 30)) +>And : Symbol(And, Decl(conditionalTypes1.ts, 161, 49)) + +type A7 = And; // boolean +>A7 : Symbol(A7, Decl(conditionalTypes1.ts, 181, 30)) +>And : Symbol(And, Decl(conditionalTypes1.ts, 161, 49)) + +type A8 = And; // boolean +>A8 : Symbol(A8, Decl(conditionalTypes1.ts, 182, 29)) +>And : Symbol(And, Decl(conditionalTypes1.ts, 161, 49)) + +type A9 = And; // boolean +>A9 : Symbol(A9, Decl(conditionalTypes1.ts, 183, 29)) +>And : Symbol(And, Decl(conditionalTypes1.ts, 161, 49)) + +type O1 = Or; // false +>O1 : Symbol(O1, Decl(conditionalTypes1.ts, 184, 32)) +>Or : Symbol(Or, Decl(conditionalTypes1.ts, 162, 65)) + +type O2 = Or; // true +>O2 : Symbol(O2, Decl(conditionalTypes1.ts, 186, 27)) +>Or : Symbol(Or, Decl(conditionalTypes1.ts, 162, 65)) + +type O3 = Or; // true +>O3 : Symbol(O3, Decl(conditionalTypes1.ts, 187, 26)) +>Or : Symbol(Or, Decl(conditionalTypes1.ts, 162, 65)) + +type O4 = Or; // true +>O4 : Symbol(O4, Decl(conditionalTypes1.ts, 188, 26)) +>Or : Symbol(Or, Decl(conditionalTypes1.ts, 162, 65)) + +type O5 = Or; // boolean +>O5 : Symbol(O5, Decl(conditionalTypes1.ts, 189, 25)) +>Or : Symbol(Or, Decl(conditionalTypes1.ts, 162, 65)) + +type O6 = Or; // boolean +>O6 : Symbol(O6, Decl(conditionalTypes1.ts, 190, 29)) +>Or : Symbol(Or, Decl(conditionalTypes1.ts, 162, 65)) + +type O7 = Or; // true +>O7 : Symbol(O7, Decl(conditionalTypes1.ts, 191, 29)) +>Or : Symbol(Or, Decl(conditionalTypes1.ts, 162, 65)) + +type O8 = Or; // true +>O8 : Symbol(O8, Decl(conditionalTypes1.ts, 192, 28)) +>Or : Symbol(Or, Decl(conditionalTypes1.ts, 162, 65)) + +type O9 = Or; // boolean +>O9 : Symbol(O9, Decl(conditionalTypes1.ts, 193, 28)) +>Or : Symbol(Or, Decl(conditionalTypes1.ts, 162, 65)) + diff --git a/tests/baselines/reference/conditionalTypes1.types b/tests/baselines/reference/conditionalTypes1.types new file mode 100644 index 0000000000000..86a02fa001bac --- /dev/null +++ b/tests/baselines/reference/conditionalTypes1.types @@ -0,0 +1,851 @@ +=== tests/cases/conformance/types/conditional/conditionalTypes1.ts === +type Diff = T extends U ? never : T; +>Diff : Diff +>T : T +>U : U +>T : T +>U : U +>T : T + +type Filter = T extends U ? T : never; +>Filter : Filter +>T : T +>U : U +>T : T +>U : U +>T : T + +type NonNullable = Diff; +>NonNullable : Diff +>T : T +>Diff : Diff +>T : T +>null : null + +type T00 = Diff<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "b" | "d" +>T00 : "b" | "d" +>Diff : Diff + +type T01 = Filter<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "a" | "c" +>T01 : "a" | "c" +>Filter : Filter + +type T02 = Diff void), Function>; // string | number +>T02 : string | number +>Diff : Diff +>Function : Function + +type T03 = Filter void), Function>; // () => void +>T03 : () => void +>Filter : Filter +>Function : Function + +type T04 = NonNullable; // string | number +>T04 : string | number +>NonNullable : Diff + +type T05 = NonNullable<(() => string) | string[] | null | undefined>; // (() => string) | string[] +>T05 : (() => string) | string[] +>NonNullable : Diff +>null : null + +function f1(x: T, y: NonNullable) { +>f1 : (x: T, y: Diff) => void +>T : T +>x : T +>T : T +>y : Diff +>NonNullable : Diff +>T : T + + x = y; +>x = y : Diff +>x : T +>y : Diff + + y = x; // Error +>y = x : T +>y : Diff +>x : T +} + +function f2(x: T, y: NonNullable) { +>f2 : (x: T, y: Diff) => void +>T : T +>x : T +>T : T +>y : Diff +>NonNullable : Diff +>T : T + + x = y; +>x = y : Diff +>x : T +>y : Diff + + y = x; // Error +>y = x : T +>y : Diff +>x : T + + let s1: string = x; // Error +>s1 : string +>x : T + + let s2: string = y; +>s2 : string +>y : Diff +} + +function f3(x: Partial[keyof T], y: NonNullable[keyof T]>) { +>f3 : (x: Partial[keyof T], y: Diff[keyof T], null | undefined>) => void +>T : T +>x : Partial[keyof T] +>Partial : Partial +>T : T +>T : T +>y : Diff[keyof T], null | undefined> +>NonNullable : Diff +>Partial : Partial +>T : T +>T : T + + x = y; +>x = y : Diff[keyof T], null | undefined> +>x : Partial[keyof T] +>y : Diff[keyof T], null | undefined> + + y = x; // Error +>y = x : Partial[keyof T] +>y : Diff[keyof T], null | undefined> +>x : Partial[keyof T] +} + +type Options = { k: "a", a: number } | { k: "b", b: string } | { k: "c", c: boolean }; +>Options : Options +>k : "a" +>a : number +>k : "b" +>b : string +>k : "c" +>c : boolean + +type T10 = Diff; // { k: "c", c: boolean } +>T10 : { k: "c"; c: boolean; } +>Diff : Diff +>Options : Options +>k : "a" | "b" + +type T11 = Filter; // { k: "a", a: number } | { k: "b", b: string } +>T11 : { k: "a"; a: number; } | { k: "b"; b: string; } +>Filter : Filter +>Options : Options +>k : "a" | "b" + +type T12 = Diff; // { k: "c", c: boolean } +>T12 : { k: "c"; c: boolean; } +>Diff : Diff +>Options : Options +>k : "a" +>k : "b" + +type T13 = Filter; // { k: "a", a: number } | { k: "b", b: string } +>T13 : { k: "a"; a: number; } | { k: "b"; b: string; } +>Filter : Filter +>Options : Options +>k : "a" +>k : "b" + +type T14 = Diff; // Options +>T14 : Options +>Diff : Diff +>Options : Options +>q : "a" + +type T15 = Filter; // never +>T15 : never +>Filter : Filter +>Options : Options +>q : "a" + +declare function f4(p: K): Filter; +>f4 : (p: K) => Filter +>T : T +>Options : Options +>K : K +>p : K +>K : K +>Filter : Filter +>T : T +>k : K +>K : K + +let x0 = f4("a"); // { k: "a", a: number } +>x0 : { k: "a"; a: number; } +>f4("a") : { k: "a"; a: number; } +>f4 : (p: K) => Filter +>"a" : "a" + +type OptionsOfKind = Filter; +>OptionsOfKind : Filter<{ k: "a"; a: number; }, { k: K; }> | Filter<{ k: "b"; b: string; }, { k: K; }> | Filter<{ k: "c"; c: boolean; }, { k: K; }> +>K : K +>Options : Options +>Filter : Filter +>Options : Options +>k : K +>K : K + +type T16 = OptionsOfKind<"a" | "b">; // { k: "a", a: number } | { k: "b", b: string } +>T16 : { k: "a"; a: number; } | { k: "b"; b: string; } +>OptionsOfKind : Filter<{ k: "a"; a: number; }, { k: K; }> | Filter<{ k: "b"; b: string; }, { k: K; }> | Filter<{ k: "c"; c: boolean; }, { k: K; }> + +type Select = Filter; +>Select : Filter +>T : T +>K : K +>T : T +>V : V +>T : T +>K : K +>Filter : Filter +>T : T +>P : P +>K : K +>V : V + +type T17 = Select; // // { k: "a", a: number } | { k: "b", b: string } +>T17 : { k: "a"; a: number; } | { k: "b"; b: string; } +>Select : Filter +>Options : Options + +type TypeName = +>TypeName : TypeName +>T : T + + T extends string ? "string" : +>T : T + + T extends number ? "number" : +>T : T + + T extends boolean ? "boolean" : +>T : T + + T extends undefined ? "undefined" : +>T : T + + T extends Function ? "function" : +>T : T +>Function : Function + + "object"; + +type T20 = TypeName void)>; // "string" | "function" +>T20 : "string" | "function" +>TypeName : TypeName + +type T21 = TypeName; // "string" | "number" | "boolean" | "undefined" | "function" | "object" +>T21 : "string" | "number" | "boolean" | "undefined" | "object" | "function" +>TypeName : TypeName + +type T22 = TypeName; // "string" | "number" | "boolean" | "undefined" | "function" | "object" +>T22 : "string" | "number" | "boolean" | "undefined" | "object" | "function" +>TypeName : TypeName + +type T23 = TypeName<{}>; // "object" +>T23 : "object" +>TypeName : TypeName + +type KnockoutObservable = { object: T }; +>KnockoutObservable : KnockoutObservable +>T : T +>object : T +>T : T + +type KnockoutObservableArray = { array: T }; +>KnockoutObservableArray : KnockoutObservableArray +>T : T +>array : T +>T : T + +type KnockedOut = T extends any[] ? KnockoutObservableArray : KnockoutObservable; +>KnockedOut : KnockedOut +>T : T +>T : T +>KnockoutObservableArray : KnockoutObservableArray +>T : T +>KnockoutObservable : KnockoutObservable +>T : T + +type KnockedOutObj = { +>KnockedOutObj : KnockedOutObj +>T : T + + [P in keyof T]: KnockedOut; +>P : P +>T : T +>KnockedOut : KnockedOut +>T : T +>P : P +} + +interface Item { +>Item : Item + + id: number; +>id : number + + name: string; +>name : string + + subitems: string[]; +>subitems : string[] +} + +type KOItem = KnockedOutObj; +>KOItem : KnockedOutObj +>KnockedOutObj : KnockedOutObj +>Item : Item + +interface Part { +>Part : Part + + id: number; +>id : number + + name: string; +>name : string + + subparts: Part[]; +>subparts : Part[] +>Part : Part + + updatePart(newName: string): void; +>updatePart : (newName: string) => void +>newName : string +} + +type FunctionPropertyNames = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T]; +>FunctionPropertyNames : { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T] +>T : T +>K : K +>T : T +>T : T +>K : K +>Function : Function +>K : K +>T : T + +type FunctionProperties = Pick>; +>FunctionProperties : Pick +>T : T +>Pick : Pick +>T : T +>FunctionPropertyNames : { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T] +>T : T + +type NonFunctionPropertyNames = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T]; +>NonFunctionPropertyNames : { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T] +>T : T +>K : K +>T : T +>T : T +>K : K +>Function : Function +>K : K +>T : T + +type NonFunctionProperties = Pick>; +>NonFunctionProperties : Pick +>T : T +>Pick : Pick +>T : T +>NonFunctionPropertyNames : { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T] +>T : T + +type T30 = FunctionProperties; +>T30 : Pick +>FunctionProperties : Pick +>Part : Part + +type T31 = NonFunctionProperties; +>T31 : Pick +>NonFunctionProperties : Pick +>Part : Part + +function f7(x: T, y: FunctionProperties, z: NonFunctionProperties) { +>f7 : (x: T, y: Pick, z: Pick) => void +>T : T +>x : T +>T : T +>y : Pick +>FunctionProperties : Pick +>T : T +>z : Pick +>NonFunctionProperties : Pick +>T : T + + x = y; // Error +>x = y : Pick +>x : T +>y : Pick + + x = z; // Error +>x = z : Pick +>x : T +>z : Pick + + y = x; +>y = x : T +>y : Pick +>x : T + + y = z; // Error +>y = z : Pick +>y : Pick +>z : Pick + + z = x; +>z = x : T +>z : Pick +>x : T + + z = y; // Error +>z = y : Pick +>z : Pick +>y : Pick +} + +function f8(x: keyof T, y: FunctionPropertyNames, z: NonFunctionPropertyNames) { +>f8 : (x: keyof T, y: { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T], z: { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]) => void +>T : T +>x : keyof T +>T : T +>y : { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T] +>FunctionPropertyNames : { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T] +>T : T +>z : { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T] +>NonFunctionPropertyNames : { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T] +>T : T + + x = y; +>x = y : { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T] +>x : keyof T +>y : { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T] + + x = z; +>x = z : { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T] +>x : keyof T +>z : { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T] + + y = x; // Error +>y = x : keyof T +>y : { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T] +>x : keyof T + + y = z; // Error +>y = z : { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T] +>y : { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T] +>z : { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T] + + z = x; // Error +>z = x : keyof T +>z : { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T] +>x : keyof T + + z = y; // Error +>z = y : { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T] +>z : { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T] +>y : { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T] +} + +type DeepReadonly = +>DeepReadonly : DeepReadonly +>T : T + + T extends any[] ? DeepReadonlyArray : +>T : T +>DeepReadonlyArray : DeepReadonlyArray +>T : T + + T extends object ? DeepReadonlyObject : +>T : T +>DeepReadonlyObject : DeepReadonlyObject +>T : T + + T; +>T : T + +interface DeepReadonlyArray extends ReadonlyArray> {} +>DeepReadonlyArray : DeepReadonlyArray +>T : T +>ReadonlyArray : ReadonlyArray +>DeepReadonly : DeepReadonly +>T : T + +type DeepReadonlyObject = { +>DeepReadonlyObject : DeepReadonlyObject +>T : T + + readonly [P in NonFunctionPropertyNames]: DeepReadonly; +>P : P +>NonFunctionPropertyNames : { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T] +>T : T +>DeepReadonly : DeepReadonly +>T : T +>P : P + +}; + +function f10(part: DeepReadonly) { +>f10 : (part: DeepReadonlyObject) => void +>part : DeepReadonlyObject +>DeepReadonly : DeepReadonly +>Part : Part + + let name: string = part.name; +>name : string +>part.name : string +>part : DeepReadonlyObject +>name : string + + let id: number = part.subparts[0].id; +>id : number +>part.subparts[0].id : number +>part.subparts[0] : DeepReadonlyObject +>part.subparts : DeepReadonlyArray +>part : DeepReadonlyObject +>subparts : DeepReadonlyArray +>0 : 0 +>id : number + + part.id = part.id; // Error +>part.id = part.id : number +>part.id : any +>part : DeepReadonlyObject +>id : any +>part.id : number +>part : DeepReadonlyObject +>id : number + + part.subparts[0] = part.subparts[0]; // Error +>part.subparts[0] = part.subparts[0] : DeepReadonlyObject +>part.subparts[0] : DeepReadonlyObject +>part.subparts : DeepReadonlyArray +>part : DeepReadonlyObject +>subparts : DeepReadonlyArray +>0 : 0 +>part.subparts[0] : DeepReadonlyObject +>part.subparts : DeepReadonlyArray +>part : DeepReadonlyObject +>subparts : DeepReadonlyArray +>0 : 0 + + part.subparts[0].id = part.subparts[0].id; // Error +>part.subparts[0].id = part.subparts[0].id : number +>part.subparts[0].id : any +>part.subparts[0] : DeepReadonlyObject +>part.subparts : DeepReadonlyArray +>part : DeepReadonlyObject +>subparts : DeepReadonlyArray +>0 : 0 +>id : any +>part.subparts[0].id : number +>part.subparts[0] : DeepReadonlyObject +>part.subparts : DeepReadonlyArray +>part : DeepReadonlyObject +>subparts : DeepReadonlyArray +>0 : 0 +>id : number + + part.updatePart("hello"); // Error +>part.updatePart("hello") : any +>part.updatePart : any +>part : DeepReadonlyObject +>updatePart : any +>"hello" : "hello" +} + +type ZeroOf = T extends number ? 0 : T extends string ? "" : false; +>ZeroOf : ZeroOf +>T : T +>T : T +>T : T +>false : false + +function zeroOf(value: T) { +>zeroOf : (value: T) => ZeroOf +>T : T +>value : T +>T : T + + return >(typeof value === "number" ? 0 : typeof value === "string" ? "" : false); +>>(typeof value === "number" ? 0 : typeof value === "string" ? "" : false) : ZeroOf +>ZeroOf : ZeroOf +>T : T +>(typeof value === "number" ? 0 : typeof value === "string" ? "" : false) : false | 0 | "" +>typeof value === "number" ? 0 : typeof value === "string" ? "" : false : false | 0 | "" +>typeof value === "number" : boolean +>typeof value : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function" +>value : T +>"number" : "number" +>0 : 0 +>typeof value === "string" ? "" : false : false | "" +>typeof value === "string" : boolean +>typeof value : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function" +>value : T +>"string" : "string" +>"" : "" +>false : false +} + +function f20(n: number, b: boolean, x: number | boolean, y: T) { +>f20 : (n: number, b: boolean, x: number | boolean, y: T) => void +>T : T +>n : number +>b : boolean +>x : number | boolean +>y : T +>T : T + + zeroOf(5); // 0 +>zeroOf(5) : 0 +>zeroOf : (value: T) => ZeroOf +>5 : 5 + + zeroOf("hello"); // "" +>zeroOf("hello") : "" +>zeroOf : (value: T) => ZeroOf +>"hello" : "hello" + + zeroOf(true); // false +>zeroOf(true) : false +>zeroOf : (value: T) => ZeroOf +>true : true + + zeroOf(n); // 0 +>zeroOf(n) : 0 +>zeroOf : (value: T) => ZeroOf +>n : number + + zeroOf(b); // False +>zeroOf(b) : false +>zeroOf : (value: T) => ZeroOf +>b : boolean + + zeroOf(x); // 0 | false +>zeroOf(x) : false | 0 +>zeroOf : (value: T) => ZeroOf +>x : number | boolean + + zeroOf(y); // ZeroOf +>zeroOf(y) : ZeroOf +>zeroOf : (value: T) => ZeroOf +>y : T +} + +function f21(x: T, y: ZeroOf) { +>f21 : (x: T, y: ZeroOf) => void +>T : T +>x : T +>T : T +>y : ZeroOf +>ZeroOf : ZeroOf +>T : T + + let z1: number | string = y; +>z1 : string | number +>y : ZeroOf + + let z2: 0 | "" = y; +>z2 : "" | 0 +>y : ZeroOf + + x = y; // Error +>x = y : ZeroOf +>x : T +>y : ZeroOf + + y = x; // Error +>y = x : T +>y : ZeroOf +>x : T +} + +type Extends = T extends U ? true : false; +>Extends : Extends +>T : T +>U : U +>T : T +>U : U +>true : true +>false : false + +type If = C extends true ? T : F; +>If : If +>C : C +>T : T +>F : F +>C : C +>true : true +>T : T +>F : F + +type Not = If; +>Not : If +>C : C +>If : If +>C : C +>false : false +>true : true + +type And = If; +>And : If +>A : A +>B : B +>If : If +>A : A +>B : B +>false : false + +type Or = If; +>Or : If +>A : A +>B : B +>If : If +>A : A +>true : true +>B : B + +type isString = Extends; +>isString : Extends +>T : T +>Extends : Extends +>T : T + +type Q1 = isString; // false +>Q1 : false +>isString : Extends + +type Q2 = isString<"abc">; // true +>Q2 : true +>isString : Extends + +type Q3 = isString; // boolean +>Q3 : boolean +>isString : Extends + +type Q4 = isString; // boolean +>Q4 : boolean +>isString : Extends + +type N1 = Not; // true +>N1 : true +>Not : If +>false : false + +type N2 = Not; // false +>N2 : false +>Not : If +>true : true + +type N3 = Not; // boolean +>N3 : boolean +>Not : If + +type A1 = And; // false +>A1 : false +>And : If +>false : false +>false : false + +type A2 = And; // false +>A2 : false +>And : If +>false : false +>true : true + +type A3 = And; // false +>A3 : false +>And : If +>true : true +>false : false + +type A4 = And; // true +>A4 : true +>And : If +>true : true +>true : true + +type A5 = And; // false +>A5 : false +>And : If +>false : false + +type A6 = And; // false +>A6 : false +>And : If +>false : false + +type A7 = And; // boolean +>A7 : boolean +>And : If +>true : true + +type A8 = And; // boolean +>A8 : boolean +>And : If +>true : true + +type A9 = And; // boolean +>A9 : boolean +>And : If + +type O1 = Or; // false +>O1 : false +>Or : If +>false : false +>false : false + +type O2 = Or; // true +>O2 : true +>Or : If +>false : false +>true : true + +type O3 = Or; // true +>O3 : true +>Or : If +>true : true +>false : false + +type O4 = Or; // true +>O4 : true +>Or : If +>true : true +>true : true + +type O5 = Or; // boolean +>O5 : boolean +>Or : If +>false : false + +type O6 = Or; // boolean +>O6 : boolean +>Or : If +>false : false + +type O7 = Or; // true +>O7 : true +>Or : If +>true : true + +type O8 = Or; // true +>O8 : true +>Or : If +>true : true + +type O9 = Or; // boolean +>O9 : boolean +>Or : If + From fc7d1c39482d9af525a773e5d4a18a176184fcf8 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 20 Jan 2018 15:32:26 -0800 Subject: [PATCH 33/39] Revise comments --- src/compiler/checker.ts | 16 ++++++++-------- src/compiler/types.ts | 3 ++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d0fe701760dee..2ecdefbf7f2bd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6965,7 +6965,7 @@ namespace ts { } // This function replaces substitution types with their underlying type parameters. We erase when creating - // type references and type alias instantiations because subsitution types are no longer necessary once + // type references and type alias instantiations because substitution types are no longer necessary once // the type arguments have been validated against their corresponding type parameter constraints. function eraseSubstitutionType(type: Type) { return type.flags & TypeFlags.Substitution ? (type).typeParameter : type; @@ -14621,7 +14621,7 @@ namespace ts { checkExternalEmitHelpers(memberDecl, ExternalEmitHelpers.Assign); } if (propertiesArray.length > 0) { - spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, propagatedFlags, 0); + spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, propagatedFlags, /*objectFlags*/ 0); propertiesArray = []; propertiesTable = createSymbolTable(); hasComputedStringProperty = false; @@ -14633,7 +14633,7 @@ namespace ts { error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); return unknownType; } - spread = getSpreadType(spread, type, node.symbol, propagatedFlags, 0); + spread = getSpreadType(spread, type, node.symbol, propagatedFlags, /*objectFlags*/ 0); offset = i + 1; continue; } @@ -14678,7 +14678,7 @@ namespace ts { if (spread !== emptyObjectType) { if (propertiesArray.length > 0) { - spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, propagatedFlags, 0); + spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, propagatedFlags, /*objectFlags*/ 0); } return spread; } @@ -14811,7 +14811,7 @@ namespace ts { else { Debug.assert(attributeDecl.kind === SyntaxKind.JsxSpreadAttribute); if (attributesTable.size > 0) { - spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, 0, ObjectFlags.JsxAttributes); + spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, /*typeFlags*/ 0, ObjectFlags.JsxAttributes); attributesTable = createSymbolTable(); } const exprType = checkExpressionCached(attributeDecl.expression, checkMode); @@ -14819,7 +14819,7 @@ namespace ts { hasSpreadAnyType = true; } if (isValidSpreadType(exprType)) { - spread = getSpreadType(spread, exprType, openingLikeElement.symbol, 0, ObjectFlags.JsxAttributes); + spread = getSpreadType(spread, exprType, openingLikeElement.symbol, /*typeFlags*/ 0, ObjectFlags.JsxAttributes); } else { typeToIntersect = typeToIntersect ? getIntersectionType([typeToIntersect, exprType]) : exprType; @@ -14829,7 +14829,7 @@ namespace ts { if (!hasSpreadAnyType) { if (attributesTable.size > 0) { - spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, 0, ObjectFlags.JsxAttributes); + spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, /*typeFlags*/ 0, ObjectFlags.JsxAttributes); } } @@ -14855,7 +14855,7 @@ namespace ts { const childPropMap = createSymbolTable(); childPropMap.set(jsxChildrenPropertyName, childrenPropSymbol); spread = getSpreadType(spread, createAnonymousType(attributes.symbol, childPropMap, emptyArray, emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined), - attributes.symbol, 0, ObjectFlags.JsxAttributes); + attributes.symbol, /*typeFlags*/ 0, ObjectFlags.JsxAttributes); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index b9f3638724355..13c9f151fec7e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3804,7 +3804,8 @@ namespace ts { // Substitution types are created for type parameter references that occur in the true branch // of a conditional type. For example, in 'T extends string ? Foo : Bar', the reference to // T in Foo is resolved as a substitution type that substitutes 'string & T' for T. Thus, if - // Foo has a 'string' constraint on its type parameter, T will satisfy it. + // Foo has a 'string' constraint on its type parameter, T will satisfy it. Substitution types + // disappear upon instantiation (just like type parameters). export interface SubstitutionType extends InstantiableType { typeParameter: TypeParameter; // Target type parameter substitute: Type; // Type to substitute for type parameter From f19959afd4b182881160f2fcea1c790e6f8daac5 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 20 Jan 2018 15:58:52 -0800 Subject: [PATCH 34/39] Cache substitution types and remove erasure that was too eager --- src/compiler/checker.ts | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2ecdefbf7f2bd..010ee5663d04b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -303,6 +303,7 @@ namespace ts { const literalTypes = createMap(); const indexedAccessTypes = createMap(); const conditionalTypes = createMap(); + const substitutionTypes = createMap(); const evolvingArrayTypes: EvolvingArrayType[] = []; const undefinedProperties = createMap() as UnderscoreEscapedMap; @@ -6964,15 +6965,7 @@ namespace ts { return result & TypeFlags.PropagatingFlags; } - // This function replaces substitution types with their underlying type parameters. We erase when creating - // type references and type alias instantiations because substitution types are no longer necessary once - // the type arguments have been validated against their corresponding type parameter constraints. - function eraseSubstitutionType(type: Type) { - return type.flags & TypeFlags.Substitution ? (type).typeParameter : type; - } - function createTypeReference(target: GenericType, typeArguments: Type[]): TypeReference { - typeArguments = sameMap(typeArguments, eraseSubstitutionType); const id = getTypeListId(typeArguments); let type = target.instantiations.get(id); if (!type) { @@ -7039,7 +7032,6 @@ namespace ts { } function getTypeAliasInstantiation(symbol: Symbol, typeArguments: Type[]): Type { - typeArguments = sameMap(typeArguments, eraseSubstitutionType); const type = getDeclaredTypeOfSymbol(symbol); const links = getSymbolLinks(symbol); const typeParameters = links.typeParameters; @@ -7163,6 +7155,19 @@ namespace ts { } } + function getSubstitutionType(typeParameter: TypeParameter, substitute: Type) { + const id = typeParameter.id + "," + substitute.id; + const cached = substitutionTypes.get(id); + if (cached) { + return cached; + } + const result = createType(TypeFlags.Substitution); + result.typeParameter = typeParameter; + result.substitute = substitute; + substitutionTypes.set(id, result); + return result; + } + function getConstrainedTypeParameter(typeParameter: TypeParameter, node: Node) { let constraints: Type[]; while (isTypeNode(node)) { @@ -7174,13 +7179,7 @@ namespace ts { } node = parent; } - if (constraints) { - const result = createType(TypeFlags.Substitution); - result.typeParameter = typeParameter; - result.substitute = getIntersectionType(append(constraints, typeParameter)); - return result; - } - return typeParameter; + return constraints ? getSubstitutionType(typeParameter, getIntersectionType(append(constraints, typeParameter))) : typeParameter; } function isJSDocTypeReference(node: TypeReferenceType): node is TypeReferenceNode { @@ -8082,6 +8081,10 @@ namespace ts { return links.resolvedType; } + function getActualTypeParameter(type: Type) { + return type.flags & TypeFlags.Substitution ? (type).typeParameter : type; + } + function createConditionalType(checkType: Type, extendsType: Type, trueType: Type, falseType: Type, target: ConditionalType, mapper: TypeMapper, aliasSymbol: Symbol, aliasTypeArguments: Type[]) { const type = createType(TypeFlags.Conditional); type.checkType = checkType; @@ -8113,7 +8116,7 @@ namespace ts { return falseType; } // Return a deferred type for a check that is neither definitely true nor definitely false - return createConditionalType(eraseSubstitutionType(checkType), extendsType, trueType, falseType, + return createConditionalType(getActualTypeParameter(checkType), extendsType, trueType, falseType, /*target*/ undefined, /*mapper*/ undefined, aliasSymbol, aliasTypeArguments); } @@ -8724,7 +8727,7 @@ namespace ts { return instantiateType(type.falseType, mapper); } // Return a deferred type for a check that is neither definitely true nor definitely false - const erasedCheckType = eraseSubstitutionType(checkType); + const erasedCheckType = getActualTypeParameter(checkType); const trueType = instantiateType(type.trueType, mapper); const falseType = instantiateType(type.falseType, mapper); const id = type.id + "," + erasedCheckType.id + "," + extendsType.id + "," + trueType.id + "," + falseType.id; @@ -8773,7 +8776,7 @@ namespace ts { return getConditionalTypeInstantiation(type, mapper); } if (type.flags & TypeFlags.Substitution) { - return instantiateType((type).typeParameter, mapper); + return mapper((type).typeParameter); } } return type; From b8692901f215eaf6572413cb071569acbde218f8 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 21 Jan 2018 08:03:30 -0800 Subject: [PATCH 35/39] Remove unnecessary caching of substitution types --- src/compiler/checker.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 010ee5663d04b..d7a0da1843a9d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -303,7 +303,6 @@ namespace ts { const literalTypes = createMap(); const indexedAccessTypes = createMap(); const conditionalTypes = createMap(); - const substitutionTypes = createMap(); const evolvingArrayTypes: EvolvingArrayType[] = []; const undefinedProperties = createMap() as UnderscoreEscapedMap; @@ -7156,15 +7155,9 @@ namespace ts { } function getSubstitutionType(typeParameter: TypeParameter, substitute: Type) { - const id = typeParameter.id + "," + substitute.id; - const cached = substitutionTypes.get(id); - if (cached) { - return cached; - } const result = createType(TypeFlags.Substitution); result.typeParameter = typeParameter; result.substitute = substitute; - substitutionTypes.set(id, result); return result; } From 4c7ec3c51aee6b9caa35084f60c15afeba5315b3 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 21 Jan 2018 12:45:02 -0800 Subject: [PATCH 36/39] Shared code path for getConditionalType and instantiateConditionalType --- src/compiler/checker.ts | 57 +++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 34 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d7a0da1843a9d..cabe140ad1151 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8091,26 +8091,38 @@ namespace ts { return type; } - function getConditionalType(checkType: Type, extendsType: Type, trueType: Type, falseType: Type, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type { + function getConditionalType(checkType: Type, extendsType: Type, baseTrueType: Type, baseFalseType: Type, target: ConditionalType, mapper: TypeMapper, aliasSymbol?: Symbol, baseAliasTypeArguments?: Type[]): Type { // Distribute union types over conditional types if (checkType.flags & TypeFlags.Union) { - return getUnionType(map((checkType).types, t => getConditionalType(t, extendsType, trueType, falseType))); + return getUnionType(map((checkType).types, t => getConditionalType(t, extendsType, baseTrueType, baseFalseType, target, mapper))); } // Return union of trueType and falseType for any and never since they match anything if (checkType.flags & (TypeFlags.Any | TypeFlags.Never)) { - return getUnionType([trueType, falseType]); + return getUnionType([instantiateType(baseTrueType, mapper), instantiateType(baseFalseType, mapper)]); } // Return trueType for a definitely true extends check if (isTypeAssignableTo(checkType, extendsType)) { - return trueType; + return instantiateType(baseTrueType, mapper); } // Return falseType for a definitely false extends check if (!typeMaybeAssignableTo(instantiateType(checkType, anyMapper), instantiateType(extendsType, constraintMapper))) { - return falseType; + return instantiateType(baseFalseType, mapper); } // Return a deferred type for a check that is neither definitely true nor definitely false - return createConditionalType(getActualTypeParameter(checkType), extendsType, trueType, falseType, - /*target*/ undefined, /*mapper*/ undefined, aliasSymbol, aliasTypeArguments); + const erasedCheckType = getActualTypeParameter(checkType); + const trueType = instantiateType(baseTrueType, mapper); + const falseType = instantiateType(baseFalseType, mapper); + const id = target && (target.id + "," + erasedCheckType.id + "," + extendsType.id + "," + trueType.id + "," + falseType.id); + const cached = id && conditionalTypes.get(id); + if (cached) { + return cached; + } + const result = createConditionalType(erasedCheckType, extendsType, trueType, falseType, + target, mapper, aliasSymbol, instantiateTypes(baseAliasTypeArguments, mapper)); + if (id) { + conditionalTypes.set(id, result); + } + return result; } function getTypeFromConditionalTypeNode(node: ConditionalTypeNode): Type { @@ -8119,6 +8131,7 @@ namespace ts { links.resolvedType = getConditionalType( getTypeFromTypeNode(node.checkType), getTypeFromTypeNode(node.extendsType), getTypeFromTypeNode(node.trueType), getTypeFromTypeNode(node.falseType), + /*target*/ undefined, /*mapper*/ undefined, getAliasSymbolForTypeNode(node), getAliasTypeArgumentsForTypeNode(node)); } return links.resolvedType; @@ -8705,36 +8718,12 @@ namespace ts { } function instantiateConditionalType(type: ConditionalType, mapper: TypeMapper): Type { - const checkType = instantiateType(type.checkType, mapper); - // Return union of trueType and falseType for any and never since they match anything - if (checkType.flags & (TypeFlags.Any | TypeFlags.Never)) { - return getUnionType([instantiateType(type.trueType, mapper), instantiateType(type.falseType, mapper)]); - } - const extendsType = instantiateType(type.extendsType, mapper); - // Return trueType for a definitely true extends check - if (isTypeAssignableTo(checkType, extendsType)) { - return instantiateType(type.trueType, mapper); - } - // Return falseType for a definitely false extends check - if (!typeMaybeAssignableTo(instantiateType(checkType, anyMapper), instantiateType(extendsType, constraintMapper))) { - return instantiateType(type.falseType, mapper); - } - // Return a deferred type for a check that is neither definitely true nor definitely false - const erasedCheckType = getActualTypeParameter(checkType); - const trueType = instantiateType(type.trueType, mapper); - const falseType = instantiateType(type.falseType, mapper); - const id = type.id + "," + erasedCheckType.id + "," + extendsType.id + "," + trueType.id + "," + falseType.id; - let result = conditionalTypes.get(id); - if (!result) { - result = createConditionalType(erasedCheckType, extendsType, trueType, falseType, - type, mapper, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)); - conditionalTypes.set(id, result); - } - return result; + return getConditionalType(instantiateType(type.checkType, mapper), instantiateType(type.extendsType, mapper), + type.trueType, type.falseType, type, mapper, type.aliasSymbol, type.aliasTypeArguments); } function instantiateType(type: Type, mapper: TypeMapper): Type { - if (type && mapper !== identityMapper) { + if (type && mapper && mapper !== identityMapper) { if (type.flags & TypeFlags.TypeParameter) { return mapper(type); } From b42c6b1db661f413f136195c3e5da95639f0657c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 24 Jan 2018 13:50:31 -0800 Subject: [PATCH 37/39] Only conditional types that check naked type parameter distribute over unions --- src/compiler/checker.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cabe140ad1151..8798b22bfdf36 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8092,10 +8092,6 @@ namespace ts { } function getConditionalType(checkType: Type, extendsType: Type, baseTrueType: Type, baseFalseType: Type, target: ConditionalType, mapper: TypeMapper, aliasSymbol?: Symbol, baseAliasTypeArguments?: Type[]): Type { - // Distribute union types over conditional types - if (checkType.flags & TypeFlags.Union) { - return getUnionType(map((checkType).types, t => getConditionalType(t, extendsType, baseTrueType, baseFalseType, target, mapper))); - } // Return union of trueType and falseType for any and never since they match anything if (checkType.flags & (TypeFlags.Any | TypeFlags.Never)) { return getUnionType([instantiateType(baseTrueType, mapper), instantiateType(baseFalseType, mapper)]); @@ -8105,7 +8101,7 @@ namespace ts { return instantiateType(baseTrueType, mapper); } // Return falseType for a definitely false extends check - if (!typeMaybeAssignableTo(instantiateType(checkType, anyMapper), instantiateType(extendsType, constraintMapper))) { + if (!isTypeAssignableTo(instantiateType(checkType, anyMapper), instantiateType(extendsType, constraintMapper))) { return instantiateType(baseFalseType, mapper); } // Return a deferred type for a check that is neither definitely true nor definitely false @@ -8704,8 +8700,8 @@ namespace ts { function getConditionalTypeInstantiation(type: ConditionalType, mapper: TypeMapper): Type { const target = type.target || type; const combinedMapper = type.mapper ? combineTypeMappers(type.mapper, mapper) : mapper; - // Check if we have a conditional type of the form T extends U ? X : Y, where T is a type parameter. - // If so, the conditional type is distributive over a union type and when T is instantiated to a union + // Check if we have a conditional type where the check type is a naked type parameter. If so, + // the conditional type is distributive over union types and when T is instantiated to a union // type A | B, we produce (A extends U ? X : Y) | (B extends U ? X : Y). const checkType = target.checkType; if (checkType.flags & TypeFlags.TypeParameter) { From 8e337b5121ec9243c07c014e315cfce9b2be597f Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 24 Jan 2018 13:51:37 -0800 Subject: [PATCH 38/39] Fix bug in resolveMappedTypeMembers --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8798b22bfdf36..6fe8f5d2e141c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5788,7 +5788,7 @@ namespace ts { // and T as the template type. const typeParameter = getTypeParameterFromMappedType(type); const constraintType = getConstraintTypeFromMappedType(type); - const templateType = getTemplateTypeFromMappedType(type); + const templateType = getTemplateTypeFromMappedType(type.target || type); const modifiersType = getApparentType(getModifiersTypeFromMappedType(type)); // The 'T' in 'keyof T' const templateReadonly = !!type.declaration.readonlyToken; const templateOptional = !!type.declaration.questionToken; From 01516c84d2ce87c387b3bf037af2e90a25a6c213 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 30 Jan 2018 06:47:58 -0800 Subject: [PATCH 39/39] Update to use TypeFlags.Instantiable in instantiateSymbol --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8c97259107b81..a6c0e436e8d3b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8591,7 +8591,7 @@ namespace ts { function instantiateSymbol(symbol: Symbol, mapper: TypeMapper): Symbol { const links = getSymbolLinks(symbol); - if (links.type && !maybeTypeOfKind(links.type, TypeFlags.Object | TypeFlags.TypeVariable | TypeFlags.Index)) { + if (links.type && !maybeTypeOfKind(links.type, TypeFlags.Object | TypeFlags.Instantiable)) { // If the type of the symbol is already resolved, and if that type could not possibly // be affected by instantiation, simply return the symbol itself. return symbol;