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; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy