diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9dfb4a7e112..7abbd09fb47 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -35335,6 +35335,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); } @@ -38811,7 +38827,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) { @@ -38821,13 +38837,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 dba50cfb533..b86348c5615 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3405,6 +3405,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 f2dc63f8af9..9164c69763b 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 1e2cb936582..e921f08bfc6 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 f8ce2f7047d..6d4f6dae7ff 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3077,6 +3077,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; @@ -3101,7 +3105,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); @@ -3859,22 +3863,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 dc31b5c79cf..74e7c8cd785 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -7090,6 +7090,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 be2fa68bfbb..277f3e912d2 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 e3e2b88dd4e..35421c73ad2 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 7e798851840..33d8052a8c7 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 4ef817304b4..c7a609b3eae 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 dbfa84964df..23b84450e2d 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 04ca9ea6d05..fdba311280a 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 00000000000..0c57e21adb2 --- /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 00000000000..d487baa8ab8 --- /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 00000000000..24215af18e2 --- /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 00000000000..8a63107f74c --- /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 00000000000..c51a0918ca5 --- /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 00000000000..c5bb1b387df --- /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 00000000000..6d954cc977b --- /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 afcb58aff5d..42e5897dc66 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 00000000000..e58fe7a2f16 --- /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 00000000000..f5ff5fe5c90 --- /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 d10af6bb637..afe41c71652 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;`, });