diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 318cada64e5a2..9b69ac443395e 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -909,6 +909,9 @@ namespace ts { let currentParenthesizerRule: ((node: Node) => Node) | undefined; const { enter: enterComment, exit: exitComment } = performance.createTimerIf(extendedDiagnostics, "commentTime", "beforeComment", "afterComment"); const parenthesizer = factory.parenthesizer; + const typeArgumentParenthesizerRuleSelector: OrdinalParentheizerRuleSelector = { + select: index => index === 0 ? parenthesizer.parenthesizeLeadingTypeArgument : undefined + }; const emitBinaryExpression = createEmitBinaryExpression(); reset(); @@ -2240,7 +2243,7 @@ namespace ts { } function emitArrayType(node: ArrayTypeNode) { - emit(node.elementType, parenthesizer.parenthesizeElementTypeOfArrayType); + emit(node.elementType, parenthesizer.parenthesizeNonArrayTypeOfPostfixType); writePunctuation("["); writePunctuation("]"); } @@ -2253,7 +2256,7 @@ namespace ts { function emitTupleType(node: TupleTypeNode) { emitTokenWithComment(SyntaxKind.OpenBracketToken, node.pos, writePunctuation, node); const flags = getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTupleTypeElements : ListFormat.MultiLineTupleTypeElements; - emitList(node, node.elements, flags | ListFormat.NoSpaceIfEmpty); + emitList(node, node.elements, flags | ListFormat.NoSpaceIfEmpty, parenthesizer.parenthesizeElementTypeOfTupleType); emitTokenWithComment(SyntaxKind.CloseBracketToken, node.elements.end, writePunctuation, node); } @@ -2267,24 +2270,24 @@ namespace ts { } function emitOptionalType(node: OptionalTypeNode) { - emit(node.type, parenthesizer.parenthesizeElementTypeOfArrayType); + emit(node.type, parenthesizer.parenthesizeTypeOfOptionalType); writePunctuation("?"); } function emitUnionType(node: UnionTypeNode) { - emitList(node, node.types, ListFormat.UnionTypeConstituents, parenthesizer.parenthesizeMemberOfElementType); + emitList(node, node.types, ListFormat.UnionTypeConstituents, parenthesizer.parenthesizeConstituentTypeOfUnionType); } function emitIntersectionType(node: IntersectionTypeNode) { - emitList(node, node.types, ListFormat.IntersectionTypeConstituents, parenthesizer.parenthesizeMemberOfElementType); + emitList(node, node.types, ListFormat.IntersectionTypeConstituents, parenthesizer.parenthesizeConstituentTypeOfIntersectionType); } function emitConditionalType(node: ConditionalTypeNode) { - emit(node.checkType, parenthesizer.parenthesizeMemberOfConditionalType); + emit(node.checkType, parenthesizer.parenthesizeCheckTypeOfConditionalType); writeSpace(); writeKeyword("extends"); writeSpace(); - emit(node.extendsType, parenthesizer.parenthesizeMemberOfConditionalType); + emit(node.extendsType, parenthesizer.parenthesizeExtendsTypeOfConditionalType); writeSpace(); writePunctuation("?"); writeSpace(); @@ -2314,11 +2317,15 @@ namespace ts { function emitTypeOperator(node: TypeOperatorNode) { writeTokenText(node.operator, writeKeyword); writeSpace(); - emit(node.type, parenthesizer.parenthesizeMemberOfElementType); + + const parenthesizerRule = node.operator === SyntaxKind.ReadonlyKeyword ? + parenthesizer.parenthesizeOperandOfReadonlyTypeOperator : + parenthesizer.parenthesizeOperandOfTypeOperator; + emit(node.type, parenthesizerRule); } function emitIndexedAccessType(node: IndexedAccessTypeNode) { - emit(node.objectType, parenthesizer.parenthesizeMemberOfElementType); + emit(node.objectType, parenthesizer.parenthesizeNonArrayTypeOfPostfixType); writePunctuation("["); emit(node.indexType); writePunctuation("]"); @@ -4254,7 +4261,7 @@ namespace ts { } function emitTypeArguments(parentNode: Node, typeArguments: NodeArray | undefined) { - emitList(parentNode, typeArguments, ListFormat.TypeArguments, parenthesizer.parenthesizeMemberOfElementType); + emitList(parentNode, typeArguments, ListFormat.TypeArguments, typeArgumentParenthesizerRuleSelector); } function emitTypeParameters(parentNode: SignatureDeclaration | InterfaceDeclaration | TypeAliasDeclaration | ClassDeclaration | ClassExpression, typeParameters: NodeArray | undefined) { @@ -4322,15 +4329,15 @@ namespace ts { } } - function emitList(parentNode: Node | undefined, children: NodeArray | undefined, format: ListFormat, parenthesizerRule?: (node: Node) => Node, start?: number, count?: number) { + function emitList(parentNode: Node | undefined, children: NodeArray | undefined, format: ListFormat, parenthesizerRule?: ParenthesizerRuleOrSelector, start?: number, count?: number) { emitNodeList(emit, parentNode, children, format, parenthesizerRule, start, count); } - function emitExpressionList(parentNode: Node | undefined, children: NodeArray | undefined, format: ListFormat, parenthesizerRule?: (node: Expression) => Expression, start?: number, count?: number) { + function emitExpressionList(parentNode: Node | undefined, children: NodeArray | undefined, format: ListFormat, parenthesizerRule?: ParenthesizerRuleOrSelector, start?: number, count?: number) { emitNodeList(emitExpression, parentNode, children, format, parenthesizerRule, start, count); } - function emitNodeList(emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parentNode: Node | undefined, children: NodeArray | undefined, format: ListFormat, parenthesizerRule: ((node: Node) => Node) | undefined, start = 0, count = children ? children.length - start : 0) { + function emitNodeList(emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parentNode: Node | undefined, children: NodeArray | undefined, format: ListFormat, parenthesizerRule: ParenthesizerRuleOrSelector | undefined, start = 0, count = children ? children.length - start : 0) { const isUndefined = children === undefined; if (isUndefined && format & ListFormat.OptionalIfUndefined) { return; @@ -4386,6 +4393,8 @@ namespace ts { increaseIndent(); } + const emitListItem = getEmitListItem(emit, parenthesizerRule); + // Emit each child. let previousSibling: Node | undefined; let previousSourceFileTextKind: ReturnType; @@ -4441,12 +4450,7 @@ namespace ts { } nextListElementPos = child.pos; - if (emit.length === 1) { - emit(child); - } - else { - emit(child, parenthesizerRule); - } + emitListItem(child, emit, parenthesizerRule, i); if (shouldDecreaseIndentAfterEmit) { decreaseIndent(); @@ -5888,4 +5892,30 @@ namespace ts { CountMask = 0x0FFFFFFF, // Temp variable counter _i = 0x10000000, // Use/preference flag for '_i' } + + interface OrdinalParentheizerRuleSelector { + select(index: number): ((node: T) => T) | undefined; + } + + type ParenthesizerRule = (node: T) => T; + + type ParenthesizerRuleOrSelector = OrdinalParentheizerRuleSelector | ParenthesizerRule; + + function emitListItemNoParenthesizer(node: Node, emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, _parenthesizerRule: ParenthesizerRuleOrSelector | undefined, _index: number) { + emit(node); + } + + function emitListItemWithParenthesizerRuleSelector(node: Node, emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parenthesizerRuleSelector: OrdinalParentheizerRuleSelector, index: number) { + emit(node, parenthesizerRuleSelector.select(index)); + } + + function emitListItemWithParenthesizerRule(node: Node, emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parenthesizerRule: ParenthesizerRule | undefined, _index: number) { + emit(node, parenthesizerRule); + } + + function getEmitListItem | undefined>(emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parenthesizerRule: R): (node: Node, emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parenthesizerRule: R, index: number) => void { + return emit.length === 1 ? emitListItemNoParenthesizer : + typeof parenthesizerRule === "object" ? emitListItemWithParenthesizerRuleSelector : + emitListItemWithParenthesizerRule; + } } diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index 9164c69763ba0..5f7dbfbad522b 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -34,6 +34,8 @@ namespace ts { const getJSDocPrimaryTypeCreateFunction = memoizeOne((kind: T["kind"]) => () => createJSDocPrimaryTypeWorker(kind)); const getJSDocUnaryTypeCreateFunction = memoizeOne((kind: T["kind"]) => (type: T["type"]) => createJSDocUnaryTypeWorker(kind, type)); const getJSDocUnaryTypeUpdateFunction = memoizeOne((kind: T["kind"]) => (node: T, type: T["type"]) => updateJSDocUnaryTypeWorker(kind, node, type)); + const getJSDocPrePostfixUnaryTypeCreateFunction = memoizeOne((kind: T["kind"]) => (type: T["type"], postfix?: boolean) => createJSDocPrePostfixUnaryTypeWorker(kind, type, postfix)); + const getJSDocPrePostfixUnaryTypeUpdateFunction = memoizeOne((kind: T["kind"]) => (node: T, type: T["type"]) => updateJSDocPrePostfixUnaryTypeWorker(kind, node, type)); const getJSDocSimpleTagCreateFunction = memoizeOne((kind: T["kind"]) => (tagName: Identifier | undefined, comment?: NodeArray) => createJSDocSimpleTagWorker(kind, tagName, comment)); const getJSDocSimpleTagUpdateFunction = memoizeOne((kind: T["kind"]) => (node: T, tagName: Identifier | undefined, comment?: NodeArray) => updateJSDocSimpleTagWorker(kind, node, tagName, comment)); const getJSDocTypeLikeTagCreateFunction = memoizeOne((kind: T["kind"]) => (tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, comment?: NodeArray) => createJSDocTypeLikeTagWorker(kind, tagName, typeExpression, comment)); @@ -317,10 +319,10 @@ namespace ts { // lazily load factory members for JSDoc types with similar structure get createJSDocAllType() { return getJSDocPrimaryTypeCreateFunction(SyntaxKind.JSDocAllType); }, get createJSDocUnknownType() { return getJSDocPrimaryTypeCreateFunction(SyntaxKind.JSDocUnknownType); }, - get createJSDocNonNullableType() { return getJSDocUnaryTypeCreateFunction(SyntaxKind.JSDocNonNullableType); }, - get updateJSDocNonNullableType() { return getJSDocUnaryTypeUpdateFunction(SyntaxKind.JSDocNonNullableType); }, - get createJSDocNullableType() { return getJSDocUnaryTypeCreateFunction(SyntaxKind.JSDocNullableType); }, - get updateJSDocNullableType() { return getJSDocUnaryTypeUpdateFunction(SyntaxKind.JSDocNullableType); }, + get createJSDocNonNullableType() { return getJSDocPrePostfixUnaryTypeCreateFunction(SyntaxKind.JSDocNonNullableType); }, + get updateJSDocNonNullableType() { return getJSDocPrePostfixUnaryTypeUpdateFunction(SyntaxKind.JSDocNonNullableType); }, + get createJSDocNullableType() { return getJSDocPrePostfixUnaryTypeCreateFunction(SyntaxKind.JSDocNullableType); }, + get updateJSDocNullableType() { return getJSDocPrePostfixUnaryTypeUpdateFunction(SyntaxKind.JSDocNullableType); }, get createJSDocOptionalType() { return getJSDocUnaryTypeCreateFunction(SyntaxKind.JSDocOptionalType); }, get updateJSDocOptionalType() { return getJSDocUnaryTypeUpdateFunction(SyntaxKind.JSDocOptionalType); }, get createJSDocVariadicType() { return getJSDocUnaryTypeCreateFunction(SyntaxKind.JSDocVariadicType); }, @@ -1875,7 +1877,7 @@ namespace ts { // @api function createArrayTypeNode(elementType: TypeNode) { const node = createBaseNode(SyntaxKind.ArrayType); - node.elementType = parenthesizerRules().parenthesizeElementTypeOfArrayType(elementType); + node.elementType = parenthesizerRules().parenthesizeNonArrayTypeOfPostfixType(elementType); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } @@ -1890,7 +1892,7 @@ namespace ts { // @api function createTupleTypeNode(elements: readonly (TypeNode | NamedTupleMember)[]) { const node = createBaseNode(SyntaxKind.TupleType); - node.elements = createNodeArray(elements); + node.elements = createNodeArray(parenthesizerRules().parenthesizeElementTypesOfTupleType(elements)); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } @@ -1926,7 +1928,7 @@ namespace ts { // @api function createOptionalTypeNode(type: TypeNode) { const node = createBaseNode(SyntaxKind.OptionalType); - node.type = parenthesizerRules().parenthesizeElementTypeOfArrayType(type); + node.type = parenthesizerRules().parenthesizeTypeOfOptionalType(type); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } @@ -1953,44 +1955,44 @@ namespace ts { : node; } - function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: readonly TypeNode[]) { + function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: readonly TypeNode[], parenthesize: (nodes: readonly TypeNode[]) => readonly TypeNode[]) { const node = createBaseNode(kind); - node.types = parenthesizerRules().parenthesizeConstituentTypesOfUnionOrIntersectionType(types); + node.types = factory.createNodeArray(parenthesize(types)); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } - function updateUnionOrIntersectionTypeNode(node: T, types: NodeArray): T { + function updateUnionOrIntersectionTypeNode(node: T, types: NodeArray, parenthesize: (nodes: readonly TypeNode[]) => readonly TypeNode[]): T { return node.types !== types - ? update(createUnionOrIntersectionTypeNode(node.kind, types) as T, node) + ? update(createUnionOrIntersectionTypeNode(node.kind, types, parenthesize) as T, node) : node; } // @api function createUnionTypeNode(types: readonly TypeNode[]): UnionTypeNode { - return createUnionOrIntersectionTypeNode(SyntaxKind.UnionType, types) as UnionTypeNode; + return createUnionOrIntersectionTypeNode(SyntaxKind.UnionType, types, parenthesizerRules().parenthesizeConstituentTypesOfUnionType) as UnionTypeNode; } // @api function updateUnionTypeNode(node: UnionTypeNode, types: NodeArray) { - return updateUnionOrIntersectionTypeNode(node, types); + return updateUnionOrIntersectionTypeNode(node, types, parenthesizerRules().parenthesizeConstituentTypesOfUnionType); } // @api function createIntersectionTypeNode(types: readonly TypeNode[]): IntersectionTypeNode { - return createUnionOrIntersectionTypeNode(SyntaxKind.IntersectionType, types) as IntersectionTypeNode; + return createUnionOrIntersectionTypeNode(SyntaxKind.IntersectionType, types, parenthesizerRules().parenthesizeConstituentTypesOfIntersectionType) as IntersectionTypeNode; } // @api function updateIntersectionTypeNode(node: IntersectionTypeNode, types: NodeArray) { - return updateUnionOrIntersectionTypeNode(node, types); + return updateUnionOrIntersectionTypeNode(node, types, parenthesizerRules().parenthesizeConstituentTypesOfIntersectionType); } // @api function createConditionalTypeNode(checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode) { const node = createBaseNode(SyntaxKind.ConditionalType); node.checkType = parenthesizerRules().parenthesizeCheckTypeOfConditionalType(checkType); - node.extendsType = parenthesizerRules().parenthesizeMemberOfConditionalType(extendsType); + node.extendsType = parenthesizerRules().parenthesizeExtendsTypeOfConditionalType(extendsType); node.trueType = trueType; node.falseType = falseType; node.transformFlags = TransformFlags.ContainsTypeScript; @@ -2117,7 +2119,9 @@ namespace ts { function createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, type: TypeNode): TypeOperatorNode { const node = createBaseNode(SyntaxKind.TypeOperator); node.operator = operator; - node.type = parenthesizerRules().parenthesizeMemberOfElementType(type); + node.type = operator === SyntaxKind.ReadonlyKeyword ? + parenthesizerRules().parenthesizeOperandOfReadonlyTypeOperator(type) : + parenthesizerRules().parenthesizeOperandOfTypeOperator(type); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } @@ -2132,7 +2136,7 @@ namespace ts { // @api function createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode) { const node = createBaseNode(SyntaxKind.IndexedAccessType); - node.objectType = parenthesizerRules().parenthesizeMemberOfElementType(objectType); + node.objectType = parenthesizerRules().parenthesizeNonArrayTypeOfPostfixType(objectType); node.indexType = indexType; node.transformFlags = TransformFlags.ContainsTypeScript; return node; @@ -4323,12 +4327,21 @@ namespace ts { } // @api - // createJSDocNonNullableType // createJSDocNullableType + // createJSDocNonNullableType + function createJSDocPrePostfixUnaryTypeWorker(kind: T["kind"], type: T["type"], postfix = false): T { + const node = createJSDocUnaryTypeWorker( + kind, + postfix ? type && parenthesizerRules().parenthesizeNonArrayTypeOfPostfixType(type) : type + ) as Mutable; + node.postfix = postfix; + return node; + } + + // @api // createJSDocOptionalType // createJSDocVariadicType // createJSDocNamepathType - function createJSDocUnaryTypeWorker(kind: T["kind"], type: T["type"]): T { const node = createBaseNode(kind); node.type = type; @@ -4338,6 +4351,13 @@ namespace ts { // @api // updateJSDocNonNullableType // updateJSDocNullableType + function updateJSDocPrePostfixUnaryTypeWorker(kind: T["kind"], node: T, type: T["type"]): T { + return node.type !== type + ? update(createJSDocPrePostfixUnaryTypeWorker(kind, type, node.postfix), node) + : node; + } + + // @api // updateJSDocOptionalType // updateJSDocVariadicType // updateJSDocNamepathType diff --git a/src/compiler/factory/parenthesizerRules.ts b/src/compiler/factory/parenthesizerRules.ts index e921f08bfc69f..9f42496cc17cb 100644 --- a/src/compiler/factory/parenthesizerRules.ts +++ b/src/compiler/factory/parenthesizerRules.ts @@ -26,11 +26,19 @@ namespace ts { parenthesizeExpressionOfExpressionStatement, parenthesizeConciseBodyOfArrowFunction, parenthesizeCheckTypeOfConditionalType, - parenthesizeMemberOfConditionalType, - parenthesizeMemberOfElementType, - parenthesizeElementTypeOfArrayType, - parenthesizeConstituentTypesOfUnionOrIntersectionType, + parenthesizeExtendsTypeOfConditionalType, + parenthesizeConstituentTypesOfUnionType, + parenthesizeConstituentTypeOfUnionType, + parenthesizeConstituentTypesOfIntersectionType, + parenthesizeConstituentTypeOfIntersectionType, + parenthesizeOperandOfTypeOperator, + parenthesizeOperandOfReadonlyTypeOperator, + parenthesizeNonArrayTypeOfPostfixType, + parenthesizeElementTypesOfTupleType, + parenthesizeElementTypeOfTupleType, + parenthesizeTypeOfOptionalType, parenthesizeTypeArguments, + parenthesizeLeadingTypeArgument, }; function getParenthesizeLeftSideOfBinaryForOperator(operatorKind: BinaryOperator) { @@ -389,43 +397,197 @@ namespace ts { return body; } - function parenthesizeCheckTypeOfConditionalType(member: TypeNode): TypeNode { - return isInferTypeNode(member) ? factory.createParenthesizedType(member) : - parenthesizeMemberOfConditionalType(member); + // Type[Extends] : + // FunctionOrConstructorType + // ConditionalType[?Extends] + + // ConditionalType[Extends] : + // UnionType[?Extends] + // [~Extends] UnionType[~Extends] `extends` Type[+Extends] `?` Type[~Extends] `:` Type[~Extends] + // + // - The check type (the `UnionType`, above) does not allow function, constructor, or conditional types (they must be parenthesized) + // - The extends type (the first `Type`, above) does not allow conditional types (they must be parenthesized). Function and constructor types are fine. + // - The true and false branch types (the second and third `Type` non-terminals, above) allow any type + function parenthesizeCheckTypeOfConditionalType(checkType: TypeNode): TypeNode { + switch (checkType.kind) { + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + case SyntaxKind.ConditionalType: + return factory.createParenthesizedType(checkType); + } + return checkType; + } + + function parenthesizeExtendsTypeOfConditionalType(extendsType: TypeNode): TypeNode { + switch (extendsType.kind) { + case SyntaxKind.ConditionalType: + return factory.createParenthesizedType(extendsType); + } + return extendsType; + } + + // UnionType[Extends] : + // `|`? IntersectionType[?Extends] + // UnionType[?Extends] `|` IntersectionType[?Extends] + // + // - A union type constituent has the same precedence as the check type of a conditional type + function parenthesizeConstituentTypeOfUnionType(type: TypeNode) { + switch (type.kind) { + case SyntaxKind.UnionType: // Not strictly necessary, but a union containing a union should have been flattened + return factory.createParenthesizedType(type); + } + return parenthesizeCheckTypeOfConditionalType(type); } - function parenthesizeMemberOfConditionalType(member: TypeNode): TypeNode { - return member.kind === SyntaxKind.ConditionalType ? factory.createParenthesizedType(member) : member; + function parenthesizeConstituentTypesOfUnionType(members: readonly TypeNode[]): NodeArray { + return factory.createNodeArray(sameMap(members, parenthesizeConstituentTypeOfUnionType)); } - function parenthesizeMemberOfElementType(member: TypeNode): TypeNode { - switch (member.kind) { + // IntersectionType[Extends] : + // `&`? TypeOperator[?Extends] + // IntersectionType[?Extends] `&` TypeOperator[?Extends] + // + // - An intersection type constituent does not allow function, constructor, conditional, or union types (they must be parenthesized) + function parenthesizeConstituentTypeOfIntersectionType(type: TypeNode) { + switch (type.kind) { case SyntaxKind.UnionType: + case SyntaxKind.IntersectionType: // Not strictly necessary, but an intersection containing an intersection should have been flattened + return factory.createParenthesizedType(type); + } + return parenthesizeConstituentTypeOfUnionType(type); + } + + function parenthesizeConstituentTypesOfIntersectionType(members: readonly TypeNode[]): NodeArray { + return factory.createNodeArray(sameMap(members, parenthesizeConstituentTypeOfIntersectionType)); + } + + // TypeOperator[Extends] : + // PostfixType + // InferType[?Extends] + // `keyof` TypeOperator[?Extends] + // `unique` TypeOperator[?Extends] + // `readonly` TypeOperator[?Extends] + // + function parenthesizeOperandOfTypeOperator(type: TypeNode) { + switch (type.kind) { case SyntaxKind.IntersectionType: - case SyntaxKind.FunctionType: - case SyntaxKind.ConstructorType: - return factory.createParenthesizedType(member); + return factory.createParenthesizedType(type); } - return parenthesizeMemberOfConditionalType(member); + return parenthesizeConstituentTypeOfIntersectionType(type); } - function parenthesizeElementTypeOfArrayType(member: TypeNode): TypeNode { - switch (member.kind) { - case SyntaxKind.TypeQuery: + function parenthesizeOperandOfReadonlyTypeOperator(type: TypeNode) { + switch (type.kind) { case SyntaxKind.TypeOperator: + return factory.createParenthesizedType(type); + } + return parenthesizeOperandOfTypeOperator(type); + } + + // PostfixType : + // NonArrayType + // NonArrayType [no LineTerminator here] `!` // JSDoc + // NonArrayType [no LineTerminator here] `?` // JSDoc + // IndexedAccessType + // ArrayType + // + // IndexedAccessType : + // NonArrayType `[` Type[~Extends] `]` + // + // ArrayType : + // NonArrayType `[` `]` + // + function parenthesizeNonArrayTypeOfPostfixType(type: TypeNode) { + switch (type.kind) { case SyntaxKind.InferType: - return factory.createParenthesizedType(member); + case SyntaxKind.TypeOperator: + return factory.createParenthesizedType(type); } - return parenthesizeMemberOfElementType(member); + return parenthesizeOperandOfTypeOperator(type); } - function parenthesizeConstituentTypesOfUnionOrIntersectionType(members: readonly TypeNode[]): NodeArray { - return factory.createNodeArray(sameMap(members, parenthesizeMemberOfElementType)); + // TupleType : + // `[` Elision? `]` + // `[` NamedTupleElementTypes `]` + // `[` NamedTupleElementTypes `,` Elision? `]` + // `[` TupleElementTypes `]` + // `[` TupleElementTypes `,` Elision? `]` + // + // NamedTupleElementTypes : + // Elision? NamedTupleMember + // NamedTupleElementTypes `,` Elision? NamedTupleMember + // + // NamedTupleMember : + // Identifier `?`? `:` Type[~Extends] + // `...` Identifier `:` Type[~Extends] + // + // TupleElementTypes : + // Elision? TupleElementType + // TupleElementTypes `,` Elision? TupleElementType + // + // TupleElementType : + // Type[~Extends] // NOTE: Needs cover grammar to disallow JSDoc postfix-optional + // OptionalType + // RestType + // + // OptionalType : + // Type[~Extends] `?` // NOTE: Needs cover grammar to disallow JSDoc postfix-optional + // + // RestType : + // `...` Type[~Extends] + // + function parenthesizeElementTypesOfTupleType(types: readonly (TypeNode | NamedTupleMember)[]): NodeArray { + return factory.createNodeArray(sameMap(types, parenthesizeElementTypeOfTupleType)); + } + + function parenthesizeElementTypeOfTupleType(type: TypeNode | NamedTupleMember): TypeNode { + if (hasJSDocPostfixQuestion(type)) return factory.createParenthesizedType(type); + return type; + } + + function hasJSDocPostfixQuestion(type: TypeNode | NamedTupleMember): boolean { + if (isJSDocNullableType(type)) return type.postfix; + if (isNamedTupleMember(type)) return hasJSDocPostfixQuestion(type.type); + if (isFunctionTypeNode(type) || isConstructorTypeNode(type) || isTypeOperatorNode(type)) return hasJSDocPostfixQuestion(type.type); + if (isConditionalTypeNode(type)) return hasJSDocPostfixQuestion(type.falseType); + if (isUnionTypeNode(type)) return hasJSDocPostfixQuestion(last(type.types)); + if (isIntersectionTypeNode(type)) return hasJSDocPostfixQuestion(last(type.types)); + if (isInferTypeNode(type)) return !!type.typeParameter.constraint && hasJSDocPostfixQuestion(type.typeParameter.constraint); + return false; + } + + function parenthesizeTypeOfOptionalType(type: TypeNode): TypeNode { + if (hasJSDocPostfixQuestion(type)) return factory.createParenthesizedType(type); + return parenthesizeNonArrayTypeOfPostfixType(type); + } + // function parenthesizeMemberOfElementType(member: TypeNode): TypeNode { + // switch (member.kind) { + // case SyntaxKind.UnionType: + // case SyntaxKind.IntersectionType: + // case SyntaxKind.FunctionType: + // case SyntaxKind.ConstructorType: + // return factory.createParenthesizedType(member); + // } + // return parenthesizeMemberOfConditionalType(member); + // } + + // function parenthesizeElementTypeOfArrayType(member: TypeNode): TypeNode { + // switch (member.kind) { + // case SyntaxKind.TypeQuery: + // case SyntaxKind.TypeOperator: + // case SyntaxKind.InferType: + // return factory.createParenthesizedType(member); + // } + // return parenthesizeMemberOfElementType(member); + // } + + function parenthesizeLeadingTypeArgument(node: TypeNode) { + return isFunctionOrConstructorTypeNode(node) && node.typeParameters ? factory.createParenthesizedType(node) : node; } function parenthesizeOrdinalTypeArgument(node: TypeNode, i: number) { - return i === 0 && isFunctionOrConstructorTypeNode(node) && node.typeParameters ? factory.createParenthesizedType(node) : node; + return i === 0 ? parenthesizeLeadingTypeArgument(node) : node; } function parenthesizeTypeArguments(typeArguments: NodeArray | undefined): NodeArray | undefined { @@ -453,10 +615,18 @@ namespace ts { parenthesizeExpressionOfExpressionStatement: identity, parenthesizeConciseBodyOfArrowFunction: identity, parenthesizeCheckTypeOfConditionalType: identity, - parenthesizeMemberOfConditionalType: identity, - parenthesizeMemberOfElementType: identity, - parenthesizeElementTypeOfArrayType: identity, - parenthesizeConstituentTypesOfUnionOrIntersectionType: nodes => cast(nodes, isNodeArray), + parenthesizeExtendsTypeOfConditionalType: identity, + parenthesizeConstituentTypesOfUnionType: nodes => cast(nodes, isNodeArray), + parenthesizeConstituentTypeOfUnionType: identity, + parenthesizeConstituentTypesOfIntersectionType: nodes => cast(nodes, isNodeArray), + parenthesizeConstituentTypeOfIntersectionType: identity, + parenthesizeOperandOfTypeOperator: identity, + parenthesizeOperandOfReadonlyTypeOperator: identity, + parenthesizeNonArrayTypeOfPostfixType: identity, + parenthesizeElementTypesOfTupleType: nodes => cast(nodes, isNodeArray), + parenthesizeElementTypeOfTupleType: identity, + parenthesizeTypeOfOptionalType: identity, parenthesizeTypeArguments: nodes => nodes && cast(nodes, isNodeArray), + parenthesizeLeadingTypeArgument: identity, }; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 6d4f6dae7ff7d..a76b7d2783879 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1312,6 +1312,14 @@ namespace ts { return doInsideOfContext(NodeFlags.DisallowInContext, func); } + function allowConditionalTypesAnd(func: () => T): T { + return doOutsideOfContext(NodeFlags.DisallowConditionalTypesContext, func); + } + + function disallowConditionalTypesAnd(func: () => T): T { + return doInsideOfContext(NodeFlags.DisallowConditionalTypesContext, func); + } + function doInYieldContext(func: () => T): T { return doInsideOfContext(NodeFlags.YieldContext, func); } @@ -1348,6 +1356,10 @@ namespace ts { return inContext(NodeFlags.DisallowInContext); } + function inDisallowConditionalTypesContext() { + return inContext(NodeFlags.DisallowConditionalTypesContext); + } + function inDecoratorContext() { return inContext(NodeFlags.DecoratorContext); } @@ -2968,7 +2980,7 @@ namespace ts { function parseJSDocNonNullableType(): TypeNode { const pos = getNodePos(); nextToken(); - return finishNode(factory.createJSDocNonNullableType(parseNonArrayType()), pos); + return finishNode(factory.createJSDocNonNullableType(parseNonArrayType(), /*postfix*/ false), pos); } function parseJSDocUnknownOrNullableType(): JSDocUnknownType | JSDocNullableType { @@ -2995,7 +3007,7 @@ namespace ts { return finishNode(factory.createJSDocUnknownType(), pos); } else { - return finishNode(factory.createJSDocNullableType(parseType()), pos); + return finishNode(factory.createJSDocNullableType(parseType(), /*postfix*/ false), pos); } } @@ -3077,10 +3089,6 @@ namespace ts { } function parseTypeParameter(): TypeParameterDeclaration { - return parseTypeParameterWorker(/*canHaveDefault*/ true); - } - - function parseTypeParameterWorker(canHaveDefault: boolean): TypeParameterDeclaration { const pos = getNodePos(); const name = parseIdentifier(); let constraint: TypeNode | undefined; @@ -3105,7 +3113,7 @@ namespace ts { } } - const defaultType = canHaveDefault && parseOptional(SyntaxKind.EqualsToken) ? parseType() : undefined; + const defaultType = parseOptional(SyntaxKind.EqualsToken) ? parseType() : undefined; const node = factory.createTypeParameterDeclaration(name, constraint, defaultType); node.expression = expression; return finishNode(node, pos); @@ -3828,7 +3836,7 @@ namespace ts { switch (token()) { case SyntaxKind.ExclamationToken: nextToken(); - type = finishNode(factory.createJSDocNonNullableType(type), pos); + type = finishNode(factory.createJSDocNonNullableType(type, /*postfix*/ true), pos); break; case SyntaxKind.QuestionToken: // If next token is start of a type we have a conditional type @@ -3836,7 +3844,7 @@ namespace ts { return type; } nextToken(); - type = finishNode(factory.createJSDocNullableType(type), pos); + type = finishNode(factory.createJSDocNullableType(type, /*postfix*/ true), pos); break; case SyntaxKind.OpenBracketToken: parseExpected(SyntaxKind.OpenBracketToken); @@ -3863,10 +3871,28 @@ namespace ts { return finishNode(factory.createTypeOperatorNode(operator, parseTypeOperatorOrHigher()), pos); } + function tryParseConstraintOfInferType() { + if (parseOptional(SyntaxKind.ExtendsKeyword)) { + const constraint = disallowConditionalTypesAnd(parseType); + if (inDisallowConditionalTypesContext() || token() !== SyntaxKind.QuestionToken) { + return constraint; + } + } + } + + function parseTypeParameterOfInferType(): TypeParameterDeclaration { + const pos = getNodePos(); + const name = parseIdentifier(); + const constraint = tryParse(tryParseConstraintOfInferType); + const node = factory.createTypeParameterDeclaration(name, constraint); + node.expression = undefined; + return finishNode(node, pos); + } + function parseInferType(): InferTypeNode { const pos = getNodePos(); parseExpected(SyntaxKind.InferKeyword); - return finishNode(factory.createInferTypeNode(parseTypeParameterWorker(/*canHaveDefault*/ false)), pos); + return finishNode(factory.createInferTypeNode(parseTypeParameterOfInferType()), pos); } function parseTypeOperatorOrHigher(): TypeNode { @@ -3879,7 +3905,7 @@ namespace ts { case SyntaxKind.InferKeyword: return parseInferType(); } - return parsePostfixTypeOrHigher(); + return allowConditionalTypesAnd(parsePostfixTypeOrHigher); } function parseFunctionOrConstructorTypeToError( @@ -4028,24 +4054,22 @@ namespace ts { } function parseType(): TypeNode { - // The rules about 'yield' only apply to actual code/expression contexts. They don't - // apply to 'type' contexts. So we disable these parameters here before moving on. - return doOutsideOfContext(NodeFlags.TypeExcludesFlags, parseTypeWorker); - } + if (contextFlags & NodeFlags.TypeExcludesFlags) { + return doOutsideOfContext(NodeFlags.TypeExcludesFlags, parseType); + } - function parseTypeWorker(noConditionalTypes?: boolean): TypeNode { if (isStartOfFunctionTypeOrConstructorType()) { return parseFunctionOrConstructorType(); } const pos = getNodePos(); const type = parseUnionTypeOrHigher(); - if (!noConditionalTypes && !scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.ExtendsKeyword)) { + if (!inDisallowConditionalTypesContext() && !scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.ExtendsKeyword)) { // The type following 'extends' is not permitted to be another conditional type - const extendsType = parseTypeWorker(/*noConditionalTypes*/ true); + const extendsType = disallowConditionalTypesAnd(parseType); parseExpected(SyntaxKind.QuestionToken); - const trueType = parseTypeWorker(); + const trueType = allowConditionalTypesAnd(parseType); parseExpected(SyntaxKind.ColonToken); - const falseType = parseTypeWorker(); + const falseType = allowConditionalTypesAnd(parseType); return finishNode(factory.createConditionalTypeNode(type, extendsType, trueType, falseType), pos); } return type; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 74e7c8cd7858d..9ff329b78b825 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -757,10 +757,11 @@ namespace ts { YieldContext = 1 << 13, // If node was parsed in the 'yield' context created when parsing a generator DecoratorContext = 1 << 14, // If node was parsed as part of a decorator AwaitContext = 1 << 15, // If node was parsed in the 'await' context created when parsing an async function - ThisNodeHasError = 1 << 16, // If the parser encountered an error when parsing the code that created this node - JavaScriptFile = 1 << 17, // If node was parsed in a JavaScript - ThisNodeOrAnySubNodesHasError = 1 << 18, // If this node or any of its children had an error - HasAggregatedChildData = 1 << 19, // If we've computed data from children and cached it in this node + DisallowConditionalTypesContext = 1 << 16, // If node was parsed in a context where conditional types are not allowed + ThisNodeHasError = 1 << 17, // If the parser encountered an error when parsing the code that created this node + JavaScriptFile = 1 << 18, // If node was parsed in a JavaScript + ThisNodeOrAnySubNodesHasError = 1 << 19, // If this node or any of its children had an error + HasAggregatedChildData = 1 << 20, // If we've computed data from children and cached it in this node // These flags will be set when the parser encounters a dynamic import expression or 'import.meta' to avoid // walking the tree if the flags are not set. However, these flags are just a approximation @@ -771,15 +772,15 @@ namespace ts { // removal, it is likely that users will add the import anyway. // The advantage of this approach is its simplicity. For the case of batch compilation, // we guarantee that users won't have to pay the price of walking the tree if a dynamic import isn't used. - /* @internal */ PossiblyContainsDynamicImport = 1 << 20, - /* @internal */ PossiblyContainsImportMeta = 1 << 21, + /* @internal */ PossiblyContainsDynamicImport = 1 << 21, + /* @internal */ PossiblyContainsImportMeta = 1 << 22, - JSDoc = 1 << 22, // If node was parsed inside jsdoc - /* @internal */ Ambient = 1 << 23, // If node was inside an ambient context -- a declaration file, or inside something with the `declare` modifier. - /* @internal */ InWithStatement = 1 << 24, // If any ancestor of node was the `statement` of a WithStatement (not the `expression`) - JsonFile = 1 << 25, // If node was parsed in a Json - /* @internal */ TypeCached = 1 << 26, // If a type was cached for node at any point - /* @internal */ Deprecated = 1 << 27, // If has '@deprecated' JSDoc tag + JSDoc = 1 << 23, // If node was parsed inside jsdoc + /* @internal */ Ambient = 1 << 24, // If node was inside an ambient context -- a declaration file, or inside something with the `declare` modifier. + /* @internal */ InWithStatement = 1 << 25, // If any ancestor of node was the `statement` of a WithStatement (not the `expression`) + JsonFile = 1 << 26, // If node was parsed in a Json + /* @internal */ TypeCached = 1 << 27, // If a type was cached for node at any point + /* @internal */ Deprecated = 1 << 28, // If has '@deprecated' JSDoc tag BlockScoped = Let | Const, @@ -787,7 +788,7 @@ namespace ts { ReachabilityAndEmitFlags = ReachabilityCheckFlags | HasAsyncFunctions, // Parsing context flags - ContextFlags = DisallowInContext | YieldContext | DecoratorContext | AwaitContext | JavaScriptFile | InWithStatement | Ambient, + ContextFlags = DisallowInContext | DisallowConditionalTypesContext | YieldContext | DecoratorContext | AwaitContext | JavaScriptFile | InWithStatement | Ambient, // Exclude these flags when parsing a Type TypeExcludesFlags = YieldContext | AwaitContext, @@ -3222,11 +3223,13 @@ namespace ts { export interface JSDocNonNullableType extends JSDocType { readonly kind: SyntaxKind.JSDocNonNullableType; readonly type: TypeNode; + readonly postfix: boolean; } export interface JSDocNullableType extends JSDocType { readonly kind: SyntaxKind.JSDocNullableType; readonly type: TypeNode; + readonly postfix: boolean; } export interface JSDocOptionalType extends JSDocType { @@ -7090,11 +7093,19 @@ namespace ts { parenthesizeExpressionOfExpressionStatement(expression: Expression): Expression; parenthesizeConciseBodyOfArrowFunction(body: Expression): Expression; parenthesizeConciseBodyOfArrowFunction(body: ConciseBody): ConciseBody; - parenthesizeCheckTypeOfConditionalType(member: TypeNode): TypeNode; - parenthesizeMemberOfConditionalType(member: TypeNode): TypeNode; - parenthesizeMemberOfElementType(member: TypeNode): TypeNode; - parenthesizeElementTypeOfArrayType(member: TypeNode): TypeNode; - parenthesizeConstituentTypesOfUnionOrIntersectionType(members: readonly TypeNode[]): NodeArray; + parenthesizeCheckTypeOfConditionalType(type: TypeNode): TypeNode; + parenthesizeExtendsTypeOfConditionalType(type: TypeNode): TypeNode; + parenthesizeOperandOfTypeOperator(type: TypeNode): TypeNode; + parenthesizeOperandOfReadonlyTypeOperator(type: TypeNode): TypeNode; + parenthesizeNonArrayTypeOfPostfixType(type: TypeNode): TypeNode; + parenthesizeElementTypesOfTupleType(types: readonly (TypeNode | NamedTupleMember)[]): NodeArray; + parenthesizeElementTypeOfTupleType(type: TypeNode | NamedTupleMember): TypeNode | NamedTupleMember; + parenthesizeTypeOfOptionalType(type: TypeNode): TypeNode; + parenthesizeConstituentTypeOfUnionType(type: TypeNode): TypeNode; + parenthesizeConstituentTypesOfUnionType(constituents: readonly TypeNode[]): NodeArray; + parenthesizeConstituentTypeOfIntersectionType(type: TypeNode): TypeNode; + parenthesizeConstituentTypesOfIntersectionType(constituents: readonly TypeNode[]): NodeArray; + parenthesizeLeadingTypeArgument(typeNode: TypeNode): TypeNode; parenthesizeTypeArguments(typeParameters: readonly TypeNode[] | undefined): NodeArray | undefined; } @@ -7507,9 +7518,9 @@ namespace ts { createJSDocAllType(): JSDocAllType; createJSDocUnknownType(): JSDocUnknownType; - createJSDocNonNullableType(type: TypeNode): JSDocNonNullableType; + createJSDocNonNullableType(type: TypeNode, postfix?: boolean): JSDocNonNullableType; updateJSDocNonNullableType(node: JSDocNonNullableType, type: TypeNode): JSDocNonNullableType; - createJSDocNullableType(type: TypeNode): JSDocNullableType; + createJSDocNullableType(type: TypeNode, postfix?: boolean): JSDocNullableType; updateJSDocNullableType(node: JSDocNullableType, type: TypeNode): JSDocNullableType; createJSDocOptionalType(type: TypeNode): JSDocOptionalType; updateJSDocOptionalType(node: JSDocOptionalType, type: TypeNode): JSDocOptionalType; diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nonNullableType.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nonNullableType.json index 6753df2cc0668..9f30835104500 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nonNullableType.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nonNullableType.json @@ -12,5 +12,6 @@ "flags": "JSDoc", "modifierFlagsCache": 0, "transformFlags": 1 - } + }, + "postfix": false } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nonNullableType2.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nonNullableType2.json index e579a0db6e3cd..0b4718e71ac93 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nonNullableType2.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nonNullableType2.json @@ -12,5 +12,6 @@ "flags": "JSDoc", "modifierFlagsCache": 0, "transformFlags": 1 - } + }, + "postfix": true } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nullableType.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nullableType.json index bdc4edb280e66..17b7fa941ccf9 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nullableType.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nullableType.json @@ -12,5 +12,6 @@ "flags": "JSDoc", "modifierFlagsCache": 0, "transformFlags": 1 - } + }, + "postfix": false } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nullableType2.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nullableType2.json index 44f20173cd3d7..76313b04a415c 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nullableType2.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.nullableType2.json @@ -12,5 +12,6 @@ "flags": "JSDoc", "modifierFlagsCache": 0, "transformFlags": 1 - } + }, + "postfix": true } \ No newline at end of file diff --git a/tests/baselines/reference/aliasUsageInArray.types b/tests/baselines/reference/aliasUsageInArray.types index 168bb0cf6f873..b982d28f8c21f 100644 --- a/tests/baselines/reference/aliasUsageInArray.types +++ b/tests/baselines/reference/aliasUsageInArray.types @@ -15,13 +15,13 @@ interface IHasVisualizationModel { var xs: IHasVisualizationModel[] = [moduleA]; >xs : IHasVisualizationModel[] ->[moduleA] : (typeof moduleA)[] +>[moduleA] : typeof moduleA[] >moduleA : typeof moduleA var xs2: typeof moduleA[] = [moduleA]; ->xs2 : (typeof moduleA)[] +>xs2 : typeof moduleA[] >moduleA : typeof moduleA ->[moduleA] : (typeof moduleA)[] +>[moduleA] : typeof moduleA[] >moduleA : typeof moduleA === tests/cases/compiler/aliasUsageInArray_backbone.ts === diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 2cc99e632b4b5..7e55e1f41ba5f 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -520,16 +520,17 @@ declare namespace ts { YieldContext = 8192, DecoratorContext = 16384, AwaitContext = 32768, - ThisNodeHasError = 65536, - JavaScriptFile = 131072, - ThisNodeOrAnySubNodesHasError = 262144, - HasAggregatedChildData = 524288, - JSDoc = 4194304, - JsonFile = 33554432, + DisallowConditionalTypesContext = 65536, + ThisNodeHasError = 131072, + JavaScriptFile = 262144, + ThisNodeOrAnySubNodesHasError = 524288, + HasAggregatedChildData = 1048576, + JSDoc = 8388608, + JsonFile = 67108864, BlockScoped = 3, ReachabilityCheckFlags = 768, ReachabilityAndEmitFlags = 2816, - ContextFlags = 25358336, + ContextFlags = 50720768, TypeExcludesFlags = 40960, } export enum ModifierFlags { @@ -1798,10 +1799,12 @@ declare namespace ts { export interface JSDocNonNullableType extends JSDocType { readonly kind: SyntaxKind.JSDocNonNullableType; readonly type: TypeNode; + readonly postfix: boolean; } export interface JSDocNullableType extends JSDocType { readonly kind: SyntaxKind.JSDocNullableType; readonly type: TypeNode; + readonly postfix: boolean; } export interface JSDocOptionalType extends JSDocType { readonly kind: SyntaxKind.JSDocOptionalType; @@ -3621,9 +3624,9 @@ declare namespace ts { updateExternalModuleReference(node: ExternalModuleReference, expression: Expression): ExternalModuleReference; createJSDocAllType(): JSDocAllType; createJSDocUnknownType(): JSDocUnknownType; - createJSDocNonNullableType(type: TypeNode): JSDocNonNullableType; + createJSDocNonNullableType(type: TypeNode, postfix?: boolean): JSDocNonNullableType; updateJSDocNonNullableType(node: JSDocNonNullableType, type: TypeNode): JSDocNonNullableType; - createJSDocNullableType(type: TypeNode): JSDocNullableType; + createJSDocNullableType(type: TypeNode, postfix?: boolean): JSDocNullableType; updateJSDocNullableType(node: JSDocNullableType, type: TypeNode): JSDocNullableType; createJSDocOptionalType(type: TypeNode): JSDocOptionalType; updateJSDocOptionalType(node: JSDocOptionalType, type: TypeNode): JSDocOptionalType; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 588f4a2d550f7..8b376a328c22f 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -520,16 +520,17 @@ declare namespace ts { YieldContext = 8192, DecoratorContext = 16384, AwaitContext = 32768, - ThisNodeHasError = 65536, - JavaScriptFile = 131072, - ThisNodeOrAnySubNodesHasError = 262144, - HasAggregatedChildData = 524288, - JSDoc = 4194304, - JsonFile = 33554432, + DisallowConditionalTypesContext = 65536, + ThisNodeHasError = 131072, + JavaScriptFile = 262144, + ThisNodeOrAnySubNodesHasError = 524288, + HasAggregatedChildData = 1048576, + JSDoc = 8388608, + JsonFile = 67108864, BlockScoped = 3, ReachabilityCheckFlags = 768, ReachabilityAndEmitFlags = 2816, - ContextFlags = 25358336, + ContextFlags = 50720768, TypeExcludesFlags = 40960, } export enum ModifierFlags { @@ -1798,10 +1799,12 @@ declare namespace ts { export interface JSDocNonNullableType extends JSDocType { readonly kind: SyntaxKind.JSDocNonNullableType; readonly type: TypeNode; + readonly postfix: boolean; } export interface JSDocNullableType extends JSDocType { readonly kind: SyntaxKind.JSDocNullableType; readonly type: TypeNode; + readonly postfix: boolean; } export interface JSDocOptionalType extends JSDocType { readonly kind: SyntaxKind.JSDocOptionalType; @@ -3621,9 +3624,9 @@ declare namespace ts { updateExternalModuleReference(node: ExternalModuleReference, expression: Expression): ExternalModuleReference; createJSDocAllType(): JSDocAllType; createJSDocUnknownType(): JSDocUnknownType; - createJSDocNonNullableType(type: TypeNode): JSDocNonNullableType; + createJSDocNonNullableType(type: TypeNode, postfix?: boolean): JSDocNonNullableType; updateJSDocNonNullableType(node: JSDocNonNullableType, type: TypeNode): JSDocNonNullableType; - createJSDocNullableType(type: TypeNode): JSDocNullableType; + createJSDocNullableType(type: TypeNode, postfix?: boolean): JSDocNullableType; updateJSDocNullableType(node: JSDocNullableType, type: TypeNode): JSDocNullableType; createJSDocOptionalType(type: TypeNode): JSDocOptionalType; updateJSDocOptionalType(node: JSDocOptionalType, type: TypeNode): JSDocOptionalType; diff --git a/tests/baselines/reference/arrayLiterals.types b/tests/baselines/reference/arrayLiterals.types index ab5c6ea037d12..111ad85f4ffbb 100644 --- a/tests/baselines/reference/arrayLiterals.types +++ b/tests/baselines/reference/arrayLiterals.types @@ -65,14 +65,14 @@ var classArr = [new C(), new C()]; >C : typeof C var classTypeArray = [C, C, C]; ->classTypeArray : (typeof C)[] ->[C, C, C] : (typeof C)[] +>classTypeArray : typeof C[] +>[C, C, C] : typeof C[] >C : typeof C >C : typeof C >C : typeof C var classTypeArray: Array; // Should OK, not be a parse error ->classTypeArray : (typeof C)[] +>classTypeArray : typeof C[] >C : typeof C // Contextual type C with numeric index signature makes array literal of EveryType E of type BCT(E,C)[] diff --git a/tests/baselines/reference/arrayOfFunctionTypes3.types b/tests/baselines/reference/arrayOfFunctionTypes3.types index 4dd258645a6f2..f59a292bf24e5 100644 --- a/tests/baselines/reference/arrayOfFunctionTypes3.types +++ b/tests/baselines/reference/arrayOfFunctionTypes3.types @@ -22,8 +22,8 @@ class C { >foo : string } var y = [C, C]; ->y : (typeof C)[] ->[C, C] : (typeof C)[] +>y : typeof C[] +>[C, C] : typeof C[] >C : typeof C >C : typeof C @@ -31,7 +31,7 @@ var r3 = new y[0](); >r3 : C >new y[0]() : C >y[0] : typeof C ->y : (typeof C)[] +>y : typeof C[] >0 : 0 var a: { (x: number): number; (x: string): string; }; diff --git a/tests/baselines/reference/classCanExtendConstructorFunction.errors.txt b/tests/baselines/reference/classCanExtendConstructorFunction.errors.txt index 1fd6c25a714e4..1cb5e22b0e9b0 100644 --- a/tests/baselines/reference/classCanExtendConstructorFunction.errors.txt +++ b/tests/baselines/reference/classCanExtendConstructorFunction.errors.txt @@ -7,9 +7,9 @@ tests/cases/conformance/salsa/generic.js(20,32): error TS2345: Argument of type tests/cases/conformance/salsa/second.ts(8,25): error TS2507: Type '(numberEaten: number) => void' is not a constructor function type. tests/cases/conformance/salsa/second.ts(14,7): error TS2417: Class static side 'typeof Conestoga' incorrectly extends base class static side 'typeof Wagon'. Types of property 'circle' are incompatible. - Type '(others: (typeof Wagon)[]) => number' is not assignable to type '(wagons?: Wagon[]) => number'. + Type '(others: typeof Wagon[]) => number' is not assignable to type '(wagons?: Wagon[]) => number'. Types of parameters 'others' and 'wagons' are incompatible. - Type 'Wagon[]' is not assignable to type '(typeof Wagon)[]'. + Type 'Wagon[]' is not assignable to type 'typeof Wagon[]'. Property 'circle' is missing in type 'Wagon' but required in type 'typeof Wagon'. tests/cases/conformance/salsa/second.ts(17,15): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. @@ -93,9 +93,9 @@ tests/cases/conformance/salsa/second.ts(17,15): error TS2345: Argument of type ' ~~~~~~~~~ !!! error TS2417: Class static side 'typeof Conestoga' incorrectly extends base class static side 'typeof Wagon'. !!! error TS2417: Types of property 'circle' are incompatible. -!!! error TS2417: Type '(others: (typeof Wagon)[]) => number' is not assignable to type '(wagons?: Wagon[]) => number'. +!!! error TS2417: Type '(others: typeof Wagon[]) => number' is not assignable to type '(wagons?: Wagon[]) => number'. !!! error TS2417: Types of parameters 'others' and 'wagons' are incompatible. -!!! error TS2417: Type 'Wagon[]' is not assignable to type '(typeof Wagon)[]'. +!!! error TS2417: Type 'Wagon[]' is not assignable to type 'typeof Wagon[]'. !!! error TS2417: Property 'circle' is missing in type 'Wagon' but required in type 'typeof Wagon'. !!! related TS2728 tests/cases/conformance/salsa/first.js:9:1: 'circle' is declared here. constructor(public drunkOO: true) { diff --git a/tests/baselines/reference/classCanExtendConstructorFunction.types b/tests/baselines/reference/classCanExtendConstructorFunction.types index a060d27e54d44..61080fa649de5 100644 --- a/tests/baselines/reference/classCanExtendConstructorFunction.types +++ b/tests/baselines/reference/classCanExtendConstructorFunction.types @@ -201,12 +201,12 @@ class Conestoga extends Wagon { // should error since others is not optional static circle(others: (typeof Wagon)[]) { >circle : (others: (typeof Wagon)[]) => number ->others : (typeof Wagon)[] +>others : typeof Wagon[] >Wagon : typeof Wagon return others.length >others.length : number ->others : (typeof Wagon)[] +>others : typeof Wagon[] >length : number } } diff --git a/tests/baselines/reference/constEnumErrors.types b/tests/baselines/reference/constEnumErrors.types index d2d65e3196877..15b49ec37c09b 100644 --- a/tests/baselines/reference/constEnumErrors.types +++ b/tests/baselines/reference/constEnumErrors.types @@ -72,8 +72,8 @@ var x = E2; >E2 : typeof E2 var y = [E2]; ->y : (typeof E2)[] ->[E2] : (typeof E2)[] +>y : typeof E2[] +>[E2] : typeof E2[] >E2 : typeof E2 function foo(t: any): void { diff --git a/tests/baselines/reference/constructorTagOnClassConstructor.types b/tests/baselines/reference/constructorTagOnClassConstructor.types index f93061704a923..ec81bba0712e9 100644 --- a/tests/baselines/reference/constructorTagOnClassConstructor.types +++ b/tests/baselines/reference/constructorTagOnClassConstructor.types @@ -13,8 +13,8 @@ export class Beta { } const arr = [Alpha, Beta]; ->arr : (typeof Alpha)[] ->[Alpha, Beta] : (typeof Alpha)[] +>arr : typeof Alpha[] +>[Alpha, Beta] : typeof Alpha[] >Alpha : typeof Alpha >Beta : typeof Beta diff --git a/tests/baselines/reference/controlFlowIfStatement.types b/tests/baselines/reference/controlFlowIfStatement.types index d549ef6f0a2bb..577c28e703b3e 100644 --- a/tests/baselines/reference/controlFlowIfStatement.types +++ b/tests/baselines/reference/controlFlowIfStatement.types @@ -104,7 +104,7 @@ function c(data: string | T): T { >JSON.parse : (text: string, reviver?: (this: any, key: string, value: any) => any) => any >JSON : JSON >parse : (text: string, reviver?: (this: any, key: string, value: any) => any) => any ->data : string | (T & string) +>data : string | T & string } else { return data; diff --git a/tests/baselines/reference/derivedClassSuperProperties.types b/tests/baselines/reference/derivedClassSuperProperties.types index c52f578ce7ecd..b86f54e38bd0e 100644 --- a/tests/baselines/reference/derivedClassSuperProperties.types +++ b/tests/baselines/reference/derivedClassSuperProperties.types @@ -879,8 +879,8 @@ let a, b; >b : any const DerivedWithLoops = [ ->DerivedWithLoops : (typeof (Anonymous class))[] ->[ class extends Base { prop = true; constructor() { for(super();;) {} } }, class extends Base { prop = true; constructor() { for(a; super();) {} } }, class extends Base { prop = true; constructor() { for(a; b; super()) {} } }, class extends Base { prop = true; constructor() { for(; ; super()) { break; } } }, class extends Base { prop = true; constructor() { for (const x of super()) {} } }, class extends Base { prop = true; constructor() { while (super()) {} } }, class extends Base { prop = true; constructor() { do {} while (super()); } }, class extends Base { prop = true; constructor() { if (super()) {} } }, class extends Base { prop = true; constructor() { switch (super()) {} } },] : (typeof (Anonymous class))[] +>DerivedWithLoops : typeof (Anonymous class)[] +>[ class extends Base { prop = true; constructor() { for(super();;) {} } }, class extends Base { prop = true; constructor() { for(a; super();) {} } }, class extends Base { prop = true; constructor() { for(a; b; super()) {} } }, class extends Base { prop = true; constructor() { for(; ; super()) { break; } } }, class extends Base { prop = true; constructor() { for (const x of super()) {} } }, class extends Base { prop = true; constructor() { while (super()) {} } }, class extends Base { prop = true; constructor() { do {} while (super()); } }, class extends Base { prop = true; constructor() { if (super()) {} } }, class extends Base { prop = true; constructor() { switch (super()) {} } },] : typeof (Anonymous class)[] class extends Base { >class extends Base { prop = true; constructor() { for(super();;) {} } } : typeof (Anonymous class) diff --git a/tests/baselines/reference/discriminatedUnionTypes2.types b/tests/baselines/reference/discriminatedUnionTypes2.types index 695f0c3768f00..ff019af51fc2d 100644 --- a/tests/baselines/reference/discriminatedUnionTypes2.types +++ b/tests/baselines/reference/discriminatedUnionTypes2.types @@ -388,14 +388,14 @@ function foo1(x: RuntimeValue & { type: 'number' }) { function foo2(x: RuntimeValue & ({ type: 'number' } | { type: 'string' })) { >foo2 : (x: RuntimeValue & ({ type: 'number';} | { type: 'string';})) => void ->x : ({ type: "number"; value: number; } & { type: 'number'; }) | ({ type: "string"; value: string; } & { type: 'string'; }) +>x : { type: "number"; value: number; } & { type: 'number'; } | { type: "string"; value: string; } & { type: 'string'; } >type : "number" >type : "string" if (x.type === 'number') { >x.type === 'number' : boolean >x.type : "string" | "number" ->x : ({ type: "number"; value: number; } & { type: "number"; }) | ({ type: "string"; value: string; } & { type: "string"; }) +>x : { type: "number"; value: number; } & { type: "number"; } | { type: "string"; value: string; } & { type: "string"; } >type : "string" | "number" >'number' : "number" diff --git a/tests/baselines/reference/inferTypes2.js b/tests/baselines/reference/inferTypes2.js index 23b84450e2de5..dbfa84964df10 100644 --- a/tests/baselines/reference/inferTypes2.js +++ b/tests/baselines/reference/inferTypes2.js @@ -49,5 +49,5 @@ export declare function foo2(obj: T): T extends { [K in keyof BadNested]: BadNested[K]; } ? P : never; export declare function bar2(obj: T): T extends { - x: (infer P) extends number ? infer P : string; + x: infer P extends number ? infer P : string; } ? P : never; diff --git a/tests/baselines/reference/inferTypes2.types b/tests/baselines/reference/inferTypes2.types index fdba311280a24..04ca9ea6d0553 100644 --- a/tests/baselines/reference/inferTypes2.types +++ b/tests/baselines/reference/inferTypes2.types @@ -20,16 +20,16 @@ export type BadNested = { x: T extends number ? T : string }; >x : T extends number ? T : string export declare function foo2(obj: T): T extends { [K in keyof BadNested]: BadNested[K] } ? P : never; ->foo2 : (obj: T) => T extends { x: (infer P) extends number ? infer P : string; } ? P : never +>foo2 : (obj: T) => T extends { x: infer P extends number ? infer P : string; } ? P : never >obj : T export function bar2(obj: T) { ->bar2 : (obj: T) => T extends { x: (infer P) extends number ? infer P : string; } ? P : never +>bar2 : (obj: T) => T extends { x: infer P extends number ? infer P : string; } ? P : never >obj : T return foo2(obj); ->foo2(obj) : T extends { x: (infer P) extends number ? infer P : string; } ? P : never ->foo2 : (obj: T) => T extends { x: (infer P) extends number ? infer P : string; } ? P : never +>foo2(obj) : T extends { x: infer P extends number ? infer P : string; } ? P : never +>foo2 : (obj: T) => T extends { x: infer P extends number ? infer P : string; } ? P : never >obj : T } diff --git a/tests/baselines/reference/inferTypesWithExtends1.js b/tests/baselines/reference/inferTypesWithExtends1.js index 0c57e21adb284..c73eed127d753 100644 --- a/tests/baselines/reference/inferTypesWithExtends1.js +++ b/tests/baselines/reference/inferTypesWithExtends1.js @@ -21,8 +21,8 @@ type X2_T3 = X2<(a: object) => void>; // never // infer to return type type X3 any> = - T extends (...args: any[]) => infer U extends string ? ["string", U] : - T extends (...args: any[]) => infer U extends number ? ["number", U] : + T extends (...args: any[]) => (infer U extends string) ? ["string", U] : + T extends (...args: any[]) => (infer U extends number) ? ["number", U] : never; type X3_T1 = X3<() => "a">; // ["string", "a"] @@ -31,8 +31,8 @@ type X3_T3 = X3<() => object>; // never // infer to instance type type X4 any> = - T extends new (...args: any[]) => infer U extends { a: string } ? ["string", U] : - T extends new (...args: any[]) => infer U extends { a: number } ? ["number", U] : + T extends new (...args: any[]) => (infer U extends { a: string }) ? ["string", U] : + T extends new (...args: any[]) => (infer U extends { a: number }) ? ["number", U] : never; type X4_T1 = X4 { a: "a" }>; // ["string", { a: "a" }] @@ -91,6 +91,20 @@ type X9_T1 = X9<{ a: "a", b: "b" }>; // ["string", "a" | "b"] type X9_T2 = X9<{ a: 1, b: 2 }>; // ["number", 1 | 2] type X9_T3 = X9<{ a: object, b: object }>; // never type X9_T4 = X9<{ a: "a", b: 1 }>; // never + +// Speculative lookahead for `infer T extends U ?` +type X10 = T extends (infer U extends number ? 1 : 0) ? 1 : 0; // ok, parsed as conditional +type X10_Y1 = X10; +type X10_T1_T1 = X10_Y1; + +type X11 = T extends ((infer U) extends number ? 1 : 0) ? 1 : 0; // ok, parsed as conditional +type X12 = T extends (infer U extends number) ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`) +type X13 = T extends infer U extends number ? 1 : 0; // ok, parsed as `infer..extends` (conditional types not allowed in 'extends type') +type X14 = T extends keyof infer U extends number ? 1 : 0; // ok, parsed as `infer..extends` (precedence wouldn't have parsed the `?` as part of a type operator) +type X15 = T extends { [P in infer U extends keyof T ? 1 : 0]: 1; } ? 1 : 0; // ok, parsed as conditional +type X16 = T extends { [P in infer U extends keyof T]: 1; } ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`) +type X17 = T extends { [P in keyof T as infer U extends P ? 1 : 0]: 1; } ? 1 : 0; // ok, parsed as conditional +type X18 = T extends { [P in keyof T as infer U extends P]: 1; } ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`) //// [inferTypesWithExtends1.js] @@ -106,15 +120,15 @@ declare type X2 void> = T extends (a: infer U exte declare type X2_T1 = X2<(a: "a") => void>; declare type X2_T2 = X2<(a: 1) => void>; declare type X2_T3 = X2<(a: object) => void>; -declare type X3 any> = T extends (...args: any[]) => infer U extends string ? ["string", U] : T extends (...args: any[]) => infer U extends number ? ["number", U] : never; +declare type X3 any> = T extends (...args: any[]) => (infer U extends string) ? ["string", U] : T extends (...args: any[]) => (infer U extends number) ? ["number", U] : never; declare type X3_T1 = X3<() => "a">; declare type X3_T2 = X3<() => 1>; declare type X3_T3 = X3<() => object>; -declare type X4 any> = T extends new (...args: any[]) => infer U extends { +declare type X4 any> = T extends new (...args: any[]) => (infer U extends { a: string; -} ? ["string", U] : T extends new (...args: any[]) => infer U extends { +}) ? ["string", U] : T extends new (...args: any[]) => (infer U extends { a: number; -} ? ["number", U] : never; +}) ? ["number", U] : never; declare type X4_T1 = X4 { a: "a"; }>; @@ -211,3 +225,22 @@ declare type X9_T4 = X9<{ a: "a"; b: 1; }>; +declare type X10 = T extends (infer U extends number ? 1 : 0) ? 1 : 0; +declare type X10_Y1 = X10; +declare type X10_T1_T1 = X10_Y1; +declare type X11 = T extends ((infer U) extends number ? 1 : 0) ? 1 : 0; +declare type X12 = T extends (infer U extends number) ? 1 : 0; +declare type X13 = T extends infer U extends number ? 1 : 0; +declare type X14 = T extends keyof infer U extends number ? 1 : 0; +declare type X15 = T extends { + [P in infer U extends keyof T ? 1 : 0]: 1; +} ? 1 : 0; +declare type X16 = T extends { + [P in infer U extends keyof T]: 1; +} ? 1 : 0; +declare type X17 = T extends { + [P in keyof T as infer U extends P ? 1 : 0]: 1; +} ? 1 : 0; +declare type X18 = T extends { + [P in keyof T as infer U extends P]: 1; +} ? 1 : 0; diff --git a/tests/baselines/reference/inferTypesWithExtends1.symbols b/tests/baselines/reference/inferTypesWithExtends1.symbols index d487baa8ab814..3805f873d4b8e 100644 --- a/tests/baselines/reference/inferTypesWithExtends1.symbols +++ b/tests/baselines/reference/inferTypesWithExtends1.symbols @@ -69,17 +69,17 @@ type X3 any> = >T : Symbol(T, Decl(inferTypesWithExtends1.ts, 21, 8)) >args : Symbol(args, Decl(inferTypesWithExtends1.ts, 21, 19)) - T extends (...args: any[]) => infer U extends string ? ["string", U] : + T extends (...args: any[]) => (infer U extends string) ? ["string", U] : >T : Symbol(T, Decl(inferTypesWithExtends1.ts, 21, 8)) >args : Symbol(args, Decl(inferTypesWithExtends1.ts, 22, 15)) ->U : Symbol(U, Decl(inferTypesWithExtends1.ts, 22, 39)) ->U : Symbol(U, Decl(inferTypesWithExtends1.ts, 22, 39)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 22, 40)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 22, 40)) - T extends (...args: any[]) => infer U extends number ? ["number", U] : + T extends (...args: any[]) => (infer U extends number) ? ["number", U] : >T : Symbol(T, Decl(inferTypesWithExtends1.ts, 21, 8)) >args : Symbol(args, Decl(inferTypesWithExtends1.ts, 23, 15)) ->U : Symbol(U, Decl(inferTypesWithExtends1.ts, 23, 39)) ->U : Symbol(U, Decl(inferTypesWithExtends1.ts, 23, 39)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 23, 40)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 23, 40)) never; @@ -101,19 +101,19 @@ type X4 any> = >T : Symbol(T, Decl(inferTypesWithExtends1.ts, 31, 8)) >args : Symbol(args, Decl(inferTypesWithExtends1.ts, 31, 23)) - T extends new (...args: any[]) => infer U extends { a: string } ? ["string", U] : + T extends new (...args: any[]) => (infer U extends { a: string }) ? ["string", U] : >T : Symbol(T, Decl(inferTypesWithExtends1.ts, 31, 8)) >args : Symbol(args, Decl(inferTypesWithExtends1.ts, 32, 19)) ->U : Symbol(U, Decl(inferTypesWithExtends1.ts, 32, 43)) ->a : Symbol(a, Decl(inferTypesWithExtends1.ts, 32, 55)) ->U : Symbol(U, Decl(inferTypesWithExtends1.ts, 32, 43)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 32, 44)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 32, 56)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 32, 44)) - T extends new (...args: any[]) => infer U extends { a: number } ? ["number", U] : + T extends new (...args: any[]) => (infer U extends { a: number }) ? ["number", U] : >T : Symbol(T, Decl(inferTypesWithExtends1.ts, 31, 8)) >args : Symbol(args, Decl(inferTypesWithExtends1.ts, 33, 19)) ->U : Symbol(U, Decl(inferTypesWithExtends1.ts, 33, 43)) ->a : Symbol(a, Decl(inferTypesWithExtends1.ts, 33, 55)) ->U : Symbol(U, Decl(inferTypesWithExtends1.ts, 33, 43)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 33, 44)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 33, 56)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 33, 44)) never; @@ -341,3 +341,78 @@ type X9_T4 = X9<{ a: "a", b: 1 }>; // never >a : Symbol(a, Decl(inferTypesWithExtends1.ts, 91, 17)) >b : Symbol(b, Decl(inferTypesWithExtends1.ts, 91, 25)) +// Speculative lookahead for `infer T extends U ?` +type X10 = T extends (infer U extends number ? 1 : 0) ? 1 : 0; // ok, parsed as conditional +>X10 : Symbol(X10, Decl(inferTypesWithExtends1.ts, 91, 34)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 94, 9)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 94, 9)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 94, 30)) + +type X10_Y1 = X10; +>X10_Y1 : Symbol(X10_Y1, Decl(inferTypesWithExtends1.ts, 94, 65)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 95, 12)) +>X10 : Symbol(X10, Decl(inferTypesWithExtends1.ts, 91, 34)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 95, 12)) + +type X10_T1_T1 = X10_Y1; +>X10_T1_T1 : Symbol(X10_T1_T1, Decl(inferTypesWithExtends1.ts, 95, 47)) +>X10_Y1 : Symbol(X10_Y1, Decl(inferTypesWithExtends1.ts, 94, 65)) + +type X11 = T extends ((infer U) extends number ? 1 : 0) ? 1 : 0; // ok, parsed as conditional +>X11 : Symbol(X11, Decl(inferTypesWithExtends1.ts, 96, 32)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 98, 9)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 98, 9)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 98, 31)) + +type X12 = T extends (infer U extends number) ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`) +>X12 : Symbol(X12, Decl(inferTypesWithExtends1.ts, 98, 67)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 99, 9)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 99, 9)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 99, 30)) + +type X13 = T extends infer U extends number ? 1 : 0; // ok, parsed as `infer..extends` (conditional types not allowed in 'extends type') +>X13 : Symbol(X13, Decl(inferTypesWithExtends1.ts, 99, 57)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 100, 9)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 100, 9)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 100, 29)) + +type X14 = T extends keyof infer U extends number ? 1 : 0; // ok, parsed as `infer..extends` (precedence wouldn't have parsed the `?` as part of a type operator) +>X14 : Symbol(X14, Decl(inferTypesWithExtends1.ts, 100, 55)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 101, 9)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 101, 9)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 101, 35)) + +type X15 = T extends { [P in infer U extends keyof T ? 1 : 0]: 1; } ? 1 : 0; // ok, parsed as conditional +>X15 : Symbol(X15, Decl(inferTypesWithExtends1.ts, 101, 61)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 102, 9)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 102, 9)) +>P : Symbol(P, Decl(inferTypesWithExtends1.ts, 102, 27)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 102, 37)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 102, 9)) + +type X16 = T extends { [P in infer U extends keyof T]: 1; } ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`) +>X16 : Symbol(X16, Decl(inferTypesWithExtends1.ts, 102, 79)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 103, 9)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 103, 9)) +>P : Symbol(P, Decl(inferTypesWithExtends1.ts, 103, 27)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 103, 37)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 103, 9)) + +type X17 = T extends { [P in keyof T as infer U extends P ? 1 : 0]: 1; } ? 1 : 0; // ok, parsed as conditional +>X17 : Symbol(X17, Decl(inferTypesWithExtends1.ts, 103, 71)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 104, 9)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 104, 9)) +>P : Symbol(P, Decl(inferTypesWithExtends1.ts, 104, 27)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 104, 9)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 104, 48)) +>P : Symbol(P, Decl(inferTypesWithExtends1.ts, 104, 27)) + +type X18 = T extends { [P in keyof T as infer U extends P]: 1; } ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`) +>X18 : Symbol(X18, Decl(inferTypesWithExtends1.ts, 104, 84)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 105, 9)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 105, 9)) +>P : Symbol(P, Decl(inferTypesWithExtends1.ts, 105, 27)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 105, 9)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 105, 48)) +>P : Symbol(P, Decl(inferTypesWithExtends1.ts, 105, 27)) + diff --git a/tests/baselines/reference/inferTypesWithExtends1.types b/tests/baselines/reference/inferTypesWithExtends1.types index 24215af18e2b7..21435aee04214 100644 --- a/tests/baselines/reference/inferTypesWithExtends1.types +++ b/tests/baselines/reference/inferTypesWithExtends1.types @@ -46,10 +46,10 @@ type X3 any> = >X3 : X3 >args : any[] - T extends (...args: any[]) => infer U extends string ? ["string", U] : + T extends (...args: any[]) => (infer U extends string) ? ["string", U] : >args : any[] - T extends (...args: any[]) => infer U extends number ? ["number", U] : + T extends (...args: any[]) => (infer U extends number) ? ["number", U] : >args : any[] never; @@ -68,11 +68,11 @@ type X4 any> = >X4 : X4 >args : any[] - T extends new (...args: any[]) => infer U extends { a: string } ? ["string", U] : + T extends new (...args: any[]) => (infer U extends { a: string }) ? ["string", U] : >args : any[] >a : string - T extends new (...args: any[]) => infer U extends { a: number } ? ["number", U] : + T extends new (...args: any[]) => (infer U extends { a: number }) ? ["number", U] : >args : any[] >a : number @@ -233,3 +233,37 @@ type X9_T4 = X9<{ a: "a", b: 1 }>; // never >a : "a" >b : 1 +// Speculative lookahead for `infer T extends U ?` +type X10 = T extends (infer U extends number ? 1 : 0) ? 1 : 0; // ok, parsed as conditional +>X10 : X10 + +type X10_Y1 = X10; +>X10_Y1 : X10_Y1 + +type X10_T1_T1 = X10_Y1; +>X10_T1_T1 : 0 + +type X11 = T extends ((infer U) extends number ? 1 : 0) ? 1 : 0; // ok, parsed as conditional +>X11 : X11 + +type X12 = T extends (infer U extends number) ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`) +>X12 : X12 + +type X13 = T extends infer U extends number ? 1 : 0; // ok, parsed as `infer..extends` (conditional types not allowed in 'extends type') +>X13 : X13 + +type X14 = T extends keyof infer U extends number ? 1 : 0; // ok, parsed as `infer..extends` (precedence wouldn't have parsed the `?` as part of a type operator) +>X14 : X14 + +type X15 = T extends { [P in infer U extends keyof T ? 1 : 0]: 1; } ? 1 : 0; // ok, parsed as conditional +>X15 : X15 + +type X16 = T extends { [P in infer U extends keyof T]: 1; } ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`) +>X16 : X16 + +type X17 = T extends { [P in keyof T as infer U extends P ? 1 : 0]: 1; } ? 1 : 0; // ok, parsed as conditional +>X17 : X17 + +type X18 = T extends { [P in keyof T as infer U extends P]: 1; } ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`) +>X18 : X18 + diff --git a/tests/baselines/reference/intersectionAndUnionTypes.errors.txt b/tests/baselines/reference/intersectionAndUnionTypes.errors.txt index 049ff9ca685a3..bd379acb0becf 100644 --- a/tests/baselines/reference/intersectionAndUnionTypes.errors.txt +++ b/tests/baselines/reference/intersectionAndUnionTypes.errors.txt @@ -2,22 +2,22 @@ tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(19,1): e Property 'b' is missing in type 'A' but required in type 'B'. tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(20,1): error TS2322: Type 'B' is not assignable to type 'A & B'. Property 'a' is missing in type 'B' but required in type 'A'. -tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(23,1): error TS2322: Type 'A | B' is not assignable to type '(A & B) | (C & D)'. - Type 'A' is not assignable to type '(A & B) | (C & D)'. +tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(23,1): error TS2322: Type 'A | B' is not assignable to type 'A & B | C & D'. + Type 'A' is not assignable to type 'A & B | C & D'. Type 'A' is not assignable to type 'A & B'. -tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(25,1): error TS2322: Type 'C | D' is not assignable to type '(A & B) | (C & D)'. - Type 'C' is not assignable to type '(A & B) | (C & D)'. +tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(25,1): error TS2322: Type 'C | D' is not assignable to type 'A & B | C & D'. + Type 'C' is not assignable to type 'A & B | C & D'. Type 'C' is not assignable to type 'C & D'. Property 'd' is missing in type 'C' but required in type 'D'. -tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(26,1): error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'A & B'. +tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(26,1): error TS2322: Type 'A & B | C & D' is not assignable to type 'A & B'. Type 'C & D' is not assignable to type 'A & B'. Property 'a' is missing in type 'C & D' but required in type 'A'. -tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(27,1): error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'A | B'. +tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(27,1): error TS2322: Type 'A & B | C & D' is not assignable to type 'A | B'. Type 'C & D' is not assignable to type 'A | B'. -tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(28,1): error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'C & D'. +tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(28,1): error TS2322: Type 'A & B | C & D' is not assignable to type 'C & D'. Type 'A & B' is not assignable to type 'C & D'. Property 'c' is missing in type 'A & B' but required in type 'C'. -tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(29,1): error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'C | D'. +tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(29,1): error TS2322: Type 'A & B | C & D' is not assignable to type 'C | D'. Type 'A & B' is not assignable to type 'C | D'. tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(31,1): error TS2322: Type 'A & B' is not assignable to type '(A | B) & (C | D)'. Type 'A & B' is not assignable to type 'B & D'. @@ -74,36 +74,36 @@ tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(37,1): e x = anb; // Ok x = aob; ~ -!!! error TS2322: Type 'A | B' is not assignable to type '(A & B) | (C & D)'. -!!! error TS2322: Type 'A' is not assignable to type '(A & B) | (C & D)'. +!!! error TS2322: Type 'A | B' is not assignable to type 'A & B | C & D'. +!!! error TS2322: Type 'A' is not assignable to type 'A & B | C & D'. !!! error TS2322: Type 'A' is not assignable to type 'A & B'. x = cnd; // Ok x = cod; ~ -!!! error TS2322: Type 'C | D' is not assignable to type '(A & B) | (C & D)'. -!!! error TS2322: Type 'C' is not assignable to type '(A & B) | (C & D)'. +!!! error TS2322: Type 'C | D' is not assignable to type 'A & B | C & D'. +!!! error TS2322: Type 'C' is not assignable to type 'A & B | C & D'. !!! error TS2322: Type 'C' is not assignable to type 'C & D'. !!! error TS2322: Property 'd' is missing in type 'C' but required in type 'D'. !!! related TS2728 tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts:4:15: 'd' is declared here. anb = x; ~~~ -!!! error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'A & B'. +!!! error TS2322: Type 'A & B | C & D' is not assignable to type 'A & B'. !!! error TS2322: Type 'C & D' is not assignable to type 'A & B'. !!! error TS2322: Property 'a' is missing in type 'C & D' but required in type 'A'. !!! related TS2728 tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts:1:15: 'a' is declared here. aob = x; ~~~ -!!! error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'A | B'. +!!! error TS2322: Type 'A & B | C & D' is not assignable to type 'A | B'. !!! error TS2322: Type 'C & D' is not assignable to type 'A | B'. cnd = x; ~~~ -!!! error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'C & D'. +!!! error TS2322: Type 'A & B | C & D' is not assignable to type 'C & D'. !!! error TS2322: Type 'A & B' is not assignable to type 'C & D'. !!! error TS2322: Property 'c' is missing in type 'A & B' but required in type 'C'. !!! related TS2728 tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts:3:15: 'c' is declared here. cod = x; ~~~ -!!! error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'C | D'. +!!! error TS2322: Type 'A & B | C & D' is not assignable to type 'C | D'. !!! error TS2322: Type 'A & B' is not assignable to type 'C | D'. y = anb; diff --git a/tests/baselines/reference/intersectionAndUnionTypes.types b/tests/baselines/reference/intersectionAndUnionTypes.types index 0109cd1f7892e..ae031a211e92e 100644 --- a/tests/baselines/reference/intersectionAndUnionTypes.types +++ b/tests/baselines/reference/intersectionAndUnionTypes.types @@ -36,7 +36,7 @@ var cod: C | D; >cod : C | D var x: A & B | C & D; ->x : (A & B) | (C & D) +>x : A & B | C & D var y: (A | B) & (C | D); >y : (A | B) & (C | D) @@ -63,43 +63,43 @@ anb = b; x = anb; // Ok >x = anb : A & B ->x : (A & B) | (C & D) +>x : A & B | C & D >anb : A & B x = aob; >x = aob : A | B ->x : (A & B) | (C & D) +>x : A & B | C & D >aob : A | B x = cnd; // Ok >x = cnd : C & D ->x : (A & B) | (C & D) +>x : A & B | C & D >cnd : C & D x = cod; >x = cod : C | D ->x : (A & B) | (C & D) +>x : A & B | C & D >cod : C | D anb = x; ->anb = x : (A & B) | (C & D) +>anb = x : A & B | C & D >anb : A & B ->x : (A & B) | (C & D) +>x : A & B | C & D aob = x; ->aob = x : (A & B) | (C & D) +>aob = x : A & B | C & D >aob : A | B ->x : (A & B) | (C & D) +>x : A & B | C & D cnd = x; ->cnd = x : (A & B) | (C & D) +>cnd = x : A & B | C & D >cnd : C & D ->x : (A & B) | (C & D) +>x : A & B | C & D cod = x; ->cod = x : (A & B) | (C & D) +>cod = x : A & B | C & D >cod : C | D ->x : (A & B) | (C & D) +>x : A & B | C & D y = anb; >y = anb : A & B diff --git a/tests/baselines/reference/intersectionNarrowing.types b/tests/baselines/reference/intersectionNarrowing.types index 049e6c976eb6d..2a479d57dcfa4 100644 --- a/tests/baselines/reference/intersectionNarrowing.types +++ b/tests/baselines/reference/intersectionNarrowing.types @@ -2,11 +2,11 @@ // Repros from #43130 function f1(x: T & string | T & undefined) { ->f1 : (x: (T & string) | (T & undefined)) => void ->x : (T & string) | (T & undefined) +>f1 : (x: T & string | T & undefined) => void +>x : T & string | T & undefined if (x) { ->x : (T & string) | (T & undefined) +>x : T & string | T & undefined x; // Should narrow to T & string >x : T & string @@ -14,12 +14,12 @@ function f1(x: T & string | T & undefined) { } function f2(x: T & string | T & undefined) { ->f2 : (x: (T & string) | (T & undefined)) => void ->x : (T & string) | (T & undefined) +>f2 : (x: T & string | T & undefined) => void +>x : T & string | T & undefined if (x !== undefined) { >x !== undefined : boolean ->x : (T & string) | (T & undefined) +>x : T & string | T & undefined >undefined : undefined x; // Should narrow to T & string @@ -32,13 +32,13 @@ function f2(x: T & string | T & undefined) { } function f3(x: T & string | T & number) { ->f3 : (x: (T & string) | (T & number)) => void ->x : (T & string) | (T & number) +>f3 : (x: T & string | T & number) => void +>x : T & string | T & number if (typeof x === "string") { >typeof x === "string" : boolean >typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" ->x : (T & string) | (T & number) +>x : T & string | T & number >"string" : "string" x; // Should narrow to T & string @@ -51,11 +51,11 @@ function f3(x: T & string | T & number) { } function f4(x: T & 1 | T & 2) { ->f4 : (x: (T & 1) | (T & 2)) => void ->x : (T & 1) | (T & 2) +>f4 : (x: T & 1 | T & 2) => void +>x : T & 1 | T & 2 switch (x) { ->x : (T & 1) | (T & 2) +>x : T & 1 | T & 2 case 1: x; break; // T & 1 >1 : 1 diff --git a/tests/baselines/reference/intersectionOfUnionNarrowing.types b/tests/baselines/reference/intersectionOfUnionNarrowing.types index 27dc8f3dc6c6c..31bd761bf820b 100644 --- a/tests/baselines/reference/intersectionOfUnionNarrowing.types +++ b/tests/baselines/reference/intersectionOfUnionNarrowing.types @@ -20,9 +20,9 @@ declare const q: X & AorB; if (q.a !== undefined) { >q.a !== undefined : boolean ->q.a : ({ aProp: string; } & object) | undefined +>q.a : { aProp: string; } & object | undefined >q : X & AorB ->a : ({ aProp: string; } & object) | undefined +>a : { aProp: string; } & object | undefined >undefined : undefined q.a.aProp; diff --git a/tests/baselines/reference/keyofAndIndexedAccess2.types b/tests/baselines/reference/keyofAndIndexedAccess2.types index 048e11cad674d..6126559cbcdf5 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess2.types +++ b/tests/baselines/reference/keyofAndIndexedAccess2.types @@ -495,7 +495,7 @@ function fn4() { >'abc' : "abc" let y: ReadonlyArray[K] = 'abc'; ->y : readonly string[][K] +>y : (readonly string[])[K] >'abc' : "abc" } @@ -564,7 +564,7 @@ for (const action of actions) { window[action](x, y); >window[action](x, y) : void ->window[action] : (((x: number, y: number) => void) & ((x: number, y: number) => void)) | (((width: number, height: number) => void) & ((width: number, height: number) => void)) +>window[action] : ((x: number, y: number) => void) & ((x: number, y: number) => void) | ((width: number, height: number) => void) & ((width: number, height: number) => void) >window : Window & typeof globalThis >action : "resizeTo" | "resizeBy" >x : number diff --git a/tests/baselines/reference/narrowingByTypeofInSwitch.types b/tests/baselines/reference/narrowingByTypeofInSwitch.types index 2b028aad6bd16..50e07bbf5f710 100644 --- a/tests/baselines/reference/narrowingByTypeofInSwitch.types +++ b/tests/baselines/reference/narrowingByTypeofInSwitch.types @@ -564,8 +564,8 @@ function multipleGenericFuse(xy: X | case 'number': return [xy] >'number' : "number" ->[xy] : [(X & number) | (Y & number)] ->xy : (X & number) | (Y & number) +>[xy] : [X & number | Y & number] +>xy : X & number | Y & number } } @@ -1104,8 +1104,8 @@ function multipleGenericFuseWithBoth case `number`: return [xy] >`number` : "number" ->[xy] : [(X & number) | (Y & number)] ->xy : (X & number) | (Y & number) +>[xy] : [X & number | Y & number] +>xy : X & number | Y & number } } diff --git a/tests/baselines/reference/narrowingTypeofFunction.types b/tests/baselines/reference/narrowingTypeofFunction.types index 9342585ddd54e..517de20c4606b 100644 --- a/tests/baselines/reference/narrowingTypeofFunction.types +++ b/tests/baselines/reference/narrowingTypeofFunction.types @@ -7,12 +7,12 @@ interface F { (): string } function f1(a: (F & Meta) | string) { >f1 : (a: (F & Meta) | string) => void ->a : string | (F & Meta) +>a : string | F & Meta if (typeof a === "function") { >typeof a === "function" : boolean >typeof a : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" ->a : string | (F & Meta) +>a : string | F & Meta >"function" : "function" a; @@ -25,17 +25,17 @@ function f1(a: (F & Meta) | string) { } function f2(x: (T & F) | T & string) { ->f2 : (x: (T & F) | (T & string)) => void ->x : (T & F) | (T & string) +>f2 : (x: (T & F) | T & string) => void +>x : T & F | T & string if (typeof x === "function") { >typeof x === "function" : boolean >typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" ->x : (T & F) | (T & string) +>x : T & F | T & string >"function" : "function" x; ->x : (T & F) | (T & string) +>x : T & F | T & string } else { x; diff --git a/tests/baselines/reference/objectLiteralExcessProperties.errors.txt b/tests/baselines/reference/objectLiteralExcessProperties.errors.txt index 245293d9a7cb6..2684694bd7eff 100644 --- a/tests/baselines/reference/objectLiteralExcessProperties.errors.txt +++ b/tests/baselines/reference/objectLiteralExcessProperties.errors.txt @@ -26,7 +26,7 @@ tests/cases/compiler/objectLiteralExcessProperties.ts(41,11): error TS2322: Type '{ name: string; prop: boolean; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'IFoo'. tests/cases/compiler/objectLiteralExcessProperties.ts(43,43): error TS2322: Type '{ name: string; prop: true; }' is not assignable to type 'T | { prop: boolean; }'. Object literal may only specify known properties, and 'name' does not exist in type '{ prop: boolean; }'. -tests/cases/compiler/objectLiteralExcessProperties.ts(45,76): error TS2322: Type '{ name: string; prop: boolean; }' is not assignable to type '(T & { prop: boolean; }) | { name: string; }'. +tests/cases/compiler/objectLiteralExcessProperties.ts(45,76): error TS2322: Type '{ name: string; prop: boolean; }' is not assignable to type 'T & { prop: boolean; } | { name: string; }'. Object literal may only specify known properties, and 'prop' does not exist in type '{ name: string; }'. tests/cases/compiler/objectLiteralExcessProperties.ts(49,44): error TS2322: Type '{ z: string; }' is not assignable to type 'object & { x: string; }'. Object literal may only specify known properties, and 'z' does not exist in type 'object & { x: string; }'. @@ -122,7 +122,7 @@ tests/cases/compiler/objectLiteralExcessProperties.ts(49,44): error TS2322: Type // Excess property checks only on non-generic parts of unions const obj4: T & { prop: boolean } | { name: string } = { name: "test", prop: true }; ~~~~~~~~~~ -!!! error TS2322: Type '{ name: string; prop: boolean; }' is not assignable to type '(T & { prop: boolean; }) | { name: string; }'. +!!! error TS2322: Type '{ name: string; prop: boolean; }' is not assignable to type 'T & { prop: boolean; } | { name: string; }'. !!! error TS2322: Object literal may only specify known properties, and 'prop' does not exist in type '{ name: string; }'. // No excess property checks when union includes 'object' type const obj5: object | { x: string } = { z: 'abc' } diff --git a/tests/baselines/reference/objectLiteralExcessProperties.types b/tests/baselines/reference/objectLiteralExcessProperties.types index cd3be132fe2d3..1fe01891583a5 100644 --- a/tests/baselines/reference/objectLiteralExcessProperties.types +++ b/tests/baselines/reference/objectLiteralExcessProperties.types @@ -132,7 +132,7 @@ function test() { // Excess property checks only on non-generic parts of unions const obj4: T & { prop: boolean } | { name: string } = { name: "test", prop: true }; ->obj4 : (T & { prop: boolean; }) | { name: string; } +>obj4 : T & { prop: boolean; } | { name: string; } >prop : boolean >name : string >{ name: "test", prop: true } : { name: string; prop: boolean; } diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index 7fd7675d1d73d..9ca8206f92991 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -670,8 +670,8 @@ function genericSpread(t: T, u: U, v: T | U, w: T | { s: string }, obj: { >v : T | U let x12 = { ...v, ...obj }; ->x12 : (T & { x: number; }) | (U & { x: number; }) ->{ ...v, ...obj } : (T & { x: number; }) | (U & { x: number; }) +>x12 : T & { x: number; } | U & { x: number; } +>{ ...v, ...obj } : T & { x: number; } | U & { x: number; } >v : T | U >obj : { x: number; } @@ -681,33 +681,33 @@ function genericSpread(t: T, u: U, v: T | U, w: T | { s: string }, obj: { >w : T | { s: string; } let x14 = { ...w, ...obj }; ->x14 : (T & { x: number; }) | { x: number; s: string; } ->{ ...w, ...obj } : (T & { x: number; }) | { x: number; s: string; } +>x14 : T & { x: number; } | { x: number; s: string; } +>{ ...w, ...obj } : T & { x: number; } | { x: number; s: string; } >w : T | { s: string; } >obj : { x: number; } let x15 = { ...t, ...v }; ->x15 : T | (T & U) ->{ ...t, ...v } : T | (T & U) +>x15 : T | T & U +>{ ...t, ...v } : T | T & U >t : T >v : T | U let x16 = { ...t, ...w }; ->x16 : T | (T & { s: string; }) ->{ ...t, ...w } : T | (T & { s: string; }) +>x16 : T | T & { s: string; } +>{ ...t, ...w } : T | T & { s: string; } >t : T >w : T | { s: string; } let x17 = { ...t, ...w, ...obj }; ->x17 : (T & { x: number; }) | (T & { x: number; s: string; }) ->{ ...t, ...w, ...obj } : (T & { x: number; }) | (T & { x: number; s: string; }) +>x17 : T & { x: number; } | T & { x: number; s: string; } +>{ ...t, ...w, ...obj } : T & { x: number; } | T & { x: number; s: string; } >t : T >w : T | { s: string; } >obj : { x: number; } let x18 = { ...t, ...v, ...w }; ->x18 : T | (T & U) | (T & { s: string; }) | (T & U & { s: string; }) ->{ ...t, ...v, ...w } : T | (T & U) | (T & { s: string; }) | (T & U & { s: string; }) +>x18 : T | T & U | T & { s: string; } | T & U & { s: string; } +>{ ...t, ...v, ...w } : T | T & U | T & { s: string; } | T & U & { s: string; } >t : T >v : T | U >w : T | { s: string; } diff --git a/tests/baselines/reference/partialOfLargeAPIIsAbleToBeWorkedWith.types b/tests/baselines/reference/partialOfLargeAPIIsAbleToBeWorkedWith.types index fbd46f7fdce2e..ec22725fd3819 100644 --- a/tests/baselines/reference/partialOfLargeAPIIsAbleToBeWorkedWith.types +++ b/tests/baselines/reference/partialOfLargeAPIIsAbleToBeWorkedWith.types @@ -222,7 +222,7 @@ for (const k of keys) { obj[k] = () => "12"; // shouldn't cause a complexity error >obj[k] = () => "12" : () => string ->obj[k] : (((x: 0) => string) & ((x: 1) => string) & ((x: 2) => string) & ((x: 3) => string) & ((x: 4) => string) & ((x: 5) => string) & ((x: 6) => string) & ((x: 7) => string) & ((x: 8) => string) & ((x: 9) => string) & ((x: 10) => string) & ((x: 11) => string) & ((x: 12) => string) & ((x: 13) => string) & ((x: 14) => string) & ((x: 15) => string) & ((x: 16) => string) & ((x: 17) => string) & ((x: 18) => string) & ((x: 19) => string) & ((x: 20) => string) & ((x: 21) => string) & ((x: 22) => string) & ((x: 23) => string) & ((x: 24) => string) & ((x: 25) => string) & ((x: 26) => string) & ((x: 27) => string) & ((x: 28) => string) & ((x: 29) => string) & ((x: 30) => string) & ((x: 31) => string) & ((x: 32) => string) & ((x: 33) => string) & ((x: 34) => string) & ((x: 35) => string) & ((x: 36) => string) & ((x: 37) => string) & ((x: 38) => string) & ((x: 39) => string) & ((x: 40) => string) & ((x: 41) => string) & ((x: 42) => string) & ((x: 43) => string) & ((x: 44) => string) & ((x: 45) => string) & ((x: 46) => string) & ((x: 47) => string) & ((x: 48) => string) & ((x: 49) => string) & ((x: 50) => string) & ((x: 51) => string)) | undefined +>obj[k] : ((x: 0) => string) & ((x: 1) => string) & ((x: 2) => string) & ((x: 3) => string) & ((x: 4) => string) & ((x: 5) => string) & ((x: 6) => string) & ((x: 7) => string) & ((x: 8) => string) & ((x: 9) => string) & ((x: 10) => string) & ((x: 11) => string) & ((x: 12) => string) & ((x: 13) => string) & ((x: 14) => string) & ((x: 15) => string) & ((x: 16) => string) & ((x: 17) => string) & ((x: 18) => string) & ((x: 19) => string) & ((x: 20) => string) & ((x: 21) => string) & ((x: 22) => string) & ((x: 23) => string) & ((x: 24) => string) & ((x: 25) => string) & ((x: 26) => string) & ((x: 27) => string) & ((x: 28) => string) & ((x: 29) => string) & ((x: 30) => string) & ((x: 31) => string) & ((x: 32) => string) & ((x: 33) => string) & ((x: 34) => string) & ((x: 35) => string) & ((x: 36) => string) & ((x: 37) => string) & ((x: 38) => string) & ((x: 39) => string) & ((x: 40) => string) & ((x: 41) => string) & ((x: 42) => string) & ((x: 43) => string) & ((x: 44) => string) & ((x: 45) => string) & ((x: 46) => string) & ((x: 47) => string) & ((x: 48) => string) & ((x: 49) => string) & ((x: 50) => string) & ((x: 51) => string) | undefined >obj : Partial >k : keyof MyAPI >() => "12" : () => string @@ -243,7 +243,7 @@ for (const k of keys) { obj2[k] = () => "12"; // shouldn't cause a complexity error >obj2[k] = () => "12" : () => string ->obj2[k] : (((x: 0) => string) & ((x: 1) => string) & ((x: 2) => string) & ((x: 3) => string) & ((x: 4) => string) & ((x: 5) => string) & ((x: 6) => string) & ((x: 7) => string) & ((x: 8) => string) & ((x: 9) => string) & ((x: 10) => string) & ((x: 11) => string) & ((x: 12) => string) & ((x: 13) => string) & ((x: 14) => string) & ((x: 15) => string) & ((x: 16) => string) & ((x: 17) => string) & ((x: 18) => string) & ((x: 19) => string) & ((x: 20) => string) & ((x: 21) => string) & ((x: 22) => string) & ((x: 23) => string) & ((x: 24) => string) & ((x: 25) => string) & ((x: 26) => string) & ((x: 27) => string) & ((x: 28) => string) & ((x: 29) => string) & ((x: 30) => string) & ((x: 31) => string) & ((x: 32) => string) & ((x: 33) => string) & ((x: 34) => string) & ((x: 35) => string) & ((x: 36) => string) & ((x: 37) => string) & ((x: 38) => string) & ((x: 39) => string) & ((x: 40) => string) & ((x: 41) => string) & ((x: 42) => string) & ((x: 43) => string) & ((x: 44) => string) & ((x: 45) => string) & ((x: 46) => string) & ((x: 47) => string) & ((x: 48) => string) & ((x: 49) => string) & ((x: 50) => string) & ((x: 51) => string)) | null | undefined +>obj2[k] : ((x: 0) => string) & ((x: 1) => string) & ((x: 2) => string) & ((x: 3) => string) & ((x: 4) => string) & ((x: 5) => string) & ((x: 6) => string) & ((x: 7) => string) & ((x: 8) => string) & ((x: 9) => string) & ((x: 10) => string) & ((x: 11) => string) & ((x: 12) => string) & ((x: 13) => string) & ((x: 14) => string) & ((x: 15) => string) & ((x: 16) => string) & ((x: 17) => string) & ((x: 18) => string) & ((x: 19) => string) & ((x: 20) => string) & ((x: 21) => string) & ((x: 22) => string) & ((x: 23) => string) & ((x: 24) => string) & ((x: 25) => string) & ((x: 26) => string) & ((x: 27) => string) & ((x: 28) => string) & ((x: 29) => string) & ((x: 30) => string) & ((x: 31) => string) & ((x: 32) => string) & ((x: 33) => string) & ((x: 34) => string) & ((x: 35) => string) & ((x: 36) => string) & ((x: 37) => string) & ((x: 38) => string) & ((x: 39) => string) & ((x: 40) => string) & ((x: 41) => string) & ((x: 42) => string) & ((x: 43) => string) & ((x: 44) => string) & ((x: 45) => string) & ((x: 46) => string) & ((x: 47) => string) & ((x: 48) => string) & ((x: 49) => string) & ((x: 50) => string) & ((x: 51) => string) | null | undefined >obj2 : PartialNull >k : keyof MyAPI >() => "12" : () => string diff --git a/tests/baselines/reference/primitiveUnionDetection.types b/tests/baselines/reference/primitiveUnionDetection.types index ac2243d80d4aa..053ea81c39aaa 100644 --- a/tests/baselines/reference/primitiveUnionDetection.types +++ b/tests/baselines/reference/primitiveUnionDetection.types @@ -5,15 +5,15 @@ type Kind = "one" | "two" | "three"; >Kind : Kind declare function getInterfaceFromString(options?: { type?: T } & { type?: Kind }): T; ->getInterfaceFromString : (options?: ({ type?: T | undefined; } & { type?: Kind | undefined; }) | undefined) => T ->options : ({ type?: T | undefined; } & { type?: Kind | undefined; }) | undefined +>getInterfaceFromString : (options?: { type?: T | undefined; } & { type?: Kind | undefined; } | undefined) => T +>options : { type?: T | undefined; } & { type?: Kind | undefined; } | undefined >type : T | undefined >type : Kind | undefined const result = getInterfaceFromString({ type: 'two' }); >result : "two" >getInterfaceFromString({ type: 'two' }) : "two" ->getInterfaceFromString : (options?: ({ type?: T | undefined; } & { type?: Kind | undefined; }) | undefined) => T +>getInterfaceFromString : (options?: { type?: T | undefined; } & { type?: Kind | undefined; } | undefined) => T >{ type: 'two' } : { type: "two"; } >type : "two" >'two' : "two" diff --git a/tests/baselines/reference/spreadObjectOrFalsy.js b/tests/baselines/reference/spreadObjectOrFalsy.js index 9aae56dc08562..17f6dac60d75c 100644 --- a/tests/baselines/reference/spreadObjectOrFalsy.js +++ b/tests/baselines/reference/spreadObjectOrFalsy.js @@ -104,7 +104,7 @@ var Foo = /** @class */ (function () { //// [spreadObjectOrFalsy.d.ts] declare function f1(a: T & undefined): any; -declare function f2(a: T | T & undefined): T | (T & undefined); +declare function f2(a: T | T & undefined): T | T & undefined; declare function f3(a: T): any; declare function f4(a: object | T): {}; declare function f5(a: S | T): S | T; diff --git a/tests/baselines/reference/spreadObjectOrFalsy.types b/tests/baselines/reference/spreadObjectOrFalsy.types index 1b9d54512e9f7..548b14e7ca2d7 100644 --- a/tests/baselines/reference/spreadObjectOrFalsy.types +++ b/tests/baselines/reference/spreadObjectOrFalsy.types @@ -9,12 +9,12 @@ function f1(a: T & undefined) { } function f2(a: T | T & undefined) { ->f2 : (a: T | (T & undefined)) => T | (T & undefined) ->a : T | (T & undefined) +>f2 : (a: T | T & undefined) => T | T & undefined +>a : T | T & undefined return { ...a }; ->{ ...a } : T | (T & undefined) ->a : T | (T & undefined) +>{ ...a } : T | T & undefined +>a : T | T & undefined } function f3(a: T) { diff --git a/tests/baselines/reference/staticFieldWithInterfaceContext.types b/tests/baselines/reference/staticFieldWithInterfaceContext.types index 0b109f955c1a1..6fc0bc7f50dc0 100644 --- a/tests/baselines/reference/staticFieldWithInterfaceContext.types +++ b/tests/baselines/reference/staticFieldWithInterfaceContext.types @@ -107,7 +107,7 @@ let [ c6 ]: [I] = [class { static x = { a: "a" } }]; let [ c7 ]: I[] = [class { static x = { a: "a" } }]; >c7 : I ->[class { static x = { a: "a" } }] : (typeof (Anonymous class))[] +>[class { static x = { a: "a" } }] : typeof (Anonymous class)[] >class { static x = { a: "a" } } : typeof (Anonymous class) >x : { a: "a"; } >{ a: "a" } : { a: "a"; } @@ -153,7 +153,7 @@ let [ c11 = class { static x = { a: "a" } } ]: I[] = [class { static x = { a: "a >{ a: "a" } : { a: "a"; } >a : "a" >"a" : "a" ->[class { static x = { a: "a" } }] : (typeof (Anonymous class))[] +>[class { static x = { a: "a" } }] : typeof (Anonymous class)[] >class { static x = { a: "a" } } : typeof (Anonymous class) >x : { a: "a"; } >{ a: "a" } : { a: "a"; } diff --git a/tests/baselines/reference/templateLiteralTypes2.types b/tests/baselines/reference/templateLiteralTypes2.types index e771c63c5357c..9497a507c95e6 100644 --- a/tests/baselines/reference/templateLiteralTypes2.types +++ b/tests/baselines/reference/templateLiteralTypes2.types @@ -402,12 +402,12 @@ const interpolatedStyle = { rotate: 12 }; function C2(transform: "-moz-initial" | (string & {})) { return 12; } >C2 : (transform: "-moz-initial" | (string & {})) => number ->transform : (string & {}) | "-moz-initial" +>transform : string & {} | "-moz-initial" >12 : 12 C2(`rotate(${interpolatedStyle.rotate}dig)`); >C2(`rotate(${interpolatedStyle.rotate}dig)`) : number ->C2 : (transform: (string & {}) | "-moz-initial") => number +>C2 : (transform: string & {} | "-moz-initial") => number >`rotate(${interpolatedStyle.rotate}dig)` : `rotate(${number}dig)` >interpolatedStyle.rotate : number >interpolatedStyle : { rotate: number; } diff --git a/tests/baselines/reference/thisTypeInObjectLiterals2.types b/tests/baselines/reference/thisTypeInObjectLiterals2.types index 227be40f79f39..a5447768337e4 100644 --- a/tests/baselines/reference/thisTypeInObjectLiterals2.types +++ b/tests/baselines/reference/thisTypeInObjectLiterals2.types @@ -407,7 +407,7 @@ type ObjectDescriptor = { >data : D | undefined methods?: M & ThisType; // Type of 'this' in methods is D & M ->methods : (M & ThisType) | undefined +>methods : M & ThisType | undefined } declare function makeObject(desc: ObjectDescriptor): D & M; diff --git a/tests/baselines/reference/typeGuardIntersectionTypes.types b/tests/baselines/reference/typeGuardIntersectionTypes.types index a9f43b4917930..c7c573e1cbb13 100644 --- a/tests/baselines/reference/typeGuardIntersectionTypes.types +++ b/tests/baselines/reference/typeGuardIntersectionTypes.types @@ -92,7 +92,7 @@ function isB(toTest: any): toTest is B { // a function that turns an A into an A & B function union(a: A): A & B | null { ->union : (a: A) => (A & B) | null +>union : (a: A) => A & B | null >a : A >null : null diff --git a/tests/baselines/reference/typeGuardsWithInstanceOf.errors.txt b/tests/baselines/reference/typeGuardsWithInstanceOf.errors.txt index ee651e82e7d39..3332be7ef9c30 100644 --- a/tests/baselines/reference/typeGuardsWithInstanceOf.errors.txt +++ b/tests/baselines/reference/typeGuardsWithInstanceOf.errors.txt @@ -1,8 +1,8 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOf.ts(7,20): error TS2339: Property 'global' does not exist on type 'never'. The intersection 'I & RegExp' was reduced to 'never' because property 'global' has conflicting types in some constituents. -tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOf.ts(36,11): error TS2339: Property 'onChanges' does not exist on type 'C | (Validator & Partial)'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOf.ts(36,11): error TS2339: Property 'onChanges' does not exist on type 'C | Validator & Partial'. Property 'onChanges' does not exist on type 'C'. -tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOf.ts(37,11): error TS2339: Property 'onChanges' does not exist on type 'C | (Validator & Partial)'. +tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOf.ts(37,11): error TS2339: Property 'onChanges' does not exist on type 'C | Validator & Partial'. Property 'onChanges' does not exist on type 'C'. @@ -47,11 +47,11 @@ tests/cases/conformance/expressions/typeGuards/typeGuardsWithInstanceOf.ts(37,11 // before 4.1. if (v.onChanges) { ~~~~~~~~~ -!!! error TS2339: Property 'onChanges' does not exist on type 'C | (Validator & Partial)'. +!!! error TS2339: Property 'onChanges' does not exist on type 'C | Validator & Partial'. !!! error TS2339: Property 'onChanges' does not exist on type 'C'. v.onChanges({}); ~~~~~~~~~ -!!! error TS2339: Property 'onChanges' does not exist on type 'C | (Validator & Partial)'. +!!! error TS2339: Property 'onChanges' does not exist on type 'C | Validator & Partial'. !!! error TS2339: Property 'onChanges' does not exist on type 'C'. } } diff --git a/tests/baselines/reference/typeGuardsWithInstanceOf.types b/tests/baselines/reference/typeGuardsWithInstanceOf.types index 0b57dbff89bf1..6b96624610e3e 100644 --- a/tests/baselines/reference/typeGuardsWithInstanceOf.types +++ b/tests/baselines/reference/typeGuardsWithInstanceOf.types @@ -68,7 +68,7 @@ function foo() { >v : C } v // Validator & Partial via subtype reduction ->v : C | (Validator & Partial) +>v : C | Validator & Partial // In 4.1, we introduced a change which _fixed_ a bug with CFA // correctly setting this to be the right object. With 4.2, @@ -76,13 +76,13 @@ function foo() { // before 4.1. if (v.onChanges) { >v.onChanges : any ->v : C | (Validator & Partial) +>v : C | Validator & Partial >onChanges : any v.onChanges({}); >v.onChanges({}) : any >v.onChanges : any ->v : C | (Validator & Partial) +>v : C | Validator & Partial >onChanges : any >{} : {} } diff --git a/tests/baselines/reference/unionTypeInference.types b/tests/baselines/reference/unionTypeInference.types index 268d4ed86ebfb..8fdec5844d63e 100644 --- a/tests/baselines/reference/unionTypeInference.types +++ b/tests/baselines/reference/unionTypeInference.types @@ -213,26 +213,26 @@ async function fun(deepPromised: DeepPromised) { >deepPromised : DeepPromised for (const value of Object.values(deepPromisedWithIndexer)) { ->value : {} | ({ [containsPromises]?: true | undefined; } & {}) | Promise<{ [containsPromises]?: true | undefined; } & {}> | null | undefined ->Object.values(deepPromisedWithIndexer) : ({} | ({ [containsPromises]?: true | undefined; } & {}) | Promise<{ [containsPromises]?: true | undefined; } & {}> | null | undefined)[] +>value : {} | { [containsPromises]?: true | undefined; } & {} | Promise<{ [containsPromises]?: true | undefined; } & {}> | null | undefined +>Object.values(deepPromisedWithIndexer) : ({} | { [containsPromises]?: true | undefined; } & {} | Promise<{ [containsPromises]?: true | undefined; } & {}> | null | undefined)[] >Object.values : { (o: { [s: string]: T; } | ArrayLike): T[]; (o: {}): any[]; } >Object : ObjectConstructor >values : { (o: { [s: string]: T; } | ArrayLike): T[]; (o: {}): any[]; } >deepPromisedWithIndexer : DeepPromised<{ [name: string]: {} | null | undefined; }> const awaitedValue = await value; ->awaitedValue : {} | ({ [containsPromises]?: true | undefined; } & {}) | null | undefined ->await value : {} | ({ [containsPromises]?: true | undefined; } & {}) | null | undefined ->value : {} | ({ [containsPromises]?: true | undefined; } & {}) | Promise<{ [containsPromises]?: true | undefined; } & {}> | null | undefined +>awaitedValue : {} | { [containsPromises]?: true | undefined; } & {} | null | undefined +>await value : {} | { [containsPromises]?: true | undefined; } & {} | null | undefined +>value : {} | { [containsPromises]?: true | undefined; } & {} | Promise<{ [containsPromises]?: true | undefined; } & {}> | null | undefined if (awaitedValue) ->awaitedValue : {} | ({ [containsPromises]?: true | undefined; } & {}) | null | undefined +>awaitedValue : {} | { [containsPromises]?: true | undefined; } & {} | null | undefined await fun(awaitedValue); >await fun(awaitedValue) : void >fun(awaitedValue) : Promise >fun : (deepPromised: DeepPromised) => Promise ->awaitedValue : {} | ({ [containsPromises]?: true | undefined; } & {}) +>awaitedValue : {} | { [containsPromises]?: true | undefined; } & {} } } diff --git a/tests/cases/conformance/types/conditional/inferTypesWithExtends1.ts b/tests/cases/conformance/types/conditional/inferTypesWithExtends1.ts index e58fe7a2f16d2..62bb69c01a62b 100644 --- a/tests/cases/conformance/types/conditional/inferTypesWithExtends1.ts +++ b/tests/cases/conformance/types/conditional/inferTypesWithExtends1.ts @@ -23,8 +23,8 @@ type X2_T3 = X2<(a: object) => void>; // never // infer to return type type X3 any> = - T extends (...args: any[]) => infer U extends string ? ["string", U] : - T extends (...args: any[]) => infer U extends number ? ["number", U] : + T extends (...args: any[]) => (infer U extends string) ? ["string", U] : + T extends (...args: any[]) => (infer U extends number) ? ["number", U] : never; type X3_T1 = X3<() => "a">; // ["string", "a"] @@ -33,8 +33,8 @@ type X3_T3 = X3<() => object>; // never // infer to instance type type X4 any> = - T extends new (...args: any[]) => infer U extends { a: string } ? ["string", U] : - T extends new (...args: any[]) => infer U extends { a: number } ? ["number", U] : + T extends new (...args: any[]) => (infer U extends { a: string }) ? ["string", U] : + T extends new (...args: any[]) => (infer U extends { a: number }) ? ["number", U] : never; type X4_T1 = X4 { a: "a" }>; // ["string", { a: "a" }] @@ -93,3 +93,17 @@ type X9_T1 = X9<{ a: "a", b: "b" }>; // ["string", "a" | "b"] type X9_T2 = X9<{ a: 1, b: 2 }>; // ["number", 1 | 2] type X9_T3 = X9<{ a: object, b: object }>; // never type X9_T4 = X9<{ a: "a", b: 1 }>; // never + +// Speculative lookahead for `infer T extends U ?` +type X10 = T extends (infer U extends number ? 1 : 0) ? 1 : 0; // ok, parsed as conditional +type X10_Y1 = X10; +type X10_T1_T1 = X10_Y1; + +type X11 = T extends ((infer U) extends number ? 1 : 0) ? 1 : 0; // ok, parsed as conditional +type X12 = T extends (infer U extends number) ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`) +type X13 = T extends infer U extends number ? 1 : 0; // ok, parsed as `infer..extends` (conditional types not allowed in 'extends type') +type X14 = T extends keyof infer U extends number ? 1 : 0; // ok, parsed as `infer..extends` (precedence wouldn't have parsed the `?` as part of a type operator) +type X15 = T extends { [P in infer U extends keyof T ? 1 : 0]: 1; } ? 1 : 0; // ok, parsed as conditional +type X16 = T extends { [P in infer U extends keyof T]: 1; } ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`) +type X17 = T extends { [P in keyof T as infer U extends P ? 1 : 0]: 1; } ? 1 : 0; // ok, parsed as conditional +type X18 = T extends { [P in keyof T as infer U extends P]: 1; } ? 1 : 0; // ok, parsed as `infer..extends` (no trailing `?`) diff --git a/tests/cases/fourslash/codeFixAddVoidToPromise.4.ts b/tests/cases/fourslash/codeFixAddVoidToPromise.4.ts index b414cb4d1e730..2f2770b436cd1 100644 --- a/tests/cases/fourslash/codeFixAddVoidToPromise.4.ts +++ b/tests/cases/fourslash/codeFixAddVoidToPromise.4.ts @@ -10,5 +10,5 @@ verify.codeFix({ errorCode: 2794, description: "Add 'void' to Promise resolved without a value", index: 0, - newFileContent: `const p4 = new Promise<({ x: number } & { y: string }) | void>(resolve => resolve());` + newFileContent: `const p4 = new Promise<{ x: number } & { y: string } | void>(resolve => resolve());` }); diff --git a/tests/cases/fourslash/codeFixAddVoidToPromiseJS.4.ts b/tests/cases/fourslash/codeFixAddVoidToPromiseJS.4.ts index 171e1135d1aec..844d50185166f 100644 --- a/tests/cases/fourslash/codeFixAddVoidToPromiseJS.4.ts +++ b/tests/cases/fourslash/codeFixAddVoidToPromiseJS.4.ts @@ -12,5 +12,5 @@ verify.codeFix({ errorCode: 2794, description: "Add 'void' to Promise resolved without a value", index: 2, - newFileContent: `const p4 = /** @type {Promise<({ x: number } & { y: string }) | void>} */(new Promise(resolve => resolve()));` + newFileContent: `const p4 = /** @type {Promise<{ x: number } & { y: string } | void>} */(new Promise(resolve => resolve()));` }); diff --git a/tests/cases/fourslash/codeFixAddVoidToPromiseJS_all.ts b/tests/cases/fourslash/codeFixAddVoidToPromiseJS_all.ts index 5c37cd851d9ae..55446cfbfdefd 100644 --- a/tests/cases/fourslash/codeFixAddVoidToPromiseJS_all.ts +++ b/tests/cases/fourslash/codeFixAddVoidToPromiseJS_all.ts @@ -17,5 +17,5 @@ verify.codeFixAll({ newFileContent: `const p1 = /** @type {Promise} */(new Promise(resolve => resolve())); const p2 = /** @type {Promise} */(new Promise(resolve => resolve())); const p3 = /** @type {Promise} */(new Promise(resolve => resolve())); -const p4 = /** @type {Promise<({ x: number } & { y: string }) | void>} */(new Promise(resolve => resolve()));` +const p4 = /** @type {Promise<{ x: number } & { y: string } | void>} */(new Promise(resolve => resolve()));` }); diff --git a/tests/cases/fourslash/codeFixAddVoidToPromise_all.ts b/tests/cases/fourslash/codeFixAddVoidToPromise_all.ts index 6f31d3388f211..b3da799ea8d07 100644 --- a/tests/cases/fourslash/codeFixAddVoidToPromise_all.ts +++ b/tests/cases/fourslash/codeFixAddVoidToPromise_all.ts @@ -15,5 +15,5 @@ verify.codeFixAll({ newFileContent: `const p1 = new Promise(resolve => resolve()); const p2 = new Promise(resolve => resolve()); const p3 = new Promise(resolve => resolve()); -const p4 = new Promise<({ x: number } & { y: string }) | void>(resolve => resolve());` +const p4 = new Promise<{ x: number } & { y: string } | void>(resolve => resolve());` });