From 8fd5eda16f3a6173654786987d8b2bf872b18ba0 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Thu, 3 Mar 2022 14:47:07 -0800 Subject: [PATCH 1/6] Add 'extends' clause to 'infer' type --- src/compiler/checker.ts | 22 +- src/compiler/diagnosticMessages.json | 4 + src/compiler/factory/nodeFactory.ts | 2 +- src/compiler/factory/parenthesizerRules.ts | 7 + src/compiler/parser.ts | 20 +- src/compiler/types.ts | 1 + .../reference/inferTypes1.errors.txt | 16 +- tests/baselines/reference/inferTypes1.js | 4 +- tests/baselines/reference/inferTypes1.symbols | 32 +- tests/baselines/reference/inferTypes1.types | 4 +- tests/baselines/reference/inferTypes2.js | 2 +- tests/baselines/reference/inferTypes2.types | 8 +- .../reference/inferTypesWithExtends1.js | 213 +++++++++++ .../reference/inferTypesWithExtends1.symbols | 343 ++++++++++++++++++ .../reference/inferTypesWithExtends1.types | 235 ++++++++++++ .../inferTypesWithExtends2.errors.txt | 14 + .../reference/inferTypesWithExtends2.js | 9 + .../reference/inferTypesWithExtends2.symbols | 16 + .../reference/inferTypesWithExtends2.types | 11 + .../types/conditional/inferTypes1.ts | 4 +- .../conditional/inferTypesWithExtends1.ts | 95 +++++ .../conditional/inferTypesWithExtends2.ts | 6 + .../cases/fourslash/refactorExtractType48.ts | 4 +- 23 files changed, 1017 insertions(+), 55 deletions(-) create mode 100644 tests/baselines/reference/inferTypesWithExtends1.js create mode 100644 tests/baselines/reference/inferTypesWithExtends1.symbols create mode 100644 tests/baselines/reference/inferTypesWithExtends1.types create mode 100644 tests/baselines/reference/inferTypesWithExtends2.errors.txt create mode 100644 tests/baselines/reference/inferTypesWithExtends2.js create mode 100644 tests/baselines/reference/inferTypesWithExtends2.symbols create mode 100644 tests/baselines/reference/inferTypesWithExtends2.types create mode 100644 tests/cases/conformance/types/conditional/inferTypesWithExtends1.ts create mode 100644 tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ccd4a50b37998..a7fe815d0a218 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -35538,6 +35538,22 @@ namespace ts { grammarErrorOnNode(node, Diagnostics.infer_declarations_are_only_permitted_in_the_extends_clause_of_a_conditional_type); } checkSourceElement(node.typeParameter); + const symbol = getSymbolOfNode(node.typeParameter); + if (symbol.declarations && symbol.declarations.length > 1) { + const links = getSymbolLinks(symbol); + if (!links.typeParametersChecked) { + links.typeParametersChecked = true; + const typeParameter = getDeclaredTypeOfTypeParameter(symbol); + const declarations: TypeParameterDeclaration[] = getDeclarationsOfKind(symbol, SyntaxKind.TypeParameter); + if (!areTypeParametersIdentical(declarations, [typeParameter], decl => [decl])) { + // Report an error on every conflicting declaration. + const name = symbolToString(symbol); + for (const declaration of declarations) { + error(declaration.name, Diagnostics.All_declarations_of_0_must_have_identical_constraints, name); + } + } + } + } registerForUnusedIdentifiersCheck(node); } @@ -39014,7 +39030,7 @@ namespace ts { } const type = getDeclaredTypeOfSymbol(symbol) as InterfaceType; - if (!areTypeParametersIdentical(declarations, type.localTypeParameters!)) { + if (!areTypeParametersIdentical(declarations, type.localTypeParameters!, getEffectiveTypeParameterDeclarations)) { // Report an error on every conflicting declaration. const name = symbolToString(symbol); for (const declaration of declarations) { @@ -39024,13 +39040,13 @@ namespace ts { } } - function areTypeParametersIdentical(declarations: readonly (ClassDeclaration | InterfaceDeclaration)[], targetParameters: TypeParameter[]) { + function areTypeParametersIdentical(declarations: readonly T[], targetParameters: TypeParameter[], getTypeParameterDeclarations: (node: T) => readonly TypeParameterDeclaration[]) { const maxTypeArgumentCount = length(targetParameters); const minTypeArgumentCount = getMinTypeArgumentCount(targetParameters); for (const declaration of declarations) { // If this declaration has too few or too many type parameters, we report an error - const sourceParameters = getEffectiveTypeParameterDeclarations(declaration); + const sourceParameters = getTypeParameterDeclarations(declaration); const numTypeParameters = sourceParameters.length; if (numTypeParameters < minTypeArgumentCount || numTypeParameters > maxTypeArgumentCount) { return false; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 387d7123beb4b..4265cd42378cb 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3413,6 +3413,10 @@ "category": "Error", "code": 2837 }, + "All declarations of '{0}' must have identical constraints.": { + "category": "Error", + "code": 2838 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index 633b4c2c5cd3e..1a98fddbed303 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -1989,7 +1989,7 @@ namespace ts { // @api function createConditionalTypeNode(checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode) { const node = createBaseNode(SyntaxKind.ConditionalType); - node.checkType = parenthesizerRules().parenthesizeMemberOfConditionalType(checkType); + node.checkType = parenthesizerRules().parenthesizeCheckTypeOfConditionalType(checkType); node.extendsType = parenthesizerRules().parenthesizeMemberOfConditionalType(extendsType); node.trueType = trueType; node.falseType = falseType; diff --git a/src/compiler/factory/parenthesizerRules.ts b/src/compiler/factory/parenthesizerRules.ts index 1e2cb936582fa..e921f08bfc69f 100644 --- a/src/compiler/factory/parenthesizerRules.ts +++ b/src/compiler/factory/parenthesizerRules.ts @@ -25,6 +25,7 @@ namespace ts { parenthesizeExpressionForDisallowedComma, parenthesizeExpressionOfExpressionStatement, parenthesizeConciseBodyOfArrowFunction, + parenthesizeCheckTypeOfConditionalType, parenthesizeMemberOfConditionalType, parenthesizeMemberOfElementType, parenthesizeElementTypeOfArrayType, @@ -388,6 +389,11 @@ namespace ts { return body; } + function parenthesizeCheckTypeOfConditionalType(member: TypeNode): TypeNode { + return isInferTypeNode(member) ? factory.createParenthesizedType(member) : + parenthesizeMemberOfConditionalType(member); + } + function parenthesizeMemberOfConditionalType(member: TypeNode): TypeNode { return member.kind === SyntaxKind.ConditionalType ? factory.createParenthesizedType(member) : member; } @@ -446,6 +452,7 @@ namespace ts { parenthesizeExpressionForDisallowedComma: identity, parenthesizeExpressionOfExpressionStatement: identity, parenthesizeConciseBodyOfArrowFunction: identity, + parenthesizeCheckTypeOfConditionalType: identity, parenthesizeMemberOfConditionalType: identity, parenthesizeMemberOfElementType: identity, parenthesizeElementTypeOfArrayType: identity, diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 898f50c475eff..570cad9621983 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3155,6 +3155,10 @@ namespace ts { } function parseTypeParameter(): TypeParameterDeclaration { + return parseTypeParameterWorker(/*canHaveDefault*/ true); + } + + function parseTypeParameterWorker(canHaveDefault: boolean): TypeParameterDeclaration { const pos = getNodePos(); const name = parseIdentifier(); let constraint: TypeNode | undefined; @@ -3179,7 +3183,7 @@ namespace ts { } } - const defaultType = parseOptional(SyntaxKind.EqualsToken) ? parseType() : undefined; + const defaultType = canHaveDefault && parseOptional(SyntaxKind.EqualsToken) ? parseType() : undefined; const node = factory.createTypeParameterDeclaration(name, constraint, defaultType); node.expression = expression; return finishNode(node, pos); @@ -3937,22 +3941,10 @@ namespace ts { return finishNode(factory.createTypeOperatorNode(operator, parseTypeOperatorOrHigher()), pos); } - function parseTypeParameterOfInferType() { - const pos = getNodePos(); - return finishNode( - factory.createTypeParameterDeclaration( - parseIdentifier(), - /*constraint*/ undefined, - /*defaultType*/ undefined - ), - pos - ); - } - function parseInferType(): InferTypeNode { const pos = getNodePos(); parseExpected(SyntaxKind.InferKeyword); - return finishNode(factory.createInferTypeNode(parseTypeParameterOfInferType()), pos); + return finishNode(factory.createInferTypeNode(parseTypeParameterWorker(/*canHaveDefault*/ false)), pos); } function parseTypeOperatorOrHigher(): TypeNode { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 3fee2e6eac415..13cea35d21b54 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -7124,6 +7124,7 @@ 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; diff --git a/tests/baselines/reference/inferTypes1.errors.txt b/tests/baselines/reference/inferTypes1.errors.txt index be2fa68bfbba5..277f3e912d2a3 100644 --- a/tests/baselines/reference/inferTypes1.errors.txt +++ b/tests/baselines/reference/inferTypes1.errors.txt @@ -8,9 +8,9 @@ tests/cases/conformance/types/conditional/inferTypes1.ts(55,25): error TS2344: T tests/cases/conformance/types/conditional/inferTypes1.ts(56,25): error TS2344: Type 'Function' does not satisfy the constraint '(x: any) => any'. Type 'Function' provides no match for the signature '(x: any): any'. tests/cases/conformance/types/conditional/inferTypes1.ts(82,12): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type. -tests/cases/conformance/types/conditional/inferTypes1.ts(83,15): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type. -tests/cases/conformance/types/conditional/inferTypes1.ts(83,41): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type. -tests/cases/conformance/types/conditional/inferTypes1.ts(83,51): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type. +tests/cases/conformance/types/conditional/inferTypes1.ts(83,16): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type. +tests/cases/conformance/types/conditional/inferTypes1.ts(83,43): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type. +tests/cases/conformance/types/conditional/inferTypes1.ts(83,53): error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type. tests/cases/conformance/types/conditional/inferTypes1.ts(84,15): error TS2304: Cannot find name 'U'. tests/cases/conformance/types/conditional/inferTypes1.ts(84,15): error TS4081: Exported type alias 'T62' has or is using private name 'U'. tests/cases/conformance/types/conditional/inferTypes1.ts(84,43): error TS2304: Cannot find name 'U'. @@ -120,12 +120,12 @@ tests/cases/conformance/types/conditional/inferTypes1.ts(153,40): error TS2322: type T60 = infer U; // Error ~~~~~~~ !!! error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type. - type T61 = infer A extends infer B ? infer C : infer D; // Error - ~~~~~~~ + type T61 = (infer A) extends infer B ? infer C : infer D; // Error + ~~~~~~~ !!! error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type. - ~~~~~~~ + ~~~~~~~ !!! error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type. - ~~~~~~~ + ~~~~~~~ !!! error TS1338: 'infer' declarations are only permitted in the 'extends' clause of a conditional type. type T62 = U extends (infer U)[] ? U : U; // Error ~ @@ -136,7 +136,7 @@ tests/cases/conformance/types/conditional/inferTypes1.ts(153,40): error TS2322: !!! error TS2304: Cannot find name 'U'. ~ !!! error TS4081: Exported type alias 'T62' has or is using private name 'U'. - type T63 = T extends (infer A extends infer B ? infer C : infer D) ? string : number; + type T63 = T extends ((infer A) extends infer B ? infer C : infer D) ? string : number; type T70 = { x: T }; type T71 = T extends T70 ? T70 : never; diff --git a/tests/baselines/reference/inferTypes1.js b/tests/baselines/reference/inferTypes1.js index e3e2b88dd4edb..35421c73ad285 100644 --- a/tests/baselines/reference/inferTypes1.js +++ b/tests/baselines/reference/inferTypes1.js @@ -81,9 +81,9 @@ type T53 = X3<{ a: (x: number) => void, b: (x: string) => void }>; // never type T54 = X3<{ a: (x: number) => void, b: () => void }>; // number type T60 = infer U; // Error -type T61 = infer A extends infer B ? infer C : infer D; // Error +type T61 = (infer A) extends infer B ? infer C : infer D; // Error type T62 = U extends (infer U)[] ? U : U; // Error -type T63 = T extends (infer A extends infer B ? infer C : infer D) ? string : number; +type T63 = T extends ((infer A) extends infer B ? infer C : infer D) ? string : number; type T70 = { x: T }; type T71 = T extends T70 ? T70 : never; diff --git a/tests/baselines/reference/inferTypes1.symbols b/tests/baselines/reference/inferTypes1.symbols index 7e79885184007..33d8052a8c73e 100644 --- a/tests/baselines/reference/inferTypes1.symbols +++ b/tests/baselines/reference/inferTypes1.symbols @@ -349,33 +349,33 @@ type T60 = infer U; // Error >T60 : Symbol(T60, Decl(inferTypes1.ts, 79, 57)) >U : Symbol(U, Decl(inferTypes1.ts, 81, 16)) -type T61 = infer A extends infer B ? infer C : infer D; // Error +type T61 = (infer A) extends infer B ? infer C : infer D; // Error >T61 : Symbol(T61, Decl(inferTypes1.ts, 81, 19)) >T : Symbol(T, Decl(inferTypes1.ts, 82, 9)) ->A : Symbol(A, Decl(inferTypes1.ts, 82, 19)) ->B : Symbol(B, Decl(inferTypes1.ts, 82, 35)) ->C : Symbol(C, Decl(inferTypes1.ts, 82, 45)) ->D : Symbol(D, Decl(inferTypes1.ts, 82, 55)) +>A : Symbol(A, Decl(inferTypes1.ts, 82, 20)) +>B : Symbol(B, Decl(inferTypes1.ts, 82, 37)) +>C : Symbol(C, Decl(inferTypes1.ts, 82, 47)) +>D : Symbol(D, Decl(inferTypes1.ts, 82, 57)) type T62 = U extends (infer U)[] ? U : U; // Error ->T62 : Symbol(T62, Decl(inferTypes1.ts, 82, 58)) +>T62 : Symbol(T62, Decl(inferTypes1.ts, 82, 60)) >T : Symbol(T, Decl(inferTypes1.ts, 83, 9)) >U : Symbol(U) >U : Symbol(U, Decl(inferTypes1.ts, 83, 30)) >U : Symbol(U, Decl(inferTypes1.ts, 83, 30)) >U : Symbol(U) -type T63 = T extends (infer A extends infer B ? infer C : infer D) ? string : number; +type T63 = T extends ((infer A) extends infer B ? infer C : infer D) ? string : number; >T63 : Symbol(T63, Decl(inferTypes1.ts, 83, 44)) >T : Symbol(T, Decl(inferTypes1.ts, 84, 9)) >T : Symbol(T, Decl(inferTypes1.ts, 84, 9)) ->A : Symbol(A, Decl(inferTypes1.ts, 84, 30)) ->B : Symbol(B, Decl(inferTypes1.ts, 84, 46)) ->C : Symbol(C, Decl(inferTypes1.ts, 84, 56)) ->D : Symbol(D, Decl(inferTypes1.ts, 84, 66)) +>A : Symbol(A, Decl(inferTypes1.ts, 84, 31)) +>B : Symbol(B, Decl(inferTypes1.ts, 84, 48)) +>C : Symbol(C, Decl(inferTypes1.ts, 84, 58)) +>D : Symbol(D, Decl(inferTypes1.ts, 84, 68)) type T70 = { x: T }; ->T70 : Symbol(T70, Decl(inferTypes1.ts, 84, 88)) +>T70 : Symbol(T70, Decl(inferTypes1.ts, 84, 90)) >T : Symbol(T, Decl(inferTypes1.ts, 86, 9)) >x : Symbol(x, Decl(inferTypes1.ts, 86, 30)) >T : Symbol(T, Decl(inferTypes1.ts, 86, 9)) @@ -384,9 +384,9 @@ type T71 = T extends T70 ? T70 : never; >T71 : Symbol(T71, Decl(inferTypes1.ts, 86, 38)) >T : Symbol(T, Decl(inferTypes1.ts, 87, 9)) >T : Symbol(T, Decl(inferTypes1.ts, 87, 9)) ->T70 : Symbol(T70, Decl(inferTypes1.ts, 84, 88)) +>T70 : Symbol(T70, Decl(inferTypes1.ts, 84, 90)) >U : Symbol(U, Decl(inferTypes1.ts, 87, 33)) ->T70 : Symbol(T70, Decl(inferTypes1.ts, 84, 88)) +>T70 : Symbol(T70, Decl(inferTypes1.ts, 84, 90)) >U : Symbol(U, Decl(inferTypes1.ts, 87, 33)) type T72 = { y: T }; @@ -401,7 +401,7 @@ type T73 = T extends T72 ? T70 : never; // Error >T : Symbol(T, Decl(inferTypes1.ts, 90, 9)) >T72 : Symbol(T72, Decl(inferTypes1.ts, 87, 54)) >U : Symbol(U, Decl(inferTypes1.ts, 90, 33)) ->T70 : Symbol(T70, Decl(inferTypes1.ts, 84, 88)) +>T70 : Symbol(T70, Decl(inferTypes1.ts, 84, 90)) >U : Symbol(U, Decl(inferTypes1.ts, 90, 33)) type T74 = { x: T, y: U }; @@ -420,7 +420,7 @@ type T75 = T extends T74 ? T70 | T72 | T74 : ne >T74 : Symbol(T74, Decl(inferTypes1.ts, 90, 54)) >U : Symbol(U, Decl(inferTypes1.ts, 93, 33), Decl(inferTypes1.ts, 93, 42)) >U : Symbol(U, Decl(inferTypes1.ts, 93, 33), Decl(inferTypes1.ts, 93, 42)) ->T70 : Symbol(T70, Decl(inferTypes1.ts, 84, 88)) +>T70 : Symbol(T70, Decl(inferTypes1.ts, 84, 90)) >U : Symbol(U, Decl(inferTypes1.ts, 93, 33), Decl(inferTypes1.ts, 93, 42)) >T72 : Symbol(T72, Decl(inferTypes1.ts, 87, 54)) >U : Symbol(U, Decl(inferTypes1.ts, 93, 33), Decl(inferTypes1.ts, 93, 42)) diff --git a/tests/baselines/reference/inferTypes1.types b/tests/baselines/reference/inferTypes1.types index 4ef817304b407..c7a609b3eaed2 100644 --- a/tests/baselines/reference/inferTypes1.types +++ b/tests/baselines/reference/inferTypes1.types @@ -253,13 +253,13 @@ type T54 = X3<{ a: (x: number) => void, b: () => void }>; // number type T60 = infer U; // Error >T60 : U -type T61 = infer A extends infer B ? infer C : infer D; // Error +type T61 = (infer A) extends infer B ? infer C : infer D; // Error >T61 : T61 type T62 = U extends (infer U)[] ? U : U; // Error >T62 : any -type T63 = T extends (infer A extends infer B ? infer C : infer D) ? string : number; +type T63 = T extends ((infer A) extends infer B ? infer C : infer D) ? string : number; >T63 : T63 type T70 = { x: T }; diff --git a/tests/baselines/reference/inferTypes2.js b/tests/baselines/reference/inferTypes2.js index dbfa84964df10..23b84450e2de5 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 04ca9ea6d0553..fdba311280a24 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 new file mode 100644 index 0000000000000..0c57e21adb284 --- /dev/null +++ b/tests/baselines/reference/inferTypesWithExtends1.js @@ -0,0 +1,213 @@ +//// [inferTypesWithExtends1.ts] +// infer to tuple element +type X1 = + T extends [infer U extends string] ? ["string", U] : + T extends [infer U extends number] ? ["number", U] : + never; + +type X1_T1 = X1<["a"]>; // ["string", "a"] +type X1_T2 = X1<[1]>; // ["number", 1] +type X1_T3 = X1<[object]>; // never + +// infer to argument +type X2 void> = + T extends (a: infer U extends string) => void ? ["string", U] : + T extends (a: infer U extends number) => void ? ["number", U] : + never; + +type X2_T1 = X2<(a: "a") => void>; // ["string", "a"] +type X2_T2 = X2<(a: 1) => void>; // ["number", 1] +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] : + never; + +type X3_T1 = X3<() => "a">; // ["string", "a"] +type X3_T2 = X3<() => 1>; // ["number", 1] +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] : + never; + +type X4_T1 = X4 { a: "a" }>; // ["string", { a: "a" }] +type X4_T2 = X4 { a: 1 }>; // ["number", { a: 1 }] +type X4_T3 = X4 { a: object }>; // never + +// infer to type argument +type X5 = + T extends Promise ? ["string", U] : + T extends Promise ? ["number", U] : + never; + +type X5_T1 = X5>; // ["string", "a" | "b"] +type X5_T2 = X5>; // ["number", 1 | 2] +type X5_T3 = X5>; // never + +// infer to property type +type X6 = + T extends { a: infer U extends string } ? ["string", U] : + T extends { a: infer U extends number } ? ["number", U] : + never; + +type X6_T1 = X6<{ a: "a" }>; // ["string", "a"] +type X6_T2 = X6<{ a: 1 }>; // ["number", 1] +type X6_T3 = X6<{ a: object }>; // never + +// infer twice with same constraint +type X7 = + T extends { a: infer U extends string, b: infer U extends string } ? ["string", U] : + T extends { a: infer U extends number, b: infer U extends number } ? ["number", U] : + never; + +type X7_T1 = X7<{ a: "a", b: "b" }>; // ["string", "a" | "b"] +type X7_T2 = X7<{ a: 1, b: 2 }>; // ["number", 1 | 2] +type X7_T3 = X7<{ a: object, b: object }>; // never +type X7_T4 = X7<{ a: "a", b: 1 }>; // never + +// infer twice with missing second constraint (same behavior as class/interface) +type X8 = + T extends { a: infer U extends string, b: infer U } ? ["string", U] : + T extends { a: infer U extends number, b: infer U } ? ["number", U] : + never; + +type X8_T1 = X8<{ a: "a", b: "b" }>; // ["string", "a" | "b"] +type X8_T2 = X8<{ a: 1, b: 2 }>; // ["number", 1 | 2] +type X8_T3 = X8<{ a: object, b: object }>; // never +type X8_T4 = X8<{ a: "a", b: 1 }>; // never + +// infer twice with missing first constraint (same behavior as class/interface) +type X9 = + T extends { a: infer U, b: infer U extends string } ? ["string", U] : + T extends { a: infer U, b: infer U extends number } ? ["number", U] : + never; + +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 + + +//// [inferTypesWithExtends1.js] +"use strict"; + + +//// [inferTypesWithExtends1.d.ts] +declare type X1 = T extends [infer U extends string] ? ["string", U] : T extends [infer U extends number] ? ["number", U] : never; +declare type X1_T1 = X1<["a"]>; +declare type X1_T2 = X1<[1]>; +declare type X1_T3 = X1<[object]>; +declare type X2 void> = T extends (a: infer U extends string) => void ? ["string", U] : T extends (a: infer U extends number) => void ? ["number", U] : never; +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_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 { + a: string; +} ? ["string", U] : T extends new (...args: any[]) => infer U extends { + a: number; +} ? ["number", U] : never; +declare type X4_T1 = X4 { + a: "a"; +}>; +declare type X4_T2 = X4 { + a: 1; +}>; +declare type X4_T3 = X4 { + a: object; +}>; +declare type X5 = T extends Promise ? ["string", U] : T extends Promise ? ["number", U] : never; +declare type X5_T1 = X5>; +declare type X5_T2 = X5>; +declare type X5_T3 = X5>; +declare type X6 = T extends { + a: infer U extends string; +} ? ["string", U] : T extends { + a: infer U extends number; +} ? ["number", U] : never; +declare type X6_T1 = X6<{ + a: "a"; +}>; +declare type X6_T2 = X6<{ + a: 1; +}>; +declare type X6_T3 = X6<{ + a: object; +}>; +declare type X7 = T extends { + a: infer U extends string; + b: infer U extends string; +} ? ["string", U] : T extends { + a: infer U extends number; + b: infer U extends number; +} ? ["number", U] : never; +declare type X7_T1 = X7<{ + a: "a"; + b: "b"; +}>; +declare type X7_T2 = X7<{ + a: 1; + b: 2; +}>; +declare type X7_T3 = X7<{ + a: object; + b: object; +}>; +declare type X7_T4 = X7<{ + a: "a"; + b: 1; +}>; +declare type X8 = T extends { + a: infer U extends string; + b: infer U; +} ? ["string", U] : T extends { + a: infer U extends number; + b: infer U; +} ? ["number", U] : never; +declare type X8_T1 = X8<{ + a: "a"; + b: "b"; +}>; +declare type X8_T2 = X8<{ + a: 1; + b: 2; +}>; +declare type X8_T3 = X8<{ + a: object; + b: object; +}>; +declare type X8_T4 = X8<{ + a: "a"; + b: 1; +}>; +declare type X9 = T extends { + a: infer U; + b: infer U extends string; +} ? ["string", U] : T extends { + a: infer U; + b: infer U extends number; +} ? ["number", U] : never; +declare type X9_T1 = X9<{ + a: "a"; + b: "b"; +}>; +declare type X9_T2 = X9<{ + a: 1; + b: 2; +}>; +declare type X9_T3 = X9<{ + a: object; + b: object; +}>; +declare type X9_T4 = X9<{ + a: "a"; + b: 1; +}>; diff --git a/tests/baselines/reference/inferTypesWithExtends1.symbols b/tests/baselines/reference/inferTypesWithExtends1.symbols new file mode 100644 index 0000000000000..d487baa8ab814 --- /dev/null +++ b/tests/baselines/reference/inferTypesWithExtends1.symbols @@ -0,0 +1,343 @@ +=== tests/cases/conformance/types/conditional/inferTypesWithExtends1.ts === +// infer to tuple element +type X1 = +>X1 : Symbol(X1, Decl(inferTypesWithExtends1.ts, 0, 0)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 1, 8)) + + T extends [infer U extends string] ? ["string", U] : +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 1, 8)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 2, 20)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 2, 20)) + + T extends [infer U extends number] ? ["number", U] : +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 1, 8)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 3, 20)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 3, 20)) + + never; + +type X1_T1 = X1<["a"]>; // ["string", "a"] +>X1_T1 : Symbol(X1_T1, Decl(inferTypesWithExtends1.ts, 4, 10)) +>X1 : Symbol(X1, Decl(inferTypesWithExtends1.ts, 0, 0)) + +type X1_T2 = X1<[1]>; // ["number", 1] +>X1_T2 : Symbol(X1_T2, Decl(inferTypesWithExtends1.ts, 6, 23)) +>X1 : Symbol(X1, Decl(inferTypesWithExtends1.ts, 0, 0)) + +type X1_T3 = X1<[object]>; // never +>X1_T3 : Symbol(X1_T3, Decl(inferTypesWithExtends1.ts, 7, 21)) +>X1 : Symbol(X1, Decl(inferTypesWithExtends1.ts, 0, 0)) + +// infer to argument +type X2 void> = +>X2 : Symbol(X2, Decl(inferTypesWithExtends1.ts, 8, 26)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 11, 8)) +>args : Symbol(args, Decl(inferTypesWithExtends1.ts, 11, 19)) + + T extends (a: infer U extends string) => void ? ["string", U] : +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 11, 8)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 12, 15)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 12, 23)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 12, 23)) + + T extends (a: infer U extends number) => void ? ["number", U] : +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 11, 8)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 13, 15)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 13, 23)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 13, 23)) + + never; + +type X2_T1 = X2<(a: "a") => void>; // ["string", "a"] +>X2_T1 : Symbol(X2_T1, Decl(inferTypesWithExtends1.ts, 14, 10)) +>X2 : Symbol(X2, Decl(inferTypesWithExtends1.ts, 8, 26)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 16, 17)) + +type X2_T2 = X2<(a: 1) => void>; // ["number", 1] +>X2_T2 : Symbol(X2_T2, Decl(inferTypesWithExtends1.ts, 16, 34)) +>X2 : Symbol(X2, Decl(inferTypesWithExtends1.ts, 8, 26)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 17, 17)) + +type X2_T3 = X2<(a: object) => void>; // never +>X2_T3 : Symbol(X2_T3, Decl(inferTypesWithExtends1.ts, 17, 32)) +>X2 : Symbol(X2, Decl(inferTypesWithExtends1.ts, 8, 26)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 18, 17)) + +// infer to return type +type X3 any> = +>X3 : Symbol(X3, Decl(inferTypesWithExtends1.ts, 18, 37)) +>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 : 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)) + + 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)) + + never; + +type X3_T1 = X3<() => "a">; // ["string", "a"] +>X3_T1 : Symbol(X3_T1, Decl(inferTypesWithExtends1.ts, 24, 10)) +>X3 : Symbol(X3, Decl(inferTypesWithExtends1.ts, 18, 37)) + +type X3_T2 = X3<() => 1>; // ["number", 1] +>X3_T2 : Symbol(X3_T2, Decl(inferTypesWithExtends1.ts, 26, 27)) +>X3 : Symbol(X3, Decl(inferTypesWithExtends1.ts, 18, 37)) + +type X3_T3 = X3<() => object>; // never +>X3_T3 : Symbol(X3_T3, Decl(inferTypesWithExtends1.ts, 27, 25)) +>X3 : Symbol(X3, Decl(inferTypesWithExtends1.ts, 18, 37)) + +// infer to instance type +type X4 any> = +>X4 : Symbol(X4, Decl(inferTypesWithExtends1.ts, 28, 30)) +>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 : 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)) + + 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)) + + never; + +type X4_T1 = X4 { a: "a" }>; // ["string", { a: "a" }] +>X4_T1 : Symbol(X4_T1, Decl(inferTypesWithExtends1.ts, 34, 10)) +>X4 : Symbol(X4, Decl(inferTypesWithExtends1.ts, 28, 30)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 36, 27)) + +type X4_T2 = X4 { a: 1 }>; // ["number", { a: 1 }] +>X4_T2 : Symbol(X4_T2, Decl(inferTypesWithExtends1.ts, 36, 38)) +>X4 : Symbol(X4, Decl(inferTypesWithExtends1.ts, 28, 30)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 37, 27)) + +type X4_T3 = X4 { a: object }>; // never +>X4_T3 : Symbol(X4_T3, Decl(inferTypesWithExtends1.ts, 37, 36)) +>X4 : Symbol(X4, Decl(inferTypesWithExtends1.ts, 28, 30)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 38, 27)) + +// infer to type argument +type X5 = +>X5 : Symbol(X5, Decl(inferTypesWithExtends1.ts, 38, 41)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 41, 8)) + + T extends Promise ? ["string", U] : +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 41, 8)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 42, 27)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 42, 27)) + + T extends Promise ? ["number", U] : +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 41, 8)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 43, 27)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 43, 27)) + + never; + +type X5_T1 = X5>; // ["string", "a" | "b"] +>X5_T1 : Symbol(X5_T1, Decl(inferTypesWithExtends1.ts, 44, 10)) +>X5 : Symbol(X5, Decl(inferTypesWithExtends1.ts, 38, 41)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) + +type X5_T2 = X5>; // ["number", 1 | 2] +>X5_T2 : Symbol(X5_T2, Decl(inferTypesWithExtends1.ts, 46, 36)) +>X5 : Symbol(X5, Decl(inferTypesWithExtends1.ts, 38, 41)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) + +type X5_T3 = X5>; // never +>X5_T3 : Symbol(X5_T3, Decl(inferTypesWithExtends1.ts, 47, 32)) +>X5 : Symbol(X5, Decl(inferTypesWithExtends1.ts, 38, 41)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) + +// infer to property type +type X6 = +>X6 : Symbol(X6, Decl(inferTypesWithExtends1.ts, 48, 34)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 51, 8)) + + T extends { a: infer U extends string } ? ["string", U] : +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 51, 8)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 52, 15)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 52, 24)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 52, 24)) + + T extends { a: infer U extends number } ? ["number", U] : +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 51, 8)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 53, 15)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 53, 24)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 53, 24)) + + never; + +type X6_T1 = X6<{ a: "a" }>; // ["string", "a"] +>X6_T1 : Symbol(X6_T1, Decl(inferTypesWithExtends1.ts, 54, 10)) +>X6 : Symbol(X6, Decl(inferTypesWithExtends1.ts, 48, 34)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 56, 17)) + +type X6_T2 = X6<{ a: 1 }>; // ["number", 1] +>X6_T2 : Symbol(X6_T2, Decl(inferTypesWithExtends1.ts, 56, 28)) +>X6 : Symbol(X6, Decl(inferTypesWithExtends1.ts, 48, 34)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 57, 17)) + +type X6_T3 = X6<{ a: object }>; // never +>X6_T3 : Symbol(X6_T3, Decl(inferTypesWithExtends1.ts, 57, 26)) +>X6 : Symbol(X6, Decl(inferTypesWithExtends1.ts, 48, 34)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 58, 17)) + +// infer twice with same constraint +type X7 = +>X7 : Symbol(X7, Decl(inferTypesWithExtends1.ts, 58, 31)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 61, 8)) + + T extends { a: infer U extends string, b: infer U extends string } ? ["string", U] : +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 61, 8)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 62, 15)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 62, 24), Decl(inferTypesWithExtends1.ts, 62, 51)) +>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 62, 42)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 62, 24), Decl(inferTypesWithExtends1.ts, 62, 51)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 62, 24), Decl(inferTypesWithExtends1.ts, 62, 51)) + + T extends { a: infer U extends number, b: infer U extends number } ? ["number", U] : +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 61, 8)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 63, 15)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 63, 24), Decl(inferTypesWithExtends1.ts, 63, 51)) +>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 63, 42)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 63, 24), Decl(inferTypesWithExtends1.ts, 63, 51)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 63, 24), Decl(inferTypesWithExtends1.ts, 63, 51)) + + never; + +type X7_T1 = X7<{ a: "a", b: "b" }>; // ["string", "a" | "b"] +>X7_T1 : Symbol(X7_T1, Decl(inferTypesWithExtends1.ts, 64, 10)) +>X7 : Symbol(X7, Decl(inferTypesWithExtends1.ts, 58, 31)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 66, 17)) +>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 66, 25)) + +type X7_T2 = X7<{ a: 1, b: 2 }>; // ["number", 1 | 2] +>X7_T2 : Symbol(X7_T2, Decl(inferTypesWithExtends1.ts, 66, 36)) +>X7 : Symbol(X7, Decl(inferTypesWithExtends1.ts, 58, 31)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 67, 17)) +>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 67, 23)) + +type X7_T3 = X7<{ a: object, b: object }>; // never +>X7_T3 : Symbol(X7_T3, Decl(inferTypesWithExtends1.ts, 67, 32)) +>X7 : Symbol(X7, Decl(inferTypesWithExtends1.ts, 58, 31)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 68, 17)) +>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 68, 28)) + +type X7_T4 = X7<{ a: "a", b: 1 }>; // never +>X7_T4 : Symbol(X7_T4, Decl(inferTypesWithExtends1.ts, 68, 42)) +>X7 : Symbol(X7, Decl(inferTypesWithExtends1.ts, 58, 31)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 69, 17)) +>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 69, 25)) + +// infer twice with missing second constraint (same behavior as class/interface) +type X8 = +>X8 : Symbol(X8, Decl(inferTypesWithExtends1.ts, 69, 34)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 72, 8)) + + T extends { a: infer U extends string, b: infer U } ? ["string", U] : +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 72, 8)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 73, 15)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 73, 24), Decl(inferTypesWithExtends1.ts, 73, 51)) +>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 73, 42)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 73, 24), Decl(inferTypesWithExtends1.ts, 73, 51)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 73, 24), Decl(inferTypesWithExtends1.ts, 73, 51)) + + T extends { a: infer U extends number, b: infer U } ? ["number", U] : +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 72, 8)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 74, 15)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 74, 24), Decl(inferTypesWithExtends1.ts, 74, 51)) +>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 74, 42)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 74, 24), Decl(inferTypesWithExtends1.ts, 74, 51)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 74, 24), Decl(inferTypesWithExtends1.ts, 74, 51)) + + never; + +type X8_T1 = X8<{ a: "a", b: "b" }>; // ["string", "a" | "b"] +>X8_T1 : Symbol(X8_T1, Decl(inferTypesWithExtends1.ts, 75, 10)) +>X8 : Symbol(X8, Decl(inferTypesWithExtends1.ts, 69, 34)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 77, 17)) +>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 77, 25)) + +type X8_T2 = X8<{ a: 1, b: 2 }>; // ["number", 1 | 2] +>X8_T2 : Symbol(X8_T2, Decl(inferTypesWithExtends1.ts, 77, 36)) +>X8 : Symbol(X8, Decl(inferTypesWithExtends1.ts, 69, 34)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 78, 17)) +>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 78, 23)) + +type X8_T3 = X8<{ a: object, b: object }>; // never +>X8_T3 : Symbol(X8_T3, Decl(inferTypesWithExtends1.ts, 78, 32)) +>X8 : Symbol(X8, Decl(inferTypesWithExtends1.ts, 69, 34)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 79, 17)) +>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 79, 28)) + +type X8_T4 = X8<{ a: "a", b: 1 }>; // never +>X8_T4 : Symbol(X8_T4, Decl(inferTypesWithExtends1.ts, 79, 42)) +>X8 : Symbol(X8, Decl(inferTypesWithExtends1.ts, 69, 34)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 80, 17)) +>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 80, 25)) + +// infer twice with missing first constraint (same behavior as class/interface) +type X9 = +>X9 : Symbol(X9, Decl(inferTypesWithExtends1.ts, 80, 34)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 83, 8)) + + T extends { a: infer U, b: infer U extends string } ? ["string", U] : +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 83, 8)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 84, 15)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 84, 24), Decl(inferTypesWithExtends1.ts, 84, 36)) +>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 84, 27)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 84, 24), Decl(inferTypesWithExtends1.ts, 84, 36)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 84, 24), Decl(inferTypesWithExtends1.ts, 84, 36)) + + T extends { a: infer U, b: infer U extends number } ? ["number", U] : +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 83, 8)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 85, 15)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 85, 24), Decl(inferTypesWithExtends1.ts, 85, 36)) +>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 85, 27)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 85, 24), Decl(inferTypesWithExtends1.ts, 85, 36)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 85, 24), Decl(inferTypesWithExtends1.ts, 85, 36)) + + never; + +type X9_T1 = X9<{ a: "a", b: "b" }>; // ["string", "a" | "b"] +>X9_T1 : Symbol(X9_T1, Decl(inferTypesWithExtends1.ts, 86, 10)) +>X9 : Symbol(X9, Decl(inferTypesWithExtends1.ts, 80, 34)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 88, 17)) +>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 88, 25)) + +type X9_T2 = X9<{ a: 1, b: 2 }>; // ["number", 1 | 2] +>X9_T2 : Symbol(X9_T2, Decl(inferTypesWithExtends1.ts, 88, 36)) +>X9 : Symbol(X9, Decl(inferTypesWithExtends1.ts, 80, 34)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 89, 17)) +>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 89, 23)) + +type X9_T3 = X9<{ a: object, b: object }>; // never +>X9_T3 : Symbol(X9_T3, Decl(inferTypesWithExtends1.ts, 89, 32)) +>X9 : Symbol(X9, Decl(inferTypesWithExtends1.ts, 80, 34)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 90, 17)) +>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 90, 28)) + +type X9_T4 = X9<{ a: "a", b: 1 }>; // never +>X9_T4 : Symbol(X9_T4, Decl(inferTypesWithExtends1.ts, 90, 42)) +>X9 : Symbol(X9, Decl(inferTypesWithExtends1.ts, 80, 34)) +>a : Symbol(a, Decl(inferTypesWithExtends1.ts, 91, 17)) +>b : Symbol(b, Decl(inferTypesWithExtends1.ts, 91, 25)) + diff --git a/tests/baselines/reference/inferTypesWithExtends1.types b/tests/baselines/reference/inferTypesWithExtends1.types new file mode 100644 index 0000000000000..24215af18e2b7 --- /dev/null +++ b/tests/baselines/reference/inferTypesWithExtends1.types @@ -0,0 +1,235 @@ +=== tests/cases/conformance/types/conditional/inferTypesWithExtends1.ts === +// infer to tuple element +type X1 = +>X1 : X1 + + T extends [infer U extends string] ? ["string", U] : + T extends [infer U extends number] ? ["number", U] : + never; + +type X1_T1 = X1<["a"]>; // ["string", "a"] +>X1_T1 : ["string", "a"] + +type X1_T2 = X1<[1]>; // ["number", 1] +>X1_T2 : ["number", 1] + +type X1_T3 = X1<[object]>; // never +>X1_T3 : never + +// infer to argument +type X2 void> = +>X2 : X2 +>args : any[] + + T extends (a: infer U extends string) => void ? ["string", U] : +>a : U + + T extends (a: infer U extends number) => void ? ["number", U] : +>a : U + + never; + +type X2_T1 = X2<(a: "a") => void>; // ["string", "a"] +>X2_T1 : ["string", "a"] +>a : "a" + +type X2_T2 = X2<(a: 1) => void>; // ["number", 1] +>X2_T2 : ["number", 1] +>a : 1 + +type X2_T3 = X2<(a: object) => void>; // never +>X2_T3 : never +>a : object + +// infer to return type +type X3 any> = +>X3 : X3 +>args : any[] + + T extends (...args: any[]) => infer U extends string ? ["string", U] : +>args : any[] + + T extends (...args: any[]) => infer U extends number ? ["number", U] : +>args : any[] + + never; + +type X3_T1 = X3<() => "a">; // ["string", "a"] +>X3_T1 : ["string", "a"] + +type X3_T2 = X3<() => 1>; // ["number", 1] +>X3_T2 : ["number", 1] + +type X3_T3 = X3<() => object>; // never +>X3_T3 : never + +// infer to instance type +type X4 any> = +>X4 : X4 +>args : any[] + + 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] : +>args : any[] +>a : number + + never; + +type X4_T1 = X4 { a: "a" }>; // ["string", { a: "a" }] +>X4_T1 : ["string", { a: "a"; }] +>a : "a" + +type X4_T2 = X4 { a: 1 }>; // ["number", { a: 1 }] +>X4_T2 : ["number", { a: 1; }] +>a : 1 + +type X4_T3 = X4 { a: object }>; // never +>X4_T3 : never +>a : object + +// infer to type argument +type X5 = +>X5 : X5 + + T extends Promise ? ["string", U] : + T extends Promise ? ["number", U] : + never; + +type X5_T1 = X5>; // ["string", "a" | "b"] +>X5_T1 : ["string", "a" | "b"] + +type X5_T2 = X5>; // ["number", 1 | 2] +>X5_T2 : ["number", 1 | 2] + +type X5_T3 = X5>; // never +>X5_T3 : never + +// infer to property type +type X6 = +>X6 : X6 + + T extends { a: infer U extends string } ? ["string", U] : +>a : U + + T extends { a: infer U extends number } ? ["number", U] : +>a : U + + never; + +type X6_T1 = X6<{ a: "a" }>; // ["string", "a"] +>X6_T1 : ["string", "a"] +>a : "a" + +type X6_T2 = X6<{ a: 1 }>; // ["number", 1] +>X6_T2 : ["number", 1] +>a : 1 + +type X6_T3 = X6<{ a: object }>; // never +>X6_T3 : never +>a : object + +// infer twice with same constraint +type X7 = +>X7 : X7 + + T extends { a: infer U extends string, b: infer U extends string } ? ["string", U] : +>a : U +>b : U + + T extends { a: infer U extends number, b: infer U extends number } ? ["number", U] : +>a : U +>b : U + + never; + +type X7_T1 = X7<{ a: "a", b: "b" }>; // ["string", "a" | "b"] +>X7_T1 : ["string", "a" | "b"] +>a : "a" +>b : "b" + +type X7_T2 = X7<{ a: 1, b: 2 }>; // ["number", 1 | 2] +>X7_T2 : ["number", 1 | 2] +>a : 1 +>b : 2 + +type X7_T3 = X7<{ a: object, b: object }>; // never +>X7_T3 : never +>a : object +>b : object + +type X7_T4 = X7<{ a: "a", b: 1 }>; // never +>X7_T4 : never +>a : "a" +>b : 1 + +// infer twice with missing second constraint (same behavior as class/interface) +type X8 = +>X8 : X8 + + T extends { a: infer U extends string, b: infer U } ? ["string", U] : +>a : U +>b : U + + T extends { a: infer U extends number, b: infer U } ? ["number", U] : +>a : U +>b : U + + never; + +type X8_T1 = X8<{ a: "a", b: "b" }>; // ["string", "a" | "b"] +>X8_T1 : ["string", "a" | "b"] +>a : "a" +>b : "b" + +type X8_T2 = X8<{ a: 1, b: 2 }>; // ["number", 1 | 2] +>X8_T2 : ["number", 1 | 2] +>a : 1 +>b : 2 + +type X8_T3 = X8<{ a: object, b: object }>; // never +>X8_T3 : never +>a : object +>b : object + +type X8_T4 = X8<{ a: "a", b: 1 }>; // never +>X8_T4 : never +>a : "a" +>b : 1 + +// infer twice with missing first constraint (same behavior as class/interface) +type X9 = +>X9 : X9 + + T extends { a: infer U, b: infer U extends string } ? ["string", U] : +>a : U +>b : U + + T extends { a: infer U, b: infer U extends number } ? ["number", U] : +>a : U +>b : U + + never; + +type X9_T1 = X9<{ a: "a", b: "b" }>; // ["string", "a" | "b"] +>X9_T1 : ["string", "a" | "b"] +>a : "a" +>b : "b" + +type X9_T2 = X9<{ a: 1, b: 2 }>; // ["number", 1 | 2] +>X9_T2 : ["number", 1 | 2] +>a : 1 +>b : 2 + +type X9_T3 = X9<{ a: object, b: object }>; // never +>X9_T3 : never +>a : object +>b : object + +type X9_T4 = X9<{ a: "a", b: 1 }>; // never +>X9_T4 : never +>a : "a" +>b : 1 + diff --git a/tests/baselines/reference/inferTypesWithExtends2.errors.txt b/tests/baselines/reference/inferTypesWithExtends2.errors.txt new file mode 100644 index 0000000000000..8a63107f74c78 --- /dev/null +++ b/tests/baselines/reference/inferTypesWithExtends2.errors.txt @@ -0,0 +1,14 @@ +tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts(3,26): error TS2838: All declarations of 'U' must have identical constraints. +tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts(3,53): error TS2838: All declarations of 'U' must have identical constraints. + + +==== tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts (2 errors) ==== + // infer twice with different constraints (same behavior as class/interface) + type X10 = + T extends { a: infer U extends string, b: infer U extends number } ? U : + ~ +!!! error TS2838: All declarations of 'U' must have identical constraints. + ~ +!!! error TS2838: All declarations of 'U' must have identical constraints. + never; + \ No newline at end of file diff --git a/tests/baselines/reference/inferTypesWithExtends2.js b/tests/baselines/reference/inferTypesWithExtends2.js new file mode 100644 index 0000000000000..c51a0918ca52e --- /dev/null +++ b/tests/baselines/reference/inferTypesWithExtends2.js @@ -0,0 +1,9 @@ +//// [inferTypesWithExtends2.ts] +// infer twice with different constraints (same behavior as class/interface) +type X10 = + T extends { a: infer U extends string, b: infer U extends number } ? U : + never; + + +//// [inferTypesWithExtends2.js] +"use strict"; diff --git a/tests/baselines/reference/inferTypesWithExtends2.symbols b/tests/baselines/reference/inferTypesWithExtends2.symbols new file mode 100644 index 0000000000000..c5bb1b387dfe8 --- /dev/null +++ b/tests/baselines/reference/inferTypesWithExtends2.symbols @@ -0,0 +1,16 @@ +=== tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts === +// infer twice with different constraints (same behavior as class/interface) +type X10 = +>X10 : Symbol(X10, Decl(inferTypesWithExtends2.ts, 0, 0)) +>T : Symbol(T, Decl(inferTypesWithExtends2.ts, 1, 9)) + + T extends { a: infer U extends string, b: infer U extends number } ? U : +>T : Symbol(T, Decl(inferTypesWithExtends2.ts, 1, 9)) +>a : Symbol(a, Decl(inferTypesWithExtends2.ts, 2, 15)) +>U : Symbol(U, Decl(inferTypesWithExtends2.ts, 2, 24), Decl(inferTypesWithExtends2.ts, 2, 51)) +>b : Symbol(b, Decl(inferTypesWithExtends2.ts, 2, 42)) +>U : Symbol(U, Decl(inferTypesWithExtends2.ts, 2, 24), Decl(inferTypesWithExtends2.ts, 2, 51)) +>U : Symbol(U, Decl(inferTypesWithExtends2.ts, 2, 24), Decl(inferTypesWithExtends2.ts, 2, 51)) + + never; + diff --git a/tests/baselines/reference/inferTypesWithExtends2.types b/tests/baselines/reference/inferTypesWithExtends2.types new file mode 100644 index 0000000000000..6d954cc977b5e --- /dev/null +++ b/tests/baselines/reference/inferTypesWithExtends2.types @@ -0,0 +1,11 @@ +=== tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts === +// infer twice with different constraints (same behavior as class/interface) +type X10 = +>X10 : X10 + + T extends { a: infer U extends string, b: infer U extends number } ? U : +>a : U +>b : U + + never; + diff --git a/tests/cases/conformance/types/conditional/inferTypes1.ts b/tests/cases/conformance/types/conditional/inferTypes1.ts index afcb58aff5d64..42e5897dc663f 100644 --- a/tests/cases/conformance/types/conditional/inferTypes1.ts +++ b/tests/cases/conformance/types/conditional/inferTypes1.ts @@ -83,9 +83,9 @@ type T53 = X3<{ a: (x: number) => void, b: (x: string) => void }>; // never type T54 = X3<{ a: (x: number) => void, b: () => void }>; // number type T60 = infer U; // Error -type T61 = infer A extends infer B ? infer C : infer D; // Error +type T61 = (infer A) extends infer B ? infer C : infer D; // Error type T62 = U extends (infer U)[] ? U : U; // Error -type T63 = T extends (infer A extends infer B ? infer C : infer D) ? string : number; +type T63 = T extends ((infer A) extends infer B ? infer C : infer D) ? string : number; type T70 = { x: T }; type T71 = T extends T70 ? T70 : never; diff --git a/tests/cases/conformance/types/conditional/inferTypesWithExtends1.ts b/tests/cases/conformance/types/conditional/inferTypesWithExtends1.ts new file mode 100644 index 0000000000000..e58fe7a2f16d2 --- /dev/null +++ b/tests/cases/conformance/types/conditional/inferTypesWithExtends1.ts @@ -0,0 +1,95 @@ +// @strict: true +// @declaration: true + +// infer to tuple element +type X1 = + T extends [infer U extends string] ? ["string", U] : + T extends [infer U extends number] ? ["number", U] : + never; + +type X1_T1 = X1<["a"]>; // ["string", "a"] +type X1_T2 = X1<[1]>; // ["number", 1] +type X1_T3 = X1<[object]>; // never + +// infer to argument +type X2 void> = + T extends (a: infer U extends string) => void ? ["string", U] : + T extends (a: infer U extends number) => void ? ["number", U] : + never; + +type X2_T1 = X2<(a: "a") => void>; // ["string", "a"] +type X2_T2 = X2<(a: 1) => void>; // ["number", 1] +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] : + never; + +type X3_T1 = X3<() => "a">; // ["string", "a"] +type X3_T2 = X3<() => 1>; // ["number", 1] +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] : + never; + +type X4_T1 = X4 { a: "a" }>; // ["string", { a: "a" }] +type X4_T2 = X4 { a: 1 }>; // ["number", { a: 1 }] +type X4_T3 = X4 { a: object }>; // never + +// infer to type argument +type X5 = + T extends Promise ? ["string", U] : + T extends Promise ? ["number", U] : + never; + +type X5_T1 = X5>; // ["string", "a" | "b"] +type X5_T2 = X5>; // ["number", 1 | 2] +type X5_T3 = X5>; // never + +// infer to property type +type X6 = + T extends { a: infer U extends string } ? ["string", U] : + T extends { a: infer U extends number } ? ["number", U] : + never; + +type X6_T1 = X6<{ a: "a" }>; // ["string", "a"] +type X6_T2 = X6<{ a: 1 }>; // ["number", 1] +type X6_T3 = X6<{ a: object }>; // never + +// infer twice with same constraint +type X7 = + T extends { a: infer U extends string, b: infer U extends string } ? ["string", U] : + T extends { a: infer U extends number, b: infer U extends number } ? ["number", U] : + never; + +type X7_T1 = X7<{ a: "a", b: "b" }>; // ["string", "a" | "b"] +type X7_T2 = X7<{ a: 1, b: 2 }>; // ["number", 1 | 2] +type X7_T3 = X7<{ a: object, b: object }>; // never +type X7_T4 = X7<{ a: "a", b: 1 }>; // never + +// infer twice with missing second constraint (same behavior as class/interface) +type X8 = + T extends { a: infer U extends string, b: infer U } ? ["string", U] : + T extends { a: infer U extends number, b: infer U } ? ["number", U] : + never; + +type X8_T1 = X8<{ a: "a", b: "b" }>; // ["string", "a" | "b"] +type X8_T2 = X8<{ a: 1, b: 2 }>; // ["number", 1 | 2] +type X8_T3 = X8<{ a: object, b: object }>; // never +type X8_T4 = X8<{ a: "a", b: 1 }>; // never + +// infer twice with missing first constraint (same behavior as class/interface) +type X9 = + T extends { a: infer U, b: infer U extends string } ? ["string", U] : + T extends { a: infer U, b: infer U extends number } ? ["number", U] : + never; + +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 diff --git a/tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts b/tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts new file mode 100644 index 0000000000000..f5ff5fe5c90af --- /dev/null +++ b/tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts @@ -0,0 +1,6 @@ +// @strict: true + +// infer twice with different constraints (same behavior as class/interface) +type X10 = + T extends { a: infer U extends string, b: infer U extends number } ? U : + never; diff --git a/tests/cases/fourslash/refactorExtractType48.ts b/tests/cases/fourslash/refactorExtractType48.ts index d10af6bb6379e..afe41c716527e 100644 --- a/tests/cases/fourslash/refactorExtractType48.ts +++ b/tests/cases/fourslash/refactorExtractType48.ts @@ -1,13 +1,13 @@ /// -//// type Crazy = /*a*/T extends [infer P, (infer R extends string ? string : never)] ? P & R : string/*b*/; +//// type Crazy = /*a*/T extends [infer P, ((infer R) extends string ? string : never)] ? P & R : string/*b*/; goTo.select("a", "b"); edit.applyRefactor({ refactorName: "Extract type", actionName: "Extract to type alias", actionDescription: "Extract to type alias", - newContent: `type /*RENAME*/NewType = T extends [infer P, (infer R extends string ? string : never)] ? P & R : string; + newContent: `type /*RENAME*/NewType = T extends [infer P, ((infer R) extends string ? string : never)] ? P & R : string; type Crazy = NewType;`, }); From 1c6f5877c41b89184d5c280cae96a711e1d2a00a Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Fri, 11 Mar 2022 11:14:14 -0800 Subject: [PATCH 2/6] Revise parse for infer..extends, improve parenthesizer --- src/compiler/emitter.ts | 68 ++++-- src/compiler/factory/nodeFactory.ts | 60 +++-- src/compiler/factory/parenthesizerRules.ts | 224 +++++++++++++++--- src/compiler/parser.ts | 66 ++++-- src/compiler/types.ts | 51 ++-- ...sions.parsesCorrectly.nonNullableType.json | 3 +- ...ions.parsesCorrectly.nonNullableType2.json | 3 +- ...ressions.parsesCorrectly.nullableType.json | 3 +- ...essions.parsesCorrectly.nullableType2.json | 3 +- .../abstractClassUnionInstantiation.types | 6 +- .../reference/aliasUsageInArray.types | 6 +- .../reference/api/tsserverlibrary.d.ts | 21 +- tests/baselines/reference/api/typescript.d.ts | 21 +- tests/baselines/reference/arrayLiterals.types | 6 +- .../reference/arrayOfFunctionTypes3.types | 6 +- ...assCanExtendConstructorFunction.errors.txt | 8 +- .../classCanExtendConstructorFunction.types | 4 +- .../baselines/reference/constEnumErrors.types | 4 +- .../constructorTagOnClassConstructor.types | 4 +- .../reference/controlFlowIfStatement.types | 2 +- .../derivedClassSuperProperties.types | 4 +- .../reference/discriminatedUnionTypes2.types | 4 +- tests/baselines/reference/inferTypes2.js | 2 +- tests/baselines/reference/inferTypes2.types | 8 +- .../reference/inferTypesWithExtends1.js | 53 ++++- .../reference/inferTypesWithExtends1.symbols | 119 ++++++++-- .../reference/inferTypesWithExtends1.types | 46 +++- .../intersectionAndUnionTypes.errors.txt | 32 +-- .../reference/intersectionAndUnionTypes.types | 26 +- .../reference/intersectionNarrowing.types | 24 +- .../intersectionOfUnionNarrowing.types | 4 +- .../reference/keyofAndIndexedAccess2.types | 4 +- .../reference/narrowingByTypeofInSwitch.types | 8 +- .../reference/narrowingTypeofFunction.types | 12 +- .../objectLiteralExcessProperties.errors.txt | 4 +- .../objectLiteralExcessProperties.types | 2 +- tests/baselines/reference/objectSpread.types | 24 +- ...artialOfLargeAPIIsAbleToBeWorkedWith.types | 4 +- .../reference/primitiveUnionDetection.types | 6 +- .../reference/spreadObjectOrFalsy.js | 2 +- .../reference/spreadObjectOrFalsy.types | 8 +- .../staticFieldWithInterfaceContext.types | 4 +- .../reference/templateLiteralTypes2.types | 4 +- .../reference/thisTypeInObjectLiterals2.types | 2 +- .../typeGuardIntersectionTypes.types | 2 +- .../typeGuardsWithInstanceOf.errors.txt | 8 +- .../reference/typeGuardsWithInstanceOf.types | 6 +- .../reference/unionTypeInference.types | 14 +- .../conditional/inferTypesWithExtends1.ts | 25 +- .../fourslash/codeFixAddVoidToPromise.4.ts | 2 +- .../fourslash/codeFixAddVoidToPromiseJS.4.ts | 2 +- .../codeFixAddVoidToPromiseJS_all.ts | 2 +- .../fourslash/codeFixAddVoidToPromise_all.ts | 2 +- 53 files changed, 743 insertions(+), 295 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 512ebab209fa7..2d6f70128d829 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 1a98fddbed303..2d19d8714f430 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 570cad9621983..7e046396d648d 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1390,6 +1390,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); } @@ -1426,6 +1434,10 @@ namespace ts { return inContext(NodeFlags.DisallowInContext); } + function inDisallowConditionalTypesContext() { + return inContext(NodeFlags.DisallowConditionalTypesContext); + } + function inDecoratorContext() { return inContext(NodeFlags.DecoratorContext); } @@ -3046,7 +3058,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 { @@ -3073,7 +3085,7 @@ namespace ts { return finishNode(factory.createJSDocUnknownType(), pos); } else { - return finishNode(factory.createJSDocNullableType(parseType()), pos); + return finishNode(factory.createJSDocNullableType(parseType(), /*postfix*/ false), pos); } } @@ -3155,10 +3167,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; @@ -3183,7 +3191,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); @@ -3283,7 +3291,7 @@ namespace ts { function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): TypeNode | undefined; function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean) { if (shouldParseReturnType(returnToken, isType)) { - return parseTypeOrTypePredicate(); + return allowConditionalTypesAnd(parseTypeOrTypePredicate); } } @@ -3906,7 +3914,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 @@ -3914,7 +3922,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); @@ -3941,10 +3949,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 { @@ -3957,7 +3983,7 @@ namespace ts { case SyntaxKind.InferKeyword: return parseInferType(); } - return parsePostfixTypeOrHigher(); + return allowConditionalTypesAnd(parsePostfixTypeOrHigher); } function parseFunctionOrConstructorTypeToError( @@ -4106,24 +4132,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 13cea35d21b54..409c3a8498abb 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -759,10 +759,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 @@ -773,15 +774,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, @@ -789,7 +790,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, @@ -3224,11 +3225,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 { @@ -7124,11 +7127,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; } @@ -7541,9 +7552,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/abstractClassUnionInstantiation.types b/tests/baselines/reference/abstractClassUnionInstantiation.types index 969f0b85c44a5..54ada1b28c9ed 100644 --- a/tests/baselines/reference/abstractClassUnionInstantiation.types +++ b/tests/baselines/reference/abstractClassUnionInstantiation.types @@ -75,11 +75,11 @@ new cls3(); // should work [ConcreteA, ConcreteB].map(cls => new cls()); // should work >[ConcreteA, ConcreteB].map(cls => new cls()) : ConcreteA[] ->[ConcreteA, ConcreteB].map : (callbackfn: (value: typeof ConcreteA, index: number, array: (typeof ConcreteA)[]) => U, thisArg?: any) => U[] ->[ConcreteA, ConcreteB] : (typeof ConcreteA)[] +>[ConcreteA, ConcreteB].map : (callbackfn: (value: typeof ConcreteA, index: number, array: typeof ConcreteA[]) => U, thisArg?: any) => U[] +>[ConcreteA, ConcreteB] : typeof ConcreteA[] >ConcreteA : typeof ConcreteA >ConcreteB : typeof ConcreteB ->map : (callbackfn: (value: typeof ConcreteA, index: number, array: (typeof ConcreteA)[]) => U, thisArg?: any) => U[] +>map : (callbackfn: (value: typeof ConcreteA, index: number, array: typeof ConcreteA[]) => U, thisArg?: any) => U[] >cls => new cls() : (cls: typeof ConcreteA) => ConcreteA >cls : typeof ConcreteA >new cls() : ConcreteA 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 fcb78f56f6cc0..6f1adca36b3fe 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -522,16 +522,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 { @@ -1800,10 +1801,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; @@ -3645,9 +3648,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 e78e7d779b831..b499409a7cdec 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -522,16 +522,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 { @@ -1800,10 +1801,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; @@ -3645,9 +3648,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..3bb791b86812b 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,23 @@ 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 `?`) + +// from mongoose +type IfEquals = (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 ? A : B; //// [inferTypesWithExtends1.js] @@ -106,15 +123,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 +228,23 @@ 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; +declare type IfEquals = (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 ? A : B; diff --git a/tests/baselines/reference/inferTypesWithExtends1.symbols b/tests/baselines/reference/inferTypesWithExtends1.symbols index d487baa8ab814..eba57241461af 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,94 @@ 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)) + +// from mongoose +type IfEquals = (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 ? A : B; +>IfEquals : Symbol(IfEquals, Decl(inferTypesWithExtends1.ts, 105, 76)) +>X : Symbol(X, Decl(inferTypesWithExtends1.ts, 108, 14)) +>Y : Symbol(Y, Decl(inferTypesWithExtends1.ts, 108, 16)) +>A : Symbol(A, Decl(inferTypesWithExtends1.ts, 108, 19)) +>B : Symbol(B, Decl(inferTypesWithExtends1.ts, 108, 22)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 108, 30)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 108, 30)) +>X : Symbol(X, Decl(inferTypesWithExtends1.ts, 108, 14)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 108, 68)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 108, 68)) +>Y : Symbol(Y, Decl(inferTypesWithExtends1.ts, 108, 16)) +>A : Symbol(A, Decl(inferTypesWithExtends1.ts, 108, 19)) +>B : Symbol(B, Decl(inferTypesWithExtends1.ts, 108, 22)) + diff --git a/tests/baselines/reference/inferTypesWithExtends1.types b/tests/baselines/reference/inferTypesWithExtends1.types index 24215af18e2b7..898f847f2de72 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,41 @@ 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 + +// from mongoose +type IfEquals = (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 ? A : B; +>IfEquals : IfEquals + 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..a6268b50a3c74 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,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 `?`) + +// from mongoose +type IfEquals = (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 ? A : B; 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());` }); From 326389b6a53a13e724cf7ec0a82eef270891fc40 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Mon, 14 Mar 2022 18:56:47 -0700 Subject: [PATCH 3/6] More aggressive parens to match existing DT tests --- src/compiler/factory/nodeFactory.ts | 2 ++ src/compiler/factory/parenthesizerRules.ts | 2 ++ src/compiler/types.ts | 2 ++ src/services/textChanges.ts | 11 ++++++- .../abstractClassUnionInstantiation.types | 6 ++-- .../reference/aliasUsageInArray.types | 6 ++-- .../reference/ambientConstLiterals.types | 6 ++-- tests/baselines/reference/arrayLiterals.types | 6 ++-- .../reference/arrayOfFunctionTypes3.types | 6 ++-- .../bitwiseNotOperatorWithEnumType.types | 2 +- ...assCanExtendConstructorFunction.errors.txt | 8 ++--- .../classCanExtendConstructorFunction.types | 4 +-- .../baselines/reference/constEnumErrors.types | 4 +-- tests/baselines/reference/constEnums.types | 28 ++++++++-------- .../constructorTagOnClassConstructor.types | 4 +-- .../reference/controlFlowIfStatement.types | 2 +- tests/baselines/reference/declFileEnums.types | 2 +- .../declarationEmitSpreadStringlyKeyedEnum.js | 14 ++++---- ...clarationEmitSpreadStringlyKeyedEnum.types | 18 +++++------ .../decrementOperatorWithEnumType.types | 2 +- ...peratorWithEnumTypeInvalidOperations.types | 2 +- .../deleteOperatorWithEnumType.types | 2 +- .../derivedClassSuperProperties.types | 4 +-- .../reference/discriminatedUnionTypes2.types | 4 +-- .../reference/doubleUnderscoreEnumEmit.types | 4 +-- tests/baselines/reference/enumErrors.types | 6 ++-- .../reference/enumIdentifierLiterals.types | 10 +++--- .../enumWithNegativeInfinityProperty.types | 2 +- .../enumWithQuotedElementName1.types | 2 +- .../enumWithQuotedElementName2.types | 2 +- .../reference/enumWithUnicodeEscape1.types | 2 +- .../incrementOperatorWithEnumType.types | 2 +- ...peratorWithEnumTypeInvalidOperations.types | 2 +- .../intersectionAndUnionTypes.errors.txt | 32 +++++++++---------- .../reference/intersectionAndUnionTypes.types | 26 +++++++-------- .../reference/intersectionNarrowing.types | 24 +++++++------- .../intersectionOfUnionNarrowing.types | 4 +-- .../reference/keyofAndIndexedAccess2.types | 2 +- .../literalsInComputedProperties1.types | 8 ++--- .../reference/narrowingByTypeofInSwitch.types | 8 ++--- .../reference/narrowingTypeofFunction.types | 12 +++---- .../negateOperatorWithEnumType.types | 4 +-- .../objectLiteralExcessProperties.errors.txt | 4 +-- .../objectLiteralExcessProperties.types | 2 +- tests/baselines/reference/objectSpread.types | 24 +++++++------- tests/baselines/reference/parserEnum5.types | 4 +-- tests/baselines/reference/parserEnum7.types | 6 ++-- ...artialOfLargeAPIIsAbleToBeWorkedWith.types | 4 +-- .../reference/plusOperatorWithEnumType.types | 2 +- .../reference/primitiveUnionDetection.types | 6 ++-- .../reference/spreadObjectOrFalsy.js | 2 +- .../reference/spreadObjectOrFalsy.types | 8 ++--- .../staticFieldWithInterfaceContext.types | 4 +-- .../reference/templateLiteralTypes2.types | 4 +-- .../reference/thisTypeInObjectLiterals2.types | 2 +- .../typeGuardIntersectionTypes.types | 2 +- .../typeGuardsWithInstanceOf.errors.txt | 8 ++--- .../reference/typeGuardsWithInstanceOf.types | 6 ++-- .../typeofOperatorWithEnumType.types | 2 +- .../reference/unionTypeInference.types | 14 ++++---- .../reference/voidOperatorWithEnumType.types | 2 +- .../fourslash/codeFixAddVoidToPromise.4.ts | 2 +- .../fourslash/codeFixAddVoidToPromiseJS.4.ts | 2 +- .../codeFixAddVoidToPromiseJS_all.ts | 2 +- .../fourslash/codeFixAddVoidToPromise_all.ts | 2 +- 65 files changed, 214 insertions(+), 199 deletions(-) diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index 2d19d8714f430..d3e1314f76c8b 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -44,6 +44,8 @@ namespace ts { const factory: NodeFactory = { get parenthesizer() { return parenthesizerRules(); }, get converters() { return converters(); }, + baseFactory, + flags, createNodeArray, createNumericLiteral, createBigIntLiteral, diff --git a/src/compiler/factory/parenthesizerRules.ts b/src/compiler/factory/parenthesizerRules.ts index 9f42496cc17cb..c824c13fd1629 100644 --- a/src/compiler/factory/parenthesizerRules.ts +++ b/src/compiler/factory/parenthesizerRules.ts @@ -434,6 +434,7 @@ namespace ts { function parenthesizeConstituentTypeOfUnionType(type: TypeNode) { switch (type.kind) { case SyntaxKind.UnionType: // Not strictly necessary, but a union containing a union should have been flattened + case SyntaxKind.IntersectionType: // Not strictly necessary, but makes generated output more readable and avoids breaks in DT tests return factory.createParenthesizedType(type); } return parenthesizeCheckTypeOfConditionalType(type); @@ -501,6 +502,7 @@ namespace ts { switch (type.kind) { case SyntaxKind.InferType: case SyntaxKind.TypeOperator: + case SyntaxKind.TypeQuery: // Not strictly necessary, but makes generated output more readable and avoids breaks in DT tests return factory.createParenthesizedType(type); } return parenthesizeOperandOfTypeOperator(type); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 409c3a8498abb..06173912eefe0 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -7158,6 +7158,8 @@ namespace ts { export interface NodeFactory { /* @internal */ readonly parenthesizer: ParenthesizerRules; /* @internal */ readonly converters: NodeConverters; + /* @internal */ readonly baseFactory: BaseNodeFactory; + /* @internal */ readonly flags: NodeFactoryFlags; createNodeArray(elements?: readonly T[], hasTrailingComma?: boolean): NodeArray; // diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index dc2918572d02c..2a13736ff5a11 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -1123,8 +1123,17 @@ namespace ts.textChanges { return skipTrivia(s, 0) === s.length; } + // A transformation context that won't perform parenthesization, as some parenthesization rules + // are more aggressive than is strictly necessary. + const textChangesTransformationContext: TransformationContext = { + ...nullTransformationContext, + factory: createNodeFactory( + nullTransformationContext.factory.flags | NodeFactoryFlags.NoParenthesizerRules, + nullTransformationContext.factory.baseFactory), + }; + export function assignPositionsToNode(node: Node): Node { - const visited = visitEachChild(node, assignPositionsToNode, nullTransformationContext, assignPositionsToNodeArray, assignPositionsToNode); + const visited = visitEachChild(node, assignPositionsToNode, textChangesTransformationContext, assignPositionsToNodeArray, assignPositionsToNode); // create proxy node for non synthesized nodes const newNode = nodeIsSynthesized(visited) ? visited : Object.create(visited) as Node; setTextRangePosEnd(newNode, getPos(node), getEnd(node)); diff --git a/tests/baselines/reference/abstractClassUnionInstantiation.types b/tests/baselines/reference/abstractClassUnionInstantiation.types index 54ada1b28c9ed..969f0b85c44a5 100644 --- a/tests/baselines/reference/abstractClassUnionInstantiation.types +++ b/tests/baselines/reference/abstractClassUnionInstantiation.types @@ -75,11 +75,11 @@ new cls3(); // should work [ConcreteA, ConcreteB].map(cls => new cls()); // should work >[ConcreteA, ConcreteB].map(cls => new cls()) : ConcreteA[] ->[ConcreteA, ConcreteB].map : (callbackfn: (value: typeof ConcreteA, index: number, array: typeof ConcreteA[]) => U, thisArg?: any) => U[] ->[ConcreteA, ConcreteB] : typeof ConcreteA[] +>[ConcreteA, ConcreteB].map : (callbackfn: (value: typeof ConcreteA, index: number, array: (typeof ConcreteA)[]) => U, thisArg?: any) => U[] +>[ConcreteA, ConcreteB] : (typeof ConcreteA)[] >ConcreteA : typeof ConcreteA >ConcreteB : typeof ConcreteB ->map : (callbackfn: (value: typeof ConcreteA, index: number, array: typeof ConcreteA[]) => U, thisArg?: any) => U[] +>map : (callbackfn: (value: typeof ConcreteA, index: number, array: (typeof ConcreteA)[]) => U, thisArg?: any) => U[] >cls => new cls() : (cls: typeof ConcreteA) => ConcreteA >cls : typeof ConcreteA >new cls() : ConcreteA diff --git a/tests/baselines/reference/aliasUsageInArray.types b/tests/baselines/reference/aliasUsageInArray.types index b982d28f8c21f..168bb0cf6f873 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/ambientConstLiterals.types b/tests/baselines/reference/ambientConstLiterals.types index 664e730dd63e6..2f7e3b678b0a1 100644 --- a/tests/baselines/reference/ambientConstLiterals.types +++ b/tests/baselines/reference/ambientConstLiterals.types @@ -12,7 +12,7 @@ enum E { A, B, C, "non identifier" } >A : E.A >B : E.B >C : E.C ->"non identifier" : typeof E["non identifier"] +>"non identifier" : (typeof E)["non identifier"] const c1 = "abc"; >c1 : "abc" @@ -54,8 +54,8 @@ const c8 = E.A; >A : E.A const c8b = E["non identifier"]; ->c8b : typeof E["non identifier"] ->E["non identifier"] : typeof E["non identifier"] +>c8b : (typeof E)["non identifier"] +>E["non identifier"] : (typeof E)["non identifier"] >E : typeof E >"non identifier" : "non identifier" diff --git a/tests/baselines/reference/arrayLiterals.types b/tests/baselines/reference/arrayLiterals.types index 111ad85f4ffbb..ab5c6ea037d12 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 f59a292bf24e5..4dd258645a6f2 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/bitwiseNotOperatorWithEnumType.types b/tests/baselines/reference/bitwiseNotOperatorWithEnumType.types index 8400808656b6e..3ecc4a705a29e 100644 --- a/tests/baselines/reference/bitwiseNotOperatorWithEnumType.types +++ b/tests/baselines/reference/bitwiseNotOperatorWithEnumType.types @@ -5,7 +5,7 @@ enum ENUM1 { A, B, "" }; >ENUM1 : ENUM1 >A : ENUM1.A >B : ENUM1.B ->"" : typeof ENUM1[""] +>"" : (typeof ENUM1)[""] // enum type var var ResultIsNumber1 = ~ENUM1; diff --git a/tests/baselines/reference/classCanExtendConstructorFunction.errors.txt b/tests/baselines/reference/classCanExtendConstructorFunction.errors.txt index 1cb5e22b0e9b0..1fd6c25a714e4 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 61080fa649de5..a060d27e54d44 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 15b49ec37c09b..d2d65e3196877 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/constEnums.types b/tests/baselines/reference/constEnums.types index cee4da5c2e1ba..a5b83c46a4ef1 100644 --- a/tests/baselines/reference/constEnums.types +++ b/tests/baselines/reference/constEnums.types @@ -184,25 +184,25 @@ const enum Comments { >Comments : Comments "//", ->"//" : typeof Comments["//"] +>"//" : (typeof Comments)["//"] "/*", ->"/*" : typeof Comments["/*"] +>"/*" : (typeof Comments)["/*"] "*/", ->"*/" : typeof Comments["*/"] +>"*/" : (typeof Comments)["*/"] "///", ->"///" : typeof Comments["///"] +>"///" : (typeof Comments)["///"] "#", ->"#" : typeof Comments["#"] +>"#" : (typeof Comments)["#"] "", ->"-->" : typeof Comments["-->"] +>"-->" : (typeof Comments)["-->"] } module A { @@ -624,37 +624,37 @@ function baz(c: Comments) { >c : Comments case Comments["//"]: ->Comments["//"] : typeof Comments["//"] +>Comments["//"] : (typeof Comments)["//"] >Comments : typeof Comments >"//" : "//" case Comments["/*"]: ->Comments["/*"] : typeof Comments["/*"] +>Comments["/*"] : (typeof Comments)["/*"] >Comments : typeof Comments >"/*" : "/*" case Comments["*/"]: ->Comments["*/"] : typeof Comments["*/"] +>Comments["*/"] : (typeof Comments)["*/"] >Comments : typeof Comments >"*/" : "*/" case Comments["///"]: ->Comments["///"] : typeof Comments["///"] +>Comments["///"] : (typeof Comments)["///"] >Comments : typeof Comments >"///" : "///" case Comments["#"]: ->Comments["#"] : typeof Comments["#"] +>Comments["#"] : (typeof Comments)["#"] >Comments : typeof Comments >"#" : "#" case Comments[""]: ->Comments["-->"] : typeof Comments["-->"] +>Comments["-->"] : (typeof Comments)["-->"] >Comments : typeof Comments >"-->" : "-->" diff --git a/tests/baselines/reference/constructorTagOnClassConstructor.types b/tests/baselines/reference/constructorTagOnClassConstructor.types index ec81bba0712e9..f93061704a923 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 577c28e703b3e..d549ef6f0a2bb 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/declFileEnums.types b/tests/baselines/reference/declFileEnums.types index ef3b86f95c4c4..a756898784ea2 100644 --- a/tests/baselines/reference/declFileEnums.types +++ b/tests/baselines/reference/declFileEnums.types @@ -83,7 +83,7 @@ enum e5 { >"Sunday" : e5.Sunday "Weekend days" ->"Weekend days" : typeof e5["Weekend days"] +>"Weekend days" : (typeof e5)["Weekend days"] } diff --git a/tests/baselines/reference/declarationEmitSpreadStringlyKeyedEnum.js b/tests/baselines/reference/declarationEmitSpreadStringlyKeyedEnum.js index d24b12c25ff6b..8ae33d5edd4bc 100644 --- a/tests/baselines/reference/declarationEmitSpreadStringlyKeyedEnum.js +++ b/tests/baselines/reference/declarationEmitSpreadStringlyKeyedEnum.js @@ -42,12 +42,12 @@ declare enum AgeGroups { } export declare const SpotifyAgeGroupEnum: { [x: number]: string; - "0-17": typeof AgeGroups["0-17"]; - "18-22": typeof AgeGroups["18-22"]; - "23-27": typeof AgeGroups["23-27"]; - "28-34": typeof AgeGroups["28-34"]; - "35-44": typeof AgeGroups["35-44"]; - "45-59": typeof AgeGroups["45-59"]; - "60-150": typeof AgeGroups["60-150"]; + "0-17": (typeof AgeGroups)["0-17"]; + "18-22": (typeof AgeGroups)["18-22"]; + "23-27": (typeof AgeGroups)["23-27"]; + "28-34": (typeof AgeGroups)["28-34"]; + "35-44": (typeof AgeGroups)["35-44"]; + "45-59": (typeof AgeGroups)["45-59"]; + "60-150": (typeof AgeGroups)["60-150"]; }; export {}; diff --git a/tests/baselines/reference/declarationEmitSpreadStringlyKeyedEnum.types b/tests/baselines/reference/declarationEmitSpreadStringlyKeyedEnum.types index 82c31d18e68b5..7124555580f3a 100644 --- a/tests/baselines/reference/declarationEmitSpreadStringlyKeyedEnum.types +++ b/tests/baselines/reference/declarationEmitSpreadStringlyKeyedEnum.types @@ -1,16 +1,16 @@ === tests/cases/compiler/declarationEmitSpreadStringlyKeyedEnum.ts === enum AgeGroups { "0-17" , "18-22" , "23-27" , "28-34" , "35-44" , "45-59" , "60-150" } >AgeGroups : AgeGroups ->"0-17" : typeof AgeGroups["0-17"] ->"18-22" : typeof AgeGroups["18-22"] ->"23-27" : typeof AgeGroups["23-27"] ->"28-34" : typeof AgeGroups["28-34"] ->"35-44" : typeof AgeGroups["35-44"] ->"45-59" : typeof AgeGroups["45-59"] ->"60-150" : typeof AgeGroups["60-150"] +>"0-17" : (typeof AgeGroups)["0-17"] +>"18-22" : (typeof AgeGroups)["18-22"] +>"23-27" : (typeof AgeGroups)["23-27"] +>"28-34" : (typeof AgeGroups)["28-34"] +>"35-44" : (typeof AgeGroups)["35-44"] +>"45-59" : (typeof AgeGroups)["45-59"] +>"60-150" : (typeof AgeGroups)["60-150"] export const SpotifyAgeGroupEnum = { ...AgeGroups }; ->SpotifyAgeGroupEnum : { [x: number]: string; "0-17": typeof AgeGroups["0-17"]; "18-22": typeof AgeGroups["18-22"]; "23-27": typeof AgeGroups["23-27"]; "28-34": typeof AgeGroups["28-34"]; "35-44": typeof AgeGroups["35-44"]; "45-59": typeof AgeGroups["45-59"]; "60-150": typeof AgeGroups["60-150"]; } ->{ ...AgeGroups } : { [x: number]: string; "0-17": typeof AgeGroups["0-17"]; "18-22": typeof AgeGroups["18-22"]; "23-27": typeof AgeGroups["23-27"]; "28-34": typeof AgeGroups["28-34"]; "35-44": typeof AgeGroups["35-44"]; "45-59": typeof AgeGroups["45-59"]; "60-150": typeof AgeGroups["60-150"]; } +>SpotifyAgeGroupEnum : { [x: number]: string; "0-17": (typeof AgeGroups)["0-17"]; "18-22": (typeof AgeGroups)["18-22"]; "23-27": (typeof AgeGroups)["23-27"]; "28-34": (typeof AgeGroups)["28-34"]; "35-44": (typeof AgeGroups)["35-44"]; "45-59": (typeof AgeGroups)["45-59"]; "60-150": (typeof AgeGroups)["60-150"]; } +>{ ...AgeGroups } : { [x: number]: string; "0-17": (typeof AgeGroups)["0-17"]; "18-22": (typeof AgeGroups)["18-22"]; "23-27": (typeof AgeGroups)["23-27"]; "28-34": (typeof AgeGroups)["28-34"]; "35-44": (typeof AgeGroups)["35-44"]; "45-59": (typeof AgeGroups)["45-59"]; "60-150": (typeof AgeGroups)["60-150"]; } >AgeGroups : typeof AgeGroups diff --git a/tests/baselines/reference/decrementOperatorWithEnumType.types b/tests/baselines/reference/decrementOperatorWithEnumType.types index 81f2a638fb4e1..45b86f2d2faf5 100644 --- a/tests/baselines/reference/decrementOperatorWithEnumType.types +++ b/tests/baselines/reference/decrementOperatorWithEnumType.types @@ -5,7 +5,7 @@ enum ENUM1 { A, B, "" }; >ENUM1 : ENUM1 >A : ENUM1.A >B : ENUM1.B ->"" : typeof ENUM1[""] +>"" : (typeof ENUM1)[""] // expression var ResultIsNumber1 = --ENUM1["A"]; diff --git a/tests/baselines/reference/decrementOperatorWithEnumTypeInvalidOperations.types b/tests/baselines/reference/decrementOperatorWithEnumTypeInvalidOperations.types index 1e469c9312cc7..3f25332999cd5 100644 --- a/tests/baselines/reference/decrementOperatorWithEnumTypeInvalidOperations.types +++ b/tests/baselines/reference/decrementOperatorWithEnumTypeInvalidOperations.types @@ -8,7 +8,7 @@ enum ENUM1 { A, B, "" }; >ENUM1 : ENUM1 >A : ENUM1.A >B : ENUM1.B ->"" : typeof ENUM1[""] +>"" : (typeof ENUM1)[""] // enum type var var ResultIsNumber1 = --ENUM; diff --git a/tests/baselines/reference/deleteOperatorWithEnumType.types b/tests/baselines/reference/deleteOperatorWithEnumType.types index 1ba8b696c5ea1..143bbda531af7 100644 --- a/tests/baselines/reference/deleteOperatorWithEnumType.types +++ b/tests/baselines/reference/deleteOperatorWithEnumType.types @@ -8,7 +8,7 @@ enum ENUM1 { A, B, "" }; >ENUM1 : ENUM1 >A : ENUM1.A >B : ENUM1.B ->"" : typeof ENUM1[""] +>"" : (typeof ENUM1)[""] // enum type var var ResultIsBoolean1 = delete ENUM; diff --git a/tests/baselines/reference/derivedClassSuperProperties.types b/tests/baselines/reference/derivedClassSuperProperties.types index b86f54e38bd0e..c52f578ce7ecd 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 ff019af51fc2d..695f0c3768f00 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/doubleUnderscoreEnumEmit.types b/tests/baselines/reference/doubleUnderscoreEnumEmit.types index 16690df1086e4..c1758414f1fc1 100644 --- a/tests/baselines/reference/doubleUnderscoreEnumEmit.types +++ b/tests/baselines/reference/doubleUnderscoreEnumEmit.types @@ -7,11 +7,11 @@ enum Foo { >1 : 1 "(Anonymous function)" = 2, ->"(Anonymous function)" : typeof Foo["(Anonymous function)"] +>"(Anonymous function)" : (typeof Foo)["(Anonymous function)"] >2 : 2 "(Anonymous class)" = 4, ->"(Anonymous class)" : typeof Foo["(Anonymous class)"] +>"(Anonymous class)" : (typeof Foo)["(Anonymous class)"] >4 : 4 "__call" = 10 diff --git a/tests/baselines/reference/enumErrors.types b/tests/baselines/reference/enumErrors.types index 05a74414ef05b..5888e0e3e673b 100644 --- a/tests/baselines/reference/enumErrors.types +++ b/tests/baselines/reference/enumErrors.types @@ -132,11 +132,11 @@ enum E13 { postColonValueComma: 2, >postColonValueComma : E13.postColonValueComma ->2 : typeof E13["2"] +>2 : (typeof E13)["2"] postColonValueSemicolon: 3; >postColonValueSemicolon : E13.postColonValueSemicolon ->3 : typeof E13["3"] +>3 : (typeof E13)["3"] }; @@ -146,7 +146,7 @@ enum E14 { a, b: any "hello" += 1, c, d} >b : E14.b >any : E14.any >"hello" : E14.hello ->1 : typeof E14["1"] +>1 : (typeof E14)["1"] >c : E14.c >d : E14.d diff --git a/tests/baselines/reference/enumIdentifierLiterals.types b/tests/baselines/reference/enumIdentifierLiterals.types index 7d5463c374087..e37e8f3a15951 100644 --- a/tests/baselines/reference/enumIdentifierLiterals.types +++ b/tests/baselines/reference/enumIdentifierLiterals.types @@ -3,17 +3,17 @@ enum Nums { >Nums : Nums 1.0, ->1.0 : typeof Nums["1"] +>1.0 : (typeof Nums)["1"] 11e-1, ->11e-1 : typeof Nums["1.1"] +>11e-1 : (typeof Nums)["1.1"] 0.12e1, ->0.12e1 : typeof Nums["1.2"] +>0.12e1 : (typeof Nums)["1.2"] "13e-1", ->"13e-1" : typeof Nums["13e-1"] +>"13e-1" : (typeof Nums)["13e-1"] 0xF00D ->0xF00D : typeof Nums["61453"] +>0xF00D : (typeof Nums)["61453"] } diff --git a/tests/baselines/reference/enumWithNegativeInfinityProperty.types b/tests/baselines/reference/enumWithNegativeInfinityProperty.types index b1cbe05f53ec5..3a795236c47a2 100644 --- a/tests/baselines/reference/enumWithNegativeInfinityProperty.types +++ b/tests/baselines/reference/enumWithNegativeInfinityProperty.types @@ -3,7 +3,7 @@ enum A { >A : A "-Infinity" = 1 ->"-Infinity" : typeof A["-Infinity"] +>"-Infinity" : (typeof A)["-Infinity"] >1 : 1 } diff --git a/tests/baselines/reference/enumWithQuotedElementName1.types b/tests/baselines/reference/enumWithQuotedElementName1.types index b3b708184aea5..2fd0e3f442c69 100644 --- a/tests/baselines/reference/enumWithQuotedElementName1.types +++ b/tests/baselines/reference/enumWithQuotedElementName1.types @@ -3,5 +3,5 @@ enum E { >E : E 'fo"o', ->'fo"o' : typeof E["fo\"o"] +>'fo"o' : (typeof E)["fo\"o"] } diff --git a/tests/baselines/reference/enumWithQuotedElementName2.types b/tests/baselines/reference/enumWithQuotedElementName2.types index 67fa731e88c29..ce871d0535267 100644 --- a/tests/baselines/reference/enumWithQuotedElementName2.types +++ b/tests/baselines/reference/enumWithQuotedElementName2.types @@ -3,5 +3,5 @@ enum E { >E : E "fo'o", ->"fo'o" : typeof E["fo'o"] +>"fo'o" : (typeof E)["fo'o"] } diff --git a/tests/baselines/reference/enumWithUnicodeEscape1.types b/tests/baselines/reference/enumWithUnicodeEscape1.types index 701f0f9bd3b37..e33394fba3153 100644 --- a/tests/baselines/reference/enumWithUnicodeEscape1.types +++ b/tests/baselines/reference/enumWithUnicodeEscape1.types @@ -3,6 +3,6 @@ enum E { >E : E 'gold \u2730' ->'gold \u2730' : typeof E["gold \u2730"] +>'gold \u2730' : (typeof E)["gold \u2730"] } diff --git a/tests/baselines/reference/incrementOperatorWithEnumType.types b/tests/baselines/reference/incrementOperatorWithEnumType.types index deb056503a61a..6c7c1720bf69f 100644 --- a/tests/baselines/reference/incrementOperatorWithEnumType.types +++ b/tests/baselines/reference/incrementOperatorWithEnumType.types @@ -5,7 +5,7 @@ enum ENUM1 { A, B, "" }; >ENUM1 : ENUM1 >A : ENUM1.A >B : ENUM1.B ->"" : typeof ENUM1[""] +>"" : (typeof ENUM1)[""] // expression var ResultIsNumber1 = ++ENUM1["B"]; diff --git a/tests/baselines/reference/incrementOperatorWithEnumTypeInvalidOperations.types b/tests/baselines/reference/incrementOperatorWithEnumTypeInvalidOperations.types index d4458ca41bb35..5c33351ea2345 100644 --- a/tests/baselines/reference/incrementOperatorWithEnumTypeInvalidOperations.types +++ b/tests/baselines/reference/incrementOperatorWithEnumTypeInvalidOperations.types @@ -8,7 +8,7 @@ enum ENUM1 { A, B, "" }; >ENUM1 : ENUM1 >A : ENUM1.A >B : ENUM1.B ->"" : typeof ENUM1[""] +>"" : (typeof ENUM1)[""] // enum type var var ResultIsNumber1 = ++ENUM; diff --git a/tests/baselines/reference/intersectionAndUnionTypes.errors.txt b/tests/baselines/reference/intersectionAndUnionTypes.errors.txt index bd379acb0becf..049ff9ca685a3 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 ae031a211e92e..0109cd1f7892e 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 2a479d57dcfa4..049e6c976eb6d 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 31bd761bf820b..27dc8f3dc6c6c 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 6126559cbcdf5..9fa1ac46783bb 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess2.types +++ b/tests/baselines/reference/keyofAndIndexedAccess2.types @@ -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/literalsInComputedProperties1.types b/tests/baselines/reference/literalsInComputedProperties1.types index 8a3e2dbd81acb..d417b9f40990f 100644 --- a/tests/baselines/reference/literalsInComputedProperties1.types +++ b/tests/baselines/reference/literalsInComputedProperties1.types @@ -161,20 +161,20 @@ enum X { >X : X 1 = 1, ->1 : typeof X["1"] +>1 : (typeof X)["1"] >1 : 1 [2] = 2, ->[2] : typeof X["2"] +>[2] : (typeof X)["2"] >2 : 2 >2 : 2 "3" = 3, ->"3" : typeof X["3"] +>"3" : (typeof X)["3"] >3 : 3 ["4"] = 4, ->["4"] : typeof X["4"] +>["4"] : (typeof X)["4"] >"4" : "4" >4 : 4 diff --git a/tests/baselines/reference/narrowingByTypeofInSwitch.types b/tests/baselines/reference/narrowingByTypeofInSwitch.types index 50e07bbf5f710..2b028aad6bd16 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 517de20c4606b..9342585ddd54e 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/negateOperatorWithEnumType.types b/tests/baselines/reference/negateOperatorWithEnumType.types index 32eb5ebbe28ce..2398303496cfb 100644 --- a/tests/baselines/reference/negateOperatorWithEnumType.types +++ b/tests/baselines/reference/negateOperatorWithEnumType.types @@ -8,7 +8,7 @@ enum ENUM1 { A, B, "" }; >ENUM1 : ENUM1 >A : ENUM1.A >B : ENUM1.B ->"" : typeof ENUM1[""] +>"" : (typeof ENUM1)[""] // enum type var var ResultIsNumber1 = -ENUM; @@ -32,7 +32,7 @@ var ResultIsNumber3 = -(ENUM1.B + ENUM1[""]); >ENUM1.B : ENUM1.B >ENUM1 : typeof ENUM1 >B : ENUM1.B ->ENUM1[""] : typeof ENUM1[""] +>ENUM1[""] : (typeof ENUM1)[""] >ENUM1 : typeof ENUM1 >"" : "" diff --git a/tests/baselines/reference/objectLiteralExcessProperties.errors.txt b/tests/baselines/reference/objectLiteralExcessProperties.errors.txt index 2684694bd7eff..245293d9a7cb6 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 1fe01891583a5..cd3be132fe2d3 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 9ca8206f92991..7fd7675d1d73d 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/parserEnum5.types b/tests/baselines/reference/parserEnum5.types index f44ae1b57ca21..68450ddbd137f 100644 --- a/tests/baselines/reference/parserEnum5.types +++ b/tests/baselines/reference/parserEnum5.types @@ -6,13 +6,13 @@ enum E2 { a, } enum E3 { a: 1, } >E3 : E3 >a : E3.a ->1 : typeof E3["1"] +>1 : (typeof E3)["1"] enum E1 { a, b: 1, c, d: 2 = 3 } >E1 : E1 >a : E1.a >b : E1.b ->1 : typeof E1["1"] +>1 : (typeof E1)["1"] >c : E1.c >d : E1.d >2 : E1.c diff --git a/tests/baselines/reference/parserEnum7.types b/tests/baselines/reference/parserEnum7.types index efc650edd6757..be81351603c66 100644 --- a/tests/baselines/reference/parserEnum7.types +++ b/tests/baselines/reference/parserEnum7.types @@ -3,7 +3,7 @@ enum E { >E : E 1, 2, 3 ->1 : typeof E["1"] ->2 : typeof E["2"] ->3 : typeof E["3"] +>1 : (typeof E)["1"] +>2 : (typeof E)["2"] +>3 : (typeof E)["3"] } diff --git a/tests/baselines/reference/partialOfLargeAPIIsAbleToBeWorkedWith.types b/tests/baselines/reference/partialOfLargeAPIIsAbleToBeWorkedWith.types index ec22725fd3819..fbd46f7fdce2e 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/plusOperatorWithEnumType.types b/tests/baselines/reference/plusOperatorWithEnumType.types index b762505d9f1b1..b19fd30a2090e 100644 --- a/tests/baselines/reference/plusOperatorWithEnumType.types +++ b/tests/baselines/reference/plusOperatorWithEnumType.types @@ -8,7 +8,7 @@ enum ENUM1 { A, B, "" }; >ENUM1 : ENUM1 >A : ENUM1.A >B : ENUM1.B ->"" : typeof ENUM1[""] +>"" : (typeof ENUM1)[""] // enum type var var ResultIsNumber1 = +ENUM; diff --git a/tests/baselines/reference/primitiveUnionDetection.types b/tests/baselines/reference/primitiveUnionDetection.types index 053ea81c39aaa..ac2243d80d4aa 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 17f6dac60d75c..9aae56dc08562 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 548b14e7ca2d7..1b9d54512e9f7 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 6fc0bc7f50dc0..0b109f955c1a1 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 9497a507c95e6..e771c63c5357c 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 a5447768337e4..227be40f79f39 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 c7c573e1cbb13..a9f43b4917930 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 3332be7ef9c30..ee651e82e7d39 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 6b96624610e3e..0b57dbff89bf1 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/typeofOperatorWithEnumType.types b/tests/baselines/reference/typeofOperatorWithEnumType.types index 7f50a98e80cae..5b56029194632 100644 --- a/tests/baselines/reference/typeofOperatorWithEnumType.types +++ b/tests/baselines/reference/typeofOperatorWithEnumType.types @@ -8,7 +8,7 @@ enum ENUM1 { A, B, "" }; >ENUM1 : ENUM1 >A : ENUM1.A >B : ENUM1.B ->"" : typeof ENUM1[""] +>"" : (typeof ENUM1)[""] // enum type var var ResultIsString1 = typeof ENUM; diff --git a/tests/baselines/reference/unionTypeInference.types b/tests/baselines/reference/unionTypeInference.types index 8fdec5844d63e..268d4ed86ebfb 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/baselines/reference/voidOperatorWithEnumType.types b/tests/baselines/reference/voidOperatorWithEnumType.types index c5356d7f3bc7c..ff34ac7ee696e 100644 --- a/tests/baselines/reference/voidOperatorWithEnumType.types +++ b/tests/baselines/reference/voidOperatorWithEnumType.types @@ -8,7 +8,7 @@ enum ENUM1 { A, B, "" }; >ENUM1 : ENUM1 >A : ENUM1.A >B : ENUM1.B ->"" : typeof ENUM1[""] +>"" : (typeof ENUM1)[""] // enum type var var ResultIsAny1 = void ENUM; diff --git a/tests/cases/fourslash/codeFixAddVoidToPromise.4.ts b/tests/cases/fourslash/codeFixAddVoidToPromise.4.ts index 2f2770b436cd1..b414cb4d1e730 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 844d50185166f..171e1135d1aec 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 55446cfbfdefd..5c37cd851d9ae 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 b3da799ea8d07..6f31d3388f211 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());` }); From 4a7019ec6a95e27a4637f1f084c9eb8088085bf5 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Tue, 15 Mar 2022 17:50:32 -0700 Subject: [PATCH 4/6] tests 'infer' constraint using outer type parameter --- .../reference/inferTypesWithExtends1.js | 27 ++++++ .../reference/inferTypesWithExtends1.symbols | 92 ++++++++++++++++--- .../reference/inferTypesWithExtends1.types | 36 ++++++++ .../conditional/inferTypesWithExtends1.ts | 15 +++ 4 files changed, 157 insertions(+), 13 deletions(-) diff --git a/tests/baselines/reference/inferTypesWithExtends1.js b/tests/baselines/reference/inferTypesWithExtends1.js index 3bb791b86812b..de26103c44480 100644 --- a/tests/baselines/reference/inferTypesWithExtends1.js +++ b/tests/baselines/reference/inferTypesWithExtends1.js @@ -106,6 +106,21 @@ type X16 = T extends { [P in infer U extends keyof T]: 1; } ? 1 : 0; // ok, p 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 `?`) +type X19 = T extends (infer U extends number) ? [T, U] : never; +type X19_T1 = X19<"a">; // never +type X19_T2 = X19<1>; // [1, 1] +type X19_T3 = X19<1 | "a">; // [1, 1] + +type X20 = T extends (infer U extends number) ? T extends (infer V extends U) ? [T, U, V] : never : never; +type X20_T1 = X20<1 | "a">; // [1, 1, 1] + +type X21 = T extends (infer U extends N) ? [T, U] : never; +type X21_T1 = X21<1, 1>; // [1, 1] +type X21_T2 = X21<1 | "a", 1>; // [1, 1] +type X21_T3 = X21<1 | 2, 1>; // [1, 1] +type X21_T4 = X21<1 | 2, 2 | 3>; // [2, 2] +type X21_T5 = X21<1 | 2, 3>; // never + // from mongoose type IfEquals = (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 ? A : B; @@ -247,4 +262,16 @@ declare type X17 = T extends { declare type X18 = T extends { [P in keyof T as infer U extends P]: 1; } ? 1 : 0; +declare type X19 = T extends (infer U extends number) ? [T, U] : never; +declare type X19_T1 = X19<"a">; +declare type X19_T2 = X19<1>; +declare type X19_T3 = X19<1 | "a">; +declare type X20 = T extends (infer U extends number) ? T extends (infer V extends U) ? [T, U, V] : never : never; +declare type X20_T1 = X20<1 | "a">; +declare type X21 = T extends (infer U extends N) ? [T, U] : never; +declare type X21_T1 = X21<1, 1>; +declare type X21_T2 = X21<1 | "a", 1>; +declare type X21_T3 = X21<1 | 2, 1>; +declare type X21_T4 = X21<1 | 2, 2 | 3>; +declare type X21_T5 = X21<1 | 2, 3>; declare type IfEquals = (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 ? A : B; diff --git a/tests/baselines/reference/inferTypesWithExtends1.symbols b/tests/baselines/reference/inferTypesWithExtends1.symbols index eba57241461af..82fd31e4a4a8c 100644 --- a/tests/baselines/reference/inferTypesWithExtends1.symbols +++ b/tests/baselines/reference/inferTypesWithExtends1.symbols @@ -416,19 +416,85 @@ type X18 = T extends { [P in keyof T as infer U extends P]: 1; } ? 1 : 0; // >U : Symbol(U, Decl(inferTypesWithExtends1.ts, 105, 48)) >P : Symbol(P, Decl(inferTypesWithExtends1.ts, 105, 27)) +type X19 = T extends (infer U extends number) ? [T, U] : never; +>X19 : Symbol(X19, Decl(inferTypesWithExtends1.ts, 105, 76)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 107, 9)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 107, 9)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 107, 54)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 107, 9)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 107, 54)) + +type X19_T1 = X19<"a">; // never +>X19_T1 : Symbol(X19_T1, Decl(inferTypesWithExtends1.ts, 107, 90)) +>X19 : Symbol(X19, Decl(inferTypesWithExtends1.ts, 105, 76)) + +type X19_T2 = X19<1>; // [1, 1] +>X19_T2 : Symbol(X19_T2, Decl(inferTypesWithExtends1.ts, 108, 23)) +>X19 : Symbol(X19, Decl(inferTypesWithExtends1.ts, 105, 76)) + +type X19_T3 = X19<1 | "a">; // [1, 1] +>X19_T3 : Symbol(X19_T3, Decl(inferTypesWithExtends1.ts, 109, 21)) +>X19 : Symbol(X19, Decl(inferTypesWithExtends1.ts, 105, 76)) + +type X20 = T extends (infer U extends number) ? T extends (infer V extends U) ? [T, U, V] : never : never; +>X20 : Symbol(X20, Decl(inferTypesWithExtends1.ts, 110, 27)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 112, 9)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 112, 9)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 112, 30)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 112, 9)) +>V : Symbol(V, Decl(inferTypesWithExtends1.ts, 112, 67)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 112, 30)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 112, 9)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 112, 30)) +>V : Symbol(V, Decl(inferTypesWithExtends1.ts, 112, 67)) + +type X20_T1 = X20<1 | "a">; // [1, 1, 1] +>X20_T1 : Symbol(X20_T1, Decl(inferTypesWithExtends1.ts, 112, 109)) +>X20 : Symbol(X20, Decl(inferTypesWithExtends1.ts, 110, 27)) + +type X21 = T extends (infer U extends N) ? [T, U] : never; +>X21 : Symbol(X21, Decl(inferTypesWithExtends1.ts, 113, 27)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 115, 9)) +>N : Symbol(N, Decl(inferTypesWithExtends1.ts, 115, 11)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 115, 9)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 115, 48)) +>N : Symbol(N, Decl(inferTypesWithExtends1.ts, 115, 11)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 115, 9)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 115, 48)) + +type X21_T1 = X21<1, 1>; // [1, 1] +>X21_T1 : Symbol(X21_T1, Decl(inferTypesWithExtends1.ts, 115, 79)) +>X21 : Symbol(X21, Decl(inferTypesWithExtends1.ts, 113, 27)) + +type X21_T2 = X21<1 | "a", 1>; // [1, 1] +>X21_T2 : Symbol(X21_T2, Decl(inferTypesWithExtends1.ts, 116, 24)) +>X21 : Symbol(X21, Decl(inferTypesWithExtends1.ts, 113, 27)) + +type X21_T3 = X21<1 | 2, 1>; // [1, 1] +>X21_T3 : Symbol(X21_T3, Decl(inferTypesWithExtends1.ts, 117, 30)) +>X21 : Symbol(X21, Decl(inferTypesWithExtends1.ts, 113, 27)) + +type X21_T4 = X21<1 | 2, 2 | 3>; // [2, 2] +>X21_T4 : Symbol(X21_T4, Decl(inferTypesWithExtends1.ts, 118, 28)) +>X21 : Symbol(X21, Decl(inferTypesWithExtends1.ts, 113, 27)) + +type X21_T5 = X21<1 | 2, 3>; // never +>X21_T5 : Symbol(X21_T5, Decl(inferTypesWithExtends1.ts, 119, 32)) +>X21 : Symbol(X21, Decl(inferTypesWithExtends1.ts, 113, 27)) + // from mongoose type IfEquals = (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 ? A : B; ->IfEquals : Symbol(IfEquals, Decl(inferTypesWithExtends1.ts, 105, 76)) ->X : Symbol(X, Decl(inferTypesWithExtends1.ts, 108, 14)) ->Y : Symbol(Y, Decl(inferTypesWithExtends1.ts, 108, 16)) ->A : Symbol(A, Decl(inferTypesWithExtends1.ts, 108, 19)) ->B : Symbol(B, Decl(inferTypesWithExtends1.ts, 108, 22)) ->T : Symbol(T, Decl(inferTypesWithExtends1.ts, 108, 30)) ->T : Symbol(T, Decl(inferTypesWithExtends1.ts, 108, 30)) ->X : Symbol(X, Decl(inferTypesWithExtends1.ts, 108, 14)) ->T : Symbol(T, Decl(inferTypesWithExtends1.ts, 108, 68)) ->T : Symbol(T, Decl(inferTypesWithExtends1.ts, 108, 68)) ->Y : Symbol(Y, Decl(inferTypesWithExtends1.ts, 108, 16)) ->A : Symbol(A, Decl(inferTypesWithExtends1.ts, 108, 19)) ->B : Symbol(B, Decl(inferTypesWithExtends1.ts, 108, 22)) +>IfEquals : Symbol(IfEquals, Decl(inferTypesWithExtends1.ts, 120, 28)) +>X : Symbol(X, Decl(inferTypesWithExtends1.ts, 123, 14)) +>Y : Symbol(Y, Decl(inferTypesWithExtends1.ts, 123, 16)) +>A : Symbol(A, Decl(inferTypesWithExtends1.ts, 123, 19)) +>B : Symbol(B, Decl(inferTypesWithExtends1.ts, 123, 22)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 123, 30)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 123, 30)) +>X : Symbol(X, Decl(inferTypesWithExtends1.ts, 123, 14)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 123, 68)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 123, 68)) +>Y : Symbol(Y, Decl(inferTypesWithExtends1.ts, 123, 16)) +>A : Symbol(A, Decl(inferTypesWithExtends1.ts, 123, 19)) +>B : Symbol(B, Decl(inferTypesWithExtends1.ts, 123, 22)) diff --git a/tests/baselines/reference/inferTypesWithExtends1.types b/tests/baselines/reference/inferTypesWithExtends1.types index 898f847f2de72..83fb55727e0a9 100644 --- a/tests/baselines/reference/inferTypesWithExtends1.types +++ b/tests/baselines/reference/inferTypesWithExtends1.types @@ -267,6 +267,42 @@ type X17 = T extends { [P in keyof T as infer U extends P ? 1 : 0]: 1; } ? 1 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 +type X19 = T extends (infer U extends number) ? [T, U] : never; +>X19 : X19 + +type X19_T1 = X19<"a">; // never +>X19_T1 : never + +type X19_T2 = X19<1>; // [1, 1] +>X19_T2 : [1, 1] + +type X19_T3 = X19<1 | "a">; // [1, 1] +>X19_T3 : [1, 1] + +type X20 = T extends (infer U extends number) ? T extends (infer V extends U) ? [T, U, V] : never : never; +>X20 : X20 + +type X20_T1 = X20<1 | "a">; // [1, 1, 1] +>X20_T1 : [1, 1, 1] + +type X21 = T extends (infer U extends N) ? [T, U] : never; +>X21 : X21 + +type X21_T1 = X21<1, 1>; // [1, 1] +>X21_T1 : [1, 1] + +type X21_T2 = X21<1 | "a", 1>; // [1, 1] +>X21_T2 : [1, 1] + +type X21_T3 = X21<1 | 2, 1>; // [1, 1] +>X21_T3 : [1, 1] + +type X21_T4 = X21<1 | 2, 2 | 3>; // [2, 2] +>X21_T4 : [2, 2] + +type X21_T5 = X21<1 | 2, 3>; // never +>X21_T5 : never + // from mongoose type IfEquals = (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 ? A : B; >IfEquals : IfEquals diff --git a/tests/cases/conformance/types/conditional/inferTypesWithExtends1.ts b/tests/cases/conformance/types/conditional/inferTypesWithExtends1.ts index a6268b50a3c74..67a411fad2703 100644 --- a/tests/cases/conformance/types/conditional/inferTypesWithExtends1.ts +++ b/tests/cases/conformance/types/conditional/inferTypesWithExtends1.ts @@ -108,5 +108,20 @@ type X16 = T extends { [P in infer U extends keyof T]: 1; } ? 1 : 0; // ok, p 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 `?`) +type X19 = T extends (infer U extends number) ? [T, U] : never; +type X19_T1 = X19<"a">; // never +type X19_T2 = X19<1>; // [1, 1] +type X19_T3 = X19<1 | "a">; // [1, 1] + +type X20 = T extends (infer U extends number) ? T extends (infer V extends U) ? [T, U, V] : never : never; +type X20_T1 = X20<1 | "a">; // [1, 1, 1] + +type X21 = T extends (infer U extends N) ? [T, U] : never; +type X21_T1 = X21<1, 1>; // [1, 1] +type X21_T2 = X21<1 | "a", 1>; // [1, 1] +type X21_T3 = X21<1 | 2, 1>; // [1, 1] +type X21_T4 = X21<1 | 2, 2 | 3>; // [2, 2] +type X21_T5 = X21<1 | 2, 3>; // never + // from mongoose type IfEquals = (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 ? A : B; From 02fa9c720fe9ea58e48709e1aa52b89ad8ae650d Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Tue, 15 Mar 2022 17:56:21 -0700 Subject: [PATCH 5/6] Adds a test showing 'infer' cannot reference other 'infer' in same 'extends' --- .../inferTypesWithExtends2.errors.txt | 13 +++++++--- .../reference/inferTypesWithExtends2.js | 8 +++++-- .../reference/inferTypesWithExtends2.symbols | 24 +++++++++++++++---- .../reference/inferTypesWithExtends2.types | 13 ++++++++-- .../conditional/inferTypesWithExtends2.ts | 7 +++++- 5 files changed, 53 insertions(+), 12 deletions(-) diff --git a/tests/baselines/reference/inferTypesWithExtends2.errors.txt b/tests/baselines/reference/inferTypesWithExtends2.errors.txt index 8a63107f74c78..395e7e60fed0c 100644 --- a/tests/baselines/reference/inferTypesWithExtends2.errors.txt +++ b/tests/baselines/reference/inferTypesWithExtends2.errors.txt @@ -1,14 +1,21 @@ tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts(3,26): error TS2838: All declarations of 'U' must have identical constraints. tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts(3,53): error TS2838: All declarations of 'U' must have identical constraints. +tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts(8,48): error TS2304: Cannot find name 'U'. -==== tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts (2 errors) ==== +==== tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts (3 errors) ==== // infer twice with different constraints (same behavior as class/interface) - type X10 = + type X1 = T extends { a: infer U extends string, b: infer U extends number } ? U : ~ !!! error TS2838: All declarations of 'U' must have identical constraints. ~ !!! error TS2838: All declarations of 'U' must have identical constraints. never; - \ No newline at end of file + + // infer cannot reference type params in same 'extends' clause + type X2 = + T extends { a: infer U, b: infer V extends U } ? [U, V] : + ~ +!!! error TS2304: Cannot find name 'U'. + never; \ No newline at end of file diff --git a/tests/baselines/reference/inferTypesWithExtends2.js b/tests/baselines/reference/inferTypesWithExtends2.js index c51a0918ca52e..17bba39edad56 100644 --- a/tests/baselines/reference/inferTypesWithExtends2.js +++ b/tests/baselines/reference/inferTypesWithExtends2.js @@ -1,9 +1,13 @@ //// [inferTypesWithExtends2.ts] // infer twice with different constraints (same behavior as class/interface) -type X10 = +type X1 = T extends { a: infer U extends string, b: infer U extends number } ? U : never; - + +// infer cannot reference type params in same 'extends' clause +type X2 = + T extends { a: infer U, b: infer V extends U } ? [U, V] : + never; //// [inferTypesWithExtends2.js] "use strict"; diff --git a/tests/baselines/reference/inferTypesWithExtends2.symbols b/tests/baselines/reference/inferTypesWithExtends2.symbols index c5bb1b387dfe8..3c8bf66bf8b7a 100644 --- a/tests/baselines/reference/inferTypesWithExtends2.symbols +++ b/tests/baselines/reference/inferTypesWithExtends2.symbols @@ -1,11 +1,11 @@ === tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts === // infer twice with different constraints (same behavior as class/interface) -type X10 = ->X10 : Symbol(X10, Decl(inferTypesWithExtends2.ts, 0, 0)) ->T : Symbol(T, Decl(inferTypesWithExtends2.ts, 1, 9)) +type X1 = +>X1 : Symbol(X1, Decl(inferTypesWithExtends2.ts, 0, 0)) +>T : Symbol(T, Decl(inferTypesWithExtends2.ts, 1, 8)) T extends { a: infer U extends string, b: infer U extends number } ? U : ->T : Symbol(T, Decl(inferTypesWithExtends2.ts, 1, 9)) +>T : Symbol(T, Decl(inferTypesWithExtends2.ts, 1, 8)) >a : Symbol(a, Decl(inferTypesWithExtends2.ts, 2, 15)) >U : Symbol(U, Decl(inferTypesWithExtends2.ts, 2, 24), Decl(inferTypesWithExtends2.ts, 2, 51)) >b : Symbol(b, Decl(inferTypesWithExtends2.ts, 2, 42)) @@ -14,3 +14,19 @@ type X10 = never; +// infer cannot reference type params in same 'extends' clause +type X2 = +>X2 : Symbol(X2, Decl(inferTypesWithExtends2.ts, 3, 10)) +>T : Symbol(T, Decl(inferTypesWithExtends2.ts, 6, 8)) + + T extends { a: infer U, b: infer V extends U } ? [U, V] : +>T : Symbol(T, Decl(inferTypesWithExtends2.ts, 6, 8)) +>a : Symbol(a, Decl(inferTypesWithExtends2.ts, 7, 15)) +>U : Symbol(U, Decl(inferTypesWithExtends2.ts, 7, 24)) +>b : Symbol(b, Decl(inferTypesWithExtends2.ts, 7, 27)) +>V : Symbol(V, Decl(inferTypesWithExtends2.ts, 7, 36)) +>U : Symbol(U) +>U : Symbol(U, Decl(inferTypesWithExtends2.ts, 7, 24)) +>V : Symbol(V, Decl(inferTypesWithExtends2.ts, 7, 36)) + + never; diff --git a/tests/baselines/reference/inferTypesWithExtends2.types b/tests/baselines/reference/inferTypesWithExtends2.types index 6d954cc977b5e..e76936d07028a 100644 --- a/tests/baselines/reference/inferTypesWithExtends2.types +++ b/tests/baselines/reference/inferTypesWithExtends2.types @@ -1,7 +1,7 @@ === tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts === // infer twice with different constraints (same behavior as class/interface) -type X10 = ->X10 : X10 +type X1 = +>X1 : X1 T extends { a: infer U extends string, b: infer U extends number } ? U : >a : U @@ -9,3 +9,12 @@ type X10 = never; +// infer cannot reference type params in same 'extends' clause +type X2 = +>X2 : X2 + + T extends { a: infer U, b: infer V extends U } ? [U, V] : +>a : U +>b : V + + never; diff --git a/tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts b/tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts index f5ff5fe5c90af..98e99a55562ae 100644 --- a/tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts +++ b/tests/cases/conformance/types/conditional/inferTypesWithExtends2.ts @@ -1,6 +1,11 @@ // @strict: true // infer twice with different constraints (same behavior as class/interface) -type X10 = +type X1 = T extends { a: infer U extends string, b: infer U extends number } ? U : never; + +// infer cannot reference type params in same 'extends' clause +type X2 = + T extends { a: infer U, b: infer V extends U } ? [U, V] : + never; \ No newline at end of file From 01b9a2d5b002298d7bb76e1f2c90dcf8a7908545 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Wed, 23 Mar 2022 21:00:18 -0700 Subject: [PATCH 6/6] Emit extends clause for synthetic infer typesduring declaration emit --- src/compiler/checker.ts | 19 ++++++++++-- .../reference/inferTypesWithExtends1.js | 23 +++++++++++++- .../reference/inferTypesWithExtends1.symbols | 31 +++++++++++++++++++ .../reference/inferTypesWithExtends1.types | 22 +++++++++++++ .../reference/infiniteConstraints.types | 4 +-- .../conditional/inferTypesWithExtends1.ts | 11 +++++++ 6 files changed, 104 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 45d88e4b8248f..84af383d3df7c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4977,7 +4977,20 @@ namespace ts { if (type.flags & TypeFlags.TypeParameter || objectFlags & ObjectFlags.ClassOrInterface) { if (type.flags & TypeFlags.TypeParameter && contains(context.inferTypeParameters, type)) { context.approximateLength += (symbolName(type.symbol).length + 6); - return factory.createInferTypeNode(typeParameterToDeclarationWithConstraint(type as TypeParameter, context, /*constraintNode*/ undefined)); + let constraintNode: TypeNode | undefined; + const constraint = getConstraintOfTypeParameter(type as TypeParameter); + if (constraint) { + // If the infer type has a constraint that is not the same as the constraint + // we would have normally inferred based on context, we emit the constraint + // using `infer T extends ?`. We omit inferred constraints from type references + // as they may be elided. + const inferredConstraint = getInferredTypeParameterConstraint(type as TypeParameter, /*omitTypeReferences*/ true); + if (!(inferredConstraint && isTypeIdenticalTo(constraint, inferredConstraint))) { + context.approximateLength += 9; + constraintNode = constraint && typeToTypeNodeHelper(constraint, context); + } + } + return factory.createInferTypeNode(typeParameterToDeclarationWithConstraint(type as TypeParameter, context, constraintNode)); } if (context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams && type.flags & TypeFlags.TypeParameter && @@ -13259,7 +13272,7 @@ namespace ts { return mapDefined(filter(type.symbol && type.symbol.declarations, isTypeParameterDeclaration), getEffectiveConstraintOfTypeParameter)[0]; } - function getInferredTypeParameterConstraint(typeParameter: TypeParameter) { + function getInferredTypeParameterConstraint(typeParameter: TypeParameter, omitTypeReferences?: boolean) { let inferences: Type[] | undefined; if (typeParameter.symbol?.declarations) { for (const declaration of typeParameter.symbol.declarations) { @@ -13269,7 +13282,7 @@ namespace ts { // corresponding type parameter in 'Foo'. When multiple 'infer T' declarations are // present, we form an intersection of the inferred constraint types. const [childTypeParameter = declaration.parent, grandParent] = walkUpParenthesizedTypesAndGetParentAndChild(declaration.parent.parent); - if (grandParent.kind === SyntaxKind.TypeReference) { + if (grandParent.kind === SyntaxKind.TypeReference && !omitTypeReferences) { const typeReference = grandParent as TypeReferenceNode; const typeParameters = getTypeParametersForTypeReference(typeReference); if (typeParameters) { diff --git a/tests/baselines/reference/inferTypesWithExtends1.js b/tests/baselines/reference/inferTypesWithExtends1.js index de26103c44480..6ce0739872373 100644 --- a/tests/baselines/reference/inferTypesWithExtends1.js +++ b/tests/baselines/reference/inferTypesWithExtends1.js @@ -123,10 +123,26 @@ type X21_T5 = X21<1 | 2, 3>; // never // from mongoose type IfEquals = (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 ? A : B; - + +declare const x1: () => (T extends infer U extends number ? 1 : 0); +function f1() { + return x1; +} + +type ExpectNumber = T; +declare const x2: () => (T extends ExpectNumber ? 1 : 0); +function f2() { + return x2; +} //// [inferTypesWithExtends1.js] "use strict"; +function f1() { + return x1; +} +function f2() { + return x2; +} //// [inferTypesWithExtends1.d.ts] @@ -275,3 +291,8 @@ declare type X21_T3 = X21<1 | 2, 1>; declare type X21_T4 = X21<1 | 2, 2 | 3>; declare type X21_T5 = X21<1 | 2, 3>; declare type IfEquals = (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 ? A : B; +declare const x1: () => (T extends infer U extends number ? 1 : 0); +declare function f1(): () => T extends infer U extends number ? 1 : 0; +declare type ExpectNumber = T; +declare const x2: () => (T extends ExpectNumber ? 1 : 0); +declare function f2(): () => T extends infer U extends number ? 1 : 0; diff --git a/tests/baselines/reference/inferTypesWithExtends1.symbols b/tests/baselines/reference/inferTypesWithExtends1.symbols index 82fd31e4a4a8c..01cdc578af5e6 100644 --- a/tests/baselines/reference/inferTypesWithExtends1.symbols +++ b/tests/baselines/reference/inferTypesWithExtends1.symbols @@ -498,3 +498,34 @@ type IfEquals = (() => T extends X ? 1 : 2) extends () => T ex >A : Symbol(A, Decl(inferTypesWithExtends1.ts, 123, 19)) >B : Symbol(B, Decl(inferTypesWithExtends1.ts, 123, 22)) +declare const x1: () => (T extends infer U extends number ? 1 : 0); +>x1 : Symbol(x1, Decl(inferTypesWithExtends1.ts, 125, 13)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 125, 19)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 125, 19)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 125, 43)) + +function f1() { +>f1 : Symbol(f1, Decl(inferTypesWithExtends1.ts, 125, 70)) + + return x1; +>x1 : Symbol(x1, Decl(inferTypesWithExtends1.ts, 125, 13)) +} + +type ExpectNumber = T; +>ExpectNumber : Symbol(ExpectNumber, Decl(inferTypesWithExtends1.ts, 128, 1)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 130, 18)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 130, 18)) + +declare const x2: () => (T extends ExpectNumber ? 1 : 0); +>x2 : Symbol(x2, Decl(inferTypesWithExtends1.ts, 131, 13)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 131, 19)) +>T : Symbol(T, Decl(inferTypesWithExtends1.ts, 131, 19)) +>ExpectNumber : Symbol(ExpectNumber, Decl(inferTypesWithExtends1.ts, 128, 1)) +>U : Symbol(U, Decl(inferTypesWithExtends1.ts, 131, 56)) + +function f2() { +>f2 : Symbol(f2, Decl(inferTypesWithExtends1.ts, 131, 69)) + + return x2; +>x2 : Symbol(x2, Decl(inferTypesWithExtends1.ts, 131, 13)) +} diff --git a/tests/baselines/reference/inferTypesWithExtends1.types b/tests/baselines/reference/inferTypesWithExtends1.types index 83fb55727e0a9..b26386d0f4902 100644 --- a/tests/baselines/reference/inferTypesWithExtends1.types +++ b/tests/baselines/reference/inferTypesWithExtends1.types @@ -307,3 +307,25 @@ type X21_T5 = X21<1 | 2, 3>; // never type IfEquals = (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 ? A : B; >IfEquals : IfEquals +declare const x1: () => (T extends infer U extends number ? 1 : 0); +>x1 : () => T extends infer U extends number ? 1 : 0 + +function f1() { +>f1 : () => () => T extends infer U extends number ? 1 : 0 + + return x1; +>x1 : () => T extends infer U extends number ? 1 : 0 +} + +type ExpectNumber = T; +>ExpectNumber : T + +declare const x2: () => (T extends ExpectNumber ? 1 : 0); +>x2 : () => T extends infer U extends number ? 1 : 0 + +function f2() { +>f2 : () => () => T extends infer U extends number ? 1 : 0 + + return x2; +>x2 : () => T extends infer U extends number ? 1 : 0 +} diff --git a/tests/baselines/reference/infiniteConstraints.types b/tests/baselines/reference/infiniteConstraints.types index 3fa2bb1feedcd..6a3a1a075950c 100644 --- a/tests/baselines/reference/infiniteConstraints.types +++ b/tests/baselines/reference/infiniteConstraints.types @@ -15,7 +15,7 @@ type AProp = T >a : string declare function myBug< ->myBug : (arg: T) => T +>myBug : (arg: T) => T T extends { [K in keyof T]: T[K] extends AProp ? U : never } >(arg: T): T @@ -24,7 +24,7 @@ declare function myBug< const out = myBug({obj1: {a: "test"}}) >out : { obj1: { a: string; }; } >myBug({obj1: {a: "test"}}) : { obj1: { a: string; }; } ->myBug : (arg: T) => T +>myBug : (arg: T) => T >{obj1: {a: "test"}} : { obj1: { a: string; }; } >obj1 : { a: string; } >{a: "test"} : { a: string; } diff --git a/tests/cases/conformance/types/conditional/inferTypesWithExtends1.ts b/tests/cases/conformance/types/conditional/inferTypesWithExtends1.ts index 67a411fad2703..64034a62cb667 100644 --- a/tests/cases/conformance/types/conditional/inferTypesWithExtends1.ts +++ b/tests/cases/conformance/types/conditional/inferTypesWithExtends1.ts @@ -125,3 +125,14 @@ type X21_T5 = X21<1 | 2, 3>; // never // from mongoose type IfEquals = (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 ? A : B; + +declare const x1: () => (T extends infer U extends number ? 1 : 0); +function f1() { + return x1; +} + +type ExpectNumber = T; +declare const x2: () => (T extends ExpectNumber ? 1 : 0); +function f2() { + return x2; +} \ No newline at end of file