From b2005d0618165d273926ab7fed4ca5854c486079 Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Tue, 30 Dec 2025 21:05:55 +0530 Subject: [PATCH 01/23] quantified types --- internal/ast/ast.go | 41 +++ internal/ast/kind.go | 1 + internal/ast/kind_stringer_generated.go | 303 +++++++++--------- internal/ast/precedence.go | 3 +- internal/binder/binder.go | 5 +- internal/checker/checker.go | 102 +++++- internal/checker/exports.go | 2 +- internal/checker/jsx.go | 2 +- internal/checker/nodebuilderimpl.go | 14 +- internal/checker/relater.go | 27 ++ internal/checker/types.go | 12 +- internal/parser/parser.go | 15 + internal/printer/printer.go | 10 + .../compiler/allowQuantifiedTypes.js | 8 + .../compiler/allowQuantifiedTypes.symbols | 28 ++ .../compiler/allowQuantifiedTypes.types | 17 + .../compiler/quantifiedTypesBasic.errors.txt | 24 ++ .../compiler/quantifiedTypesBasic.js | 26 ++ .../compiler/quantifiedTypesBasic.symbols | 54 ++++ .../compiler/quantifiedTypesBasic.types | 65 ++++ .../compiler/quantifiedTypesBasic2.errors.txt | 28 ++ .../compiler/quantifiedTypesBasic2.js | 27 ++ .../compiler/quantifiedTypesBasic2.symbols | 57 ++++ .../compiler/quantifiedTypesBasic2.types | 74 +++++ .../quantifiedTypesConstraints.errors.txt | 22 ++ .../compiler/quantifiedTypesConstraints.js | 16 + .../quantifiedTypesConstraints.symbols | 31 ++ .../compiler/quantifiedTypesConstraints.types | 32 ++ .../quantifiedTypesIntermediate.errors.txt | 64 ++++ .../compiler/quantifiedTypesIntermediate.js | 78 +++++ .../quantifiedTypesIntermediate.symbols | 127 ++++++++ .../quantifiedTypesIntermediate.types | 192 +++++++++++ ...quantifiedTypesNormalizedShapes.errors.txt | 35 ++ .../quantifiedTypesNormalizedShapes.js | 34 ++ .../quantifiedTypesNormalizedShapes.symbols | 53 +++ .../quantifiedTypesNormalizedShapes.types | 49 +++ ...iedTypesSelfTypesCaseInsensitve.errors.txt | 22 ++ .../quantifiedTypesSelfTypesCaseInsensitve.js | 25 ++ ...tifiedTypesSelfTypesCaseInsensitve.symbols | 55 ++++ ...antifiedTypesSelfTypesCaseInsensitve.types | 46 +++ ...ifiedTypesSelfTypesStateMachine.errors.txt | 48 +++ .../quantifiedTypesSelfTypesStateMachine.js | 77 +++++ ...antifiedTypesSelfTypesStateMachine.symbols | 103 ++++++ ...quantifiedTypesSelfTypesStateMachine.types | 114 +++++++ .../cases/compiler/allowQuantifiedTypes.ts | 3 + testdata/tests/cases/compiler/playground.ts | 0 .../cases/compiler/quantifiedTypesBasic.ts | 11 + .../cases/compiler/quantifiedTypesBasic2.ts | 12 + .../compiler/quantifiedTypesConstraints.ts | 7 + .../compiler/quantifiedTypesIntermediate.ts | 40 +++ .../quantifiedTypesNormalizedShapes.ts | 18 ++ .../quantifiedTypesSelfTypesCaseInsensitve.ts | 16 + .../quantifiedTypesSelfTypesStateMachine.ts | 38 +++ 53 files changed, 2141 insertions(+), 172 deletions(-) create mode 100644 testdata/baselines/reference/compiler/allowQuantifiedTypes.js create mode 100644 testdata/baselines/reference/compiler/allowQuantifiedTypes.symbols create mode 100644 testdata/baselines/reference/compiler/allowQuantifiedTypes.types create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesBasic.errors.txt create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesBasic.js create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesBasic.symbols create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesBasic.types create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesBasic2.errors.txt create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesBasic2.js create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesBasic2.symbols create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesBasic2.types create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesConstraints.errors.txt create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesConstraints.js create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesConstraints.symbols create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesConstraints.types create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesIntermediate.errors.txt create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesIntermediate.js create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesIntermediate.symbols create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesIntermediate.types create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.errors.txt create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.js create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.symbols create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.types create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.errors.txt create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.js create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.symbols create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.types create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.errors.txt create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.js create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.symbols create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.types create mode 100644 testdata/tests/cases/compiler/allowQuantifiedTypes.ts create mode 100644 testdata/tests/cases/compiler/playground.ts create mode 100644 testdata/tests/cases/compiler/quantifiedTypesBasic.ts create mode 100644 testdata/tests/cases/compiler/quantifiedTypesBasic2.ts create mode 100644 testdata/tests/cases/compiler/quantifiedTypesConstraints.ts create mode 100644 testdata/tests/cases/compiler/quantifiedTypesIntermediate.ts create mode 100644 testdata/tests/cases/compiler/quantifiedTypesNormalizedShapes.ts create mode 100644 testdata/tests/cases/compiler/quantifiedTypesSelfTypesCaseInsensitve.ts create mode 100644 testdata/tests/cases/compiler/quantifiedTypesSelfTypesStateMachine.ts diff --git a/internal/ast/ast.go b/internal/ast/ast.go index 3d6dbcffcc6..acd5d37875b 100644 --- a/internal/ast/ast.go +++ b/internal/ast/ast.go @@ -573,6 +573,8 @@ func (n *Node) TypeParameterList() *NodeList { return n.AsTypeAliasDeclaration().TypeParameters case KindJSDocTemplateTag: return n.AsJSDocTemplateTag().TypeParameters + case KindQuantifiedType: + return n.AsQuantifiedTypeNode().TypeParameters default: funcLike := n.FunctionLikeData() if funcLike != nil { @@ -1750,6 +1752,10 @@ func (n *Node) AsConstructorTypeNode() *ConstructorTypeNode { return n.data.(*ConstructorTypeNode) } +func (n *Node) AsQuantifiedTypeNode() *QuantifiedTypeNode { + return n.data.(*QuantifiedTypeNode) +} + func (n *Node) AsTypeQueryNode() *TypeQueryNode { return n.data.(*TypeQueryNode) } @@ -8871,6 +8877,41 @@ func IsTemplateLiteralTypeSpan(node *Node) bool { return node.Kind == KindTemplateLiteralTypeSpan } +// QuantifiedTypeNode + +type QuantifiedTypeNode struct { + TypeNodeBase + LocalsContainerBase + TypeParameters *NodeList // NodeList[*TypeParameterDeclarationNode] + BaseType *TypeNode +} + +func (f *NodeFactory) NewQuantifiedTypeNode(typeParameters *NodeList, baseTypeNode *TypeNode) *Node { + data := &QuantifiedTypeNode{} + data.TypeParameters = typeParameters + data.BaseType = baseTypeNode + return f.newNode(KindQuantifiedType, data) +} + +func (f *NodeFactory) UpdateQuantifiedTypeNode(node *QuantifiedTypeNode, typeParameters *NodeList, baseTypeNode *TypeNode) *Node { + if typeParameters != node.TypeParameters || baseTypeNode != node.BaseType { + return updateNode(f.NewQuantifiedTypeNode(typeParameters, baseTypeNode), node.AsNode(), f.hooks) + } + return node.AsNode() +} + +func (node *QuantifiedTypeNode) ForEachChild(v Visitor) bool { + return visitNodeList(v, node.TypeParameters) || visit(v, node.BaseType) +} + +func (node *QuantifiedTypeNode) VisitEachChild(v *NodeVisitor) *Node { + return v.Factory.UpdateQuantifiedTypeNode(node, v.visitNodes(node.TypeParameters), v.visitNode(node.BaseType)) +} + +func (node *QuantifiedTypeNode) Clone(f NodeFactoryCoercible) *Node { + return cloneNode(f.AsNodeFactory().NewQuantifiedTypeNode(node.TypeParameters, node.BaseType), node.AsNode(), f.AsNodeFactory().hooks) +} + // SyntheticExpression type SyntheticExpression struct { diff --git a/internal/ast/kind.go b/internal/ast/kind.go index ed98bd68ff6..6a359cefedc 100644 --- a/internal/ast/kind.go +++ b/internal/ast/kind.go @@ -226,6 +226,7 @@ const ( KindNamedTupleMember KindTemplateLiteralType KindTemplateLiteralTypeSpan + KindQuantifiedType KindImportType // Binding patterns KindObjectBindingPattern diff --git a/internal/ast/kind_stringer_generated.go b/internal/ast/kind_stringer_generated.go index 3430cc2cb10..4a6ac4ed3a4 100644 --- a/internal/ast/kind_stringer_generated.go +++ b/internal/ast/kind_stringer_generated.go @@ -214,160 +214,161 @@ func _() { _ = x[KindNamedTupleMember-203] _ = x[KindTemplateLiteralType-204] _ = x[KindTemplateLiteralTypeSpan-205] - _ = x[KindImportType-206] - _ = x[KindObjectBindingPattern-207] - _ = x[KindArrayBindingPattern-208] - _ = x[KindBindingElement-209] - _ = x[KindArrayLiteralExpression-210] - _ = x[KindObjectLiteralExpression-211] - _ = x[KindPropertyAccessExpression-212] - _ = x[KindElementAccessExpression-213] - _ = x[KindCallExpression-214] - _ = x[KindNewExpression-215] - _ = x[KindTaggedTemplateExpression-216] - _ = x[KindTypeAssertionExpression-217] - _ = x[KindParenthesizedExpression-218] - _ = x[KindFunctionExpression-219] - _ = x[KindArrowFunction-220] - _ = x[KindDeleteExpression-221] - _ = x[KindTypeOfExpression-222] - _ = x[KindVoidExpression-223] - _ = x[KindAwaitExpression-224] - _ = x[KindPrefixUnaryExpression-225] - _ = x[KindPostfixUnaryExpression-226] - _ = x[KindBinaryExpression-227] - _ = x[KindConditionalExpression-228] - _ = x[KindTemplateExpression-229] - _ = x[KindYieldExpression-230] - _ = x[KindSpreadElement-231] - _ = x[KindClassExpression-232] - _ = x[KindOmittedExpression-233] - _ = x[KindExpressionWithTypeArguments-234] - _ = x[KindAsExpression-235] - _ = x[KindNonNullExpression-236] - _ = x[KindMetaProperty-237] - _ = x[KindSyntheticExpression-238] - _ = x[KindSatisfiesExpression-239] - _ = x[KindTemplateSpan-240] - _ = x[KindSemicolonClassElement-241] - _ = x[KindBlock-242] - _ = x[KindEmptyStatement-243] - _ = x[KindVariableStatement-244] - _ = x[KindExpressionStatement-245] - _ = x[KindIfStatement-246] - _ = x[KindDoStatement-247] - _ = x[KindWhileStatement-248] - _ = x[KindForStatement-249] - _ = x[KindForInStatement-250] - _ = x[KindForOfStatement-251] - _ = x[KindContinueStatement-252] - _ = x[KindBreakStatement-253] - _ = x[KindReturnStatement-254] - _ = x[KindWithStatement-255] - _ = x[KindSwitchStatement-256] - _ = x[KindLabeledStatement-257] - _ = x[KindThrowStatement-258] - _ = x[KindTryStatement-259] - _ = x[KindDebuggerStatement-260] - _ = x[KindVariableDeclaration-261] - _ = x[KindVariableDeclarationList-262] - _ = x[KindFunctionDeclaration-263] - _ = x[KindClassDeclaration-264] - _ = x[KindInterfaceDeclaration-265] - _ = x[KindTypeAliasDeclaration-266] - _ = x[KindEnumDeclaration-267] - _ = x[KindModuleDeclaration-268] - _ = x[KindModuleBlock-269] - _ = x[KindCaseBlock-270] - _ = x[KindNamespaceExportDeclaration-271] - _ = x[KindImportEqualsDeclaration-272] - _ = x[KindImportDeclaration-273] - _ = x[KindImportClause-274] - _ = x[KindNamespaceImport-275] - _ = x[KindNamedImports-276] - _ = x[KindImportSpecifier-277] - _ = x[KindExportAssignment-278] - _ = x[KindExportDeclaration-279] - _ = x[KindNamedExports-280] - _ = x[KindNamespaceExport-281] - _ = x[KindExportSpecifier-282] - _ = x[KindMissingDeclaration-283] - _ = x[KindExternalModuleReference-284] - _ = x[KindJsxElement-285] - _ = x[KindJsxSelfClosingElement-286] - _ = x[KindJsxOpeningElement-287] - _ = x[KindJsxClosingElement-288] - _ = x[KindJsxFragment-289] - _ = x[KindJsxOpeningFragment-290] - _ = x[KindJsxClosingFragment-291] - _ = x[KindJsxAttribute-292] - _ = x[KindJsxAttributes-293] - _ = x[KindJsxSpreadAttribute-294] - _ = x[KindJsxExpression-295] - _ = x[KindJsxNamespacedName-296] - _ = x[KindCaseClause-297] - _ = x[KindDefaultClause-298] - _ = x[KindHeritageClause-299] - _ = x[KindCatchClause-300] - _ = x[KindImportAttributes-301] - _ = x[KindImportAttribute-302] - _ = x[KindPropertyAssignment-303] - _ = x[KindShorthandPropertyAssignment-304] - _ = x[KindSpreadAssignment-305] - _ = x[KindEnumMember-306] - _ = x[KindSourceFile-307] - _ = x[KindJSDocTypeExpression-308] - _ = x[KindJSDocNameReference-309] - _ = x[KindJSDocMemberName-310] - _ = x[KindJSDocAllType-311] - _ = x[KindJSDocNullableType-312] - _ = x[KindJSDocNonNullableType-313] - _ = x[KindJSDocOptionalType-314] - _ = x[KindJSDocVariadicType-315] - _ = x[KindJSDoc-316] - _ = x[KindJSDocText-317] - _ = x[KindJSDocTypeLiteral-318] - _ = x[KindJSDocSignature-319] - _ = x[KindJSDocLink-320] - _ = x[KindJSDocLinkCode-321] - _ = x[KindJSDocLinkPlain-322] - _ = x[KindJSDocTag-323] - _ = x[KindJSDocAugmentsTag-324] - _ = x[KindJSDocImplementsTag-325] - _ = x[KindJSDocDeprecatedTag-326] - _ = x[KindJSDocPublicTag-327] - _ = x[KindJSDocPrivateTag-328] - _ = x[KindJSDocProtectedTag-329] - _ = x[KindJSDocReadonlyTag-330] - _ = x[KindJSDocOverrideTag-331] - _ = x[KindJSDocCallbackTag-332] - _ = x[KindJSDocOverloadTag-333] - _ = x[KindJSDocParameterTag-334] - _ = x[KindJSDocReturnTag-335] - _ = x[KindJSDocThisTag-336] - _ = x[KindJSDocTypeTag-337] - _ = x[KindJSDocTemplateTag-338] - _ = x[KindJSDocTypedefTag-339] - _ = x[KindJSDocSeeTag-340] - _ = x[KindJSDocPropertyTag-341] - _ = x[KindJSDocSatisfiesTag-342] - _ = x[KindJSDocImportTag-343] - _ = x[KindSyntaxList-344] - _ = x[KindJSTypeAliasDeclaration-345] - _ = x[KindJSExportAssignment-346] - _ = x[KindCommonJSExport-347] - _ = x[KindJSImportDeclaration-348] - _ = x[KindNotEmittedStatement-349] - _ = x[KindPartiallyEmittedExpression-350] - _ = x[KindCommaListExpression-351] - _ = x[KindSyntheticReferenceExpression-352] - _ = x[KindNotEmittedTypeElement-353] - _ = x[KindCount-354] + _ = x[KindQuantifiedType-206] + _ = x[KindImportType-207] + _ = x[KindObjectBindingPattern-208] + _ = x[KindArrayBindingPattern-209] + _ = x[KindBindingElement-210] + _ = x[KindArrayLiteralExpression-211] + _ = x[KindObjectLiteralExpression-212] + _ = x[KindPropertyAccessExpression-213] + _ = x[KindElementAccessExpression-214] + _ = x[KindCallExpression-215] + _ = x[KindNewExpression-216] + _ = x[KindTaggedTemplateExpression-217] + _ = x[KindTypeAssertionExpression-218] + _ = x[KindParenthesizedExpression-219] + _ = x[KindFunctionExpression-220] + _ = x[KindArrowFunction-221] + _ = x[KindDeleteExpression-222] + _ = x[KindTypeOfExpression-223] + _ = x[KindVoidExpression-224] + _ = x[KindAwaitExpression-225] + _ = x[KindPrefixUnaryExpression-226] + _ = x[KindPostfixUnaryExpression-227] + _ = x[KindBinaryExpression-228] + _ = x[KindConditionalExpression-229] + _ = x[KindTemplateExpression-230] + _ = x[KindYieldExpression-231] + _ = x[KindSpreadElement-232] + _ = x[KindClassExpression-233] + _ = x[KindOmittedExpression-234] + _ = x[KindExpressionWithTypeArguments-235] + _ = x[KindAsExpression-236] + _ = x[KindNonNullExpression-237] + _ = x[KindMetaProperty-238] + _ = x[KindSyntheticExpression-239] + _ = x[KindSatisfiesExpression-240] + _ = x[KindTemplateSpan-241] + _ = x[KindSemicolonClassElement-242] + _ = x[KindBlock-243] + _ = x[KindEmptyStatement-244] + _ = x[KindVariableStatement-245] + _ = x[KindExpressionStatement-246] + _ = x[KindIfStatement-247] + _ = x[KindDoStatement-248] + _ = x[KindWhileStatement-249] + _ = x[KindForStatement-250] + _ = x[KindForInStatement-251] + _ = x[KindForOfStatement-252] + _ = x[KindContinueStatement-253] + _ = x[KindBreakStatement-254] + _ = x[KindReturnStatement-255] + _ = x[KindWithStatement-256] + _ = x[KindSwitchStatement-257] + _ = x[KindLabeledStatement-258] + _ = x[KindThrowStatement-259] + _ = x[KindTryStatement-260] + _ = x[KindDebuggerStatement-261] + _ = x[KindVariableDeclaration-262] + _ = x[KindVariableDeclarationList-263] + _ = x[KindFunctionDeclaration-264] + _ = x[KindClassDeclaration-265] + _ = x[KindInterfaceDeclaration-266] + _ = x[KindTypeAliasDeclaration-267] + _ = x[KindEnumDeclaration-268] + _ = x[KindModuleDeclaration-269] + _ = x[KindModuleBlock-270] + _ = x[KindCaseBlock-271] + _ = x[KindNamespaceExportDeclaration-272] + _ = x[KindImportEqualsDeclaration-273] + _ = x[KindImportDeclaration-274] + _ = x[KindImportClause-275] + _ = x[KindNamespaceImport-276] + _ = x[KindNamedImports-277] + _ = x[KindImportSpecifier-278] + _ = x[KindExportAssignment-279] + _ = x[KindExportDeclaration-280] + _ = x[KindNamedExports-281] + _ = x[KindNamespaceExport-282] + _ = x[KindExportSpecifier-283] + _ = x[KindMissingDeclaration-284] + _ = x[KindExternalModuleReference-285] + _ = x[KindJsxElement-286] + _ = x[KindJsxSelfClosingElement-287] + _ = x[KindJsxOpeningElement-288] + _ = x[KindJsxClosingElement-289] + _ = x[KindJsxFragment-290] + _ = x[KindJsxOpeningFragment-291] + _ = x[KindJsxClosingFragment-292] + _ = x[KindJsxAttribute-293] + _ = x[KindJsxAttributes-294] + _ = x[KindJsxSpreadAttribute-295] + _ = x[KindJsxExpression-296] + _ = x[KindJsxNamespacedName-297] + _ = x[KindCaseClause-298] + _ = x[KindDefaultClause-299] + _ = x[KindHeritageClause-300] + _ = x[KindCatchClause-301] + _ = x[KindImportAttributes-302] + _ = x[KindImportAttribute-303] + _ = x[KindPropertyAssignment-304] + _ = x[KindShorthandPropertyAssignment-305] + _ = x[KindSpreadAssignment-306] + _ = x[KindEnumMember-307] + _ = x[KindSourceFile-308] + _ = x[KindJSDocTypeExpression-309] + _ = x[KindJSDocNameReference-310] + _ = x[KindJSDocMemberName-311] + _ = x[KindJSDocAllType-312] + _ = x[KindJSDocNullableType-313] + _ = x[KindJSDocNonNullableType-314] + _ = x[KindJSDocOptionalType-315] + _ = x[KindJSDocVariadicType-316] + _ = x[KindJSDoc-317] + _ = x[KindJSDocText-318] + _ = x[KindJSDocTypeLiteral-319] + _ = x[KindJSDocSignature-320] + _ = x[KindJSDocLink-321] + _ = x[KindJSDocLinkCode-322] + _ = x[KindJSDocLinkPlain-323] + _ = x[KindJSDocTag-324] + _ = x[KindJSDocAugmentsTag-325] + _ = x[KindJSDocImplementsTag-326] + _ = x[KindJSDocDeprecatedTag-327] + _ = x[KindJSDocPublicTag-328] + _ = x[KindJSDocPrivateTag-329] + _ = x[KindJSDocProtectedTag-330] + _ = x[KindJSDocReadonlyTag-331] + _ = x[KindJSDocOverrideTag-332] + _ = x[KindJSDocCallbackTag-333] + _ = x[KindJSDocOverloadTag-334] + _ = x[KindJSDocParameterTag-335] + _ = x[KindJSDocReturnTag-336] + _ = x[KindJSDocThisTag-337] + _ = x[KindJSDocTypeTag-338] + _ = x[KindJSDocTemplateTag-339] + _ = x[KindJSDocTypedefTag-340] + _ = x[KindJSDocSeeTag-341] + _ = x[KindJSDocPropertyTag-342] + _ = x[KindJSDocSatisfiesTag-343] + _ = x[KindJSDocImportTag-344] + _ = x[KindSyntaxList-345] + _ = x[KindJSTypeAliasDeclaration-346] + _ = x[KindJSExportAssignment-347] + _ = x[KindCommonJSExport-348] + _ = x[KindJSImportDeclaration-349] + _ = x[KindNotEmittedStatement-350] + _ = x[KindPartiallyEmittedExpression-351] + _ = x[KindCommaListExpression-352] + _ = x[KindSyntheticReferenceExpression-353] + _ = x[KindNotEmittedTypeElement-354] + _ = x[KindCount-355] } -const _Kind_name = "KindUnknownKindEndOfFileKindSingleLineCommentTriviaKindMultiLineCommentTriviaKindNewLineTriviaKindWhitespaceTriviaKindConflictMarkerTriviaKindNonTextFileMarkerTriviaKindNumericLiteralKindBigIntLiteralKindStringLiteralKindJsxTextKindJsxTextAllWhiteSpacesKindRegularExpressionLiteralKindNoSubstitutionTemplateLiteralKindTemplateHeadKindTemplateMiddleKindTemplateTailKindOpenBraceTokenKindCloseBraceTokenKindOpenParenTokenKindCloseParenTokenKindOpenBracketTokenKindCloseBracketTokenKindDotTokenKindDotDotDotTokenKindSemicolonTokenKindCommaTokenKindQuestionDotTokenKindLessThanTokenKindLessThanSlashTokenKindGreaterThanTokenKindLessThanEqualsTokenKindGreaterThanEqualsTokenKindEqualsEqualsTokenKindExclamationEqualsTokenKindEqualsEqualsEqualsTokenKindExclamationEqualsEqualsTokenKindEqualsGreaterThanTokenKindPlusTokenKindMinusTokenKindAsteriskTokenKindAsteriskAsteriskTokenKindSlashTokenKindPercentTokenKindPlusPlusTokenKindMinusMinusTokenKindLessThanLessThanTokenKindGreaterThanGreaterThanTokenKindGreaterThanGreaterThanGreaterThanTokenKindAmpersandTokenKindBarTokenKindCaretTokenKindExclamationTokenKindTildeTokenKindAmpersandAmpersandTokenKindBarBarTokenKindQuestionTokenKindColonTokenKindAtTokenKindQuestionQuestionTokenKindBacktickTokenKindHashTokenKindEqualsTokenKindPlusEqualsTokenKindMinusEqualsTokenKindAsteriskEqualsTokenKindAsteriskAsteriskEqualsTokenKindSlashEqualsTokenKindPercentEqualsTokenKindLessThanLessThanEqualsTokenKindGreaterThanGreaterThanEqualsTokenKindGreaterThanGreaterThanGreaterThanEqualsTokenKindAmpersandEqualsTokenKindBarEqualsTokenKindBarBarEqualsTokenKindAmpersandAmpersandEqualsTokenKindQuestionQuestionEqualsTokenKindCaretEqualsTokenKindIdentifierKindPrivateIdentifierKindJSDocCommentTextTokenKindBreakKeywordKindCaseKeywordKindCatchKeywordKindClassKeywordKindConstKeywordKindContinueKeywordKindDebuggerKeywordKindDefaultKeywordKindDeleteKeywordKindDoKeywordKindElseKeywordKindEnumKeywordKindExportKeywordKindExtendsKeywordKindFalseKeywordKindFinallyKeywordKindForKeywordKindFunctionKeywordKindIfKeywordKindImportKeywordKindInKeywordKindInstanceOfKeywordKindNewKeywordKindNullKeywordKindReturnKeywordKindSuperKeywordKindSwitchKeywordKindThisKeywordKindThrowKeywordKindTrueKeywordKindTryKeywordKindTypeOfKeywordKindVarKeywordKindVoidKeywordKindWhileKeywordKindWithKeywordKindImplementsKeywordKindInterfaceKeywordKindLetKeywordKindPackageKeywordKindPrivateKeywordKindProtectedKeywordKindPublicKeywordKindStaticKeywordKindYieldKeywordKindAbstractKeywordKindAccessorKeywordKindAsKeywordKindAssertsKeywordKindAssertKeywordKindAnyKeywordKindAsyncKeywordKindAwaitKeywordKindBooleanKeywordKindConstructorKeywordKindDeclareKeywordKindGetKeywordKindImmediateKeywordKindInferKeywordKindIntrinsicKeywordKindIsKeywordKindKeyOfKeywordKindModuleKeywordKindNamespaceKeywordKindNeverKeywordKindOutKeywordKindReadonlyKeywordKindRequireKeywordKindNumberKeywordKindObjectKeywordKindSatisfiesKeywordKindSetKeywordKindStringKeywordKindSymbolKeywordKindTypeKeywordKindUndefinedKeywordKindUniqueKeywordKindUnknownKeywordKindUsingKeywordKindFromKeywordKindGlobalKeywordKindBigIntKeywordKindOverrideKeywordKindOfKeywordKindDeferKeywordKindQualifiedNameKindComputedPropertyNameKindTypeParameterKindParameterKindDecoratorKindPropertySignatureKindPropertyDeclarationKindMethodSignatureKindMethodDeclarationKindClassStaticBlockDeclarationKindConstructorKindGetAccessorKindSetAccessorKindCallSignatureKindConstructSignatureKindIndexSignatureKindTypePredicateKindTypeReferenceKindFunctionTypeKindConstructorTypeKindTypeQueryKindTypeLiteralKindArrayTypeKindTupleTypeKindOptionalTypeKindRestTypeKindUnionTypeKindIntersectionTypeKindConditionalTypeKindInferTypeKindParenthesizedTypeKindThisTypeKindTypeOperatorKindIndexedAccessTypeKindMappedTypeKindLiteralTypeKindNamedTupleMemberKindTemplateLiteralTypeKindTemplateLiteralTypeSpanKindImportTypeKindObjectBindingPatternKindArrayBindingPatternKindBindingElementKindArrayLiteralExpressionKindObjectLiteralExpressionKindPropertyAccessExpressionKindElementAccessExpressionKindCallExpressionKindNewExpressionKindTaggedTemplateExpressionKindTypeAssertionExpressionKindParenthesizedExpressionKindFunctionExpressionKindArrowFunctionKindDeleteExpressionKindTypeOfExpressionKindVoidExpressionKindAwaitExpressionKindPrefixUnaryExpressionKindPostfixUnaryExpressionKindBinaryExpressionKindConditionalExpressionKindTemplateExpressionKindYieldExpressionKindSpreadElementKindClassExpressionKindOmittedExpressionKindExpressionWithTypeArgumentsKindAsExpressionKindNonNullExpressionKindMetaPropertyKindSyntheticExpressionKindSatisfiesExpressionKindTemplateSpanKindSemicolonClassElementKindBlockKindEmptyStatementKindVariableStatementKindExpressionStatementKindIfStatementKindDoStatementKindWhileStatementKindForStatementKindForInStatementKindForOfStatementKindContinueStatementKindBreakStatementKindReturnStatementKindWithStatementKindSwitchStatementKindLabeledStatementKindThrowStatementKindTryStatementKindDebuggerStatementKindVariableDeclarationKindVariableDeclarationListKindFunctionDeclarationKindClassDeclarationKindInterfaceDeclarationKindTypeAliasDeclarationKindEnumDeclarationKindModuleDeclarationKindModuleBlockKindCaseBlockKindNamespaceExportDeclarationKindImportEqualsDeclarationKindImportDeclarationKindImportClauseKindNamespaceImportKindNamedImportsKindImportSpecifierKindExportAssignmentKindExportDeclarationKindNamedExportsKindNamespaceExportKindExportSpecifierKindMissingDeclarationKindExternalModuleReferenceKindJsxElementKindJsxSelfClosingElementKindJsxOpeningElementKindJsxClosingElementKindJsxFragmentKindJsxOpeningFragmentKindJsxClosingFragmentKindJsxAttributeKindJsxAttributesKindJsxSpreadAttributeKindJsxExpressionKindJsxNamespacedNameKindCaseClauseKindDefaultClauseKindHeritageClauseKindCatchClauseKindImportAttributesKindImportAttributeKindPropertyAssignmentKindShorthandPropertyAssignmentKindSpreadAssignmentKindEnumMemberKindSourceFileKindJSDocTypeExpressionKindJSDocNameReferenceKindJSDocMemberNameKindJSDocAllTypeKindJSDocNullableTypeKindJSDocNonNullableTypeKindJSDocOptionalTypeKindJSDocVariadicTypeKindJSDocKindJSDocTextKindJSDocTypeLiteralKindJSDocSignatureKindJSDocLinkKindJSDocLinkCodeKindJSDocLinkPlainKindJSDocTagKindJSDocAugmentsTagKindJSDocImplementsTagKindJSDocDeprecatedTagKindJSDocPublicTagKindJSDocPrivateTagKindJSDocProtectedTagKindJSDocReadonlyTagKindJSDocOverrideTagKindJSDocCallbackTagKindJSDocOverloadTagKindJSDocParameterTagKindJSDocReturnTagKindJSDocThisTagKindJSDocTypeTagKindJSDocTemplateTagKindJSDocTypedefTagKindJSDocSeeTagKindJSDocPropertyTagKindJSDocSatisfiesTagKindJSDocImportTagKindSyntaxListKindJSTypeAliasDeclarationKindJSExportAssignmentKindCommonJSExportKindJSImportDeclarationKindNotEmittedStatementKindPartiallyEmittedExpressionKindCommaListExpressionKindSyntheticReferenceExpressionKindNotEmittedTypeElementKindCount" +const _Kind_name = "KindUnknownKindEndOfFileKindSingleLineCommentTriviaKindMultiLineCommentTriviaKindNewLineTriviaKindWhitespaceTriviaKindConflictMarkerTriviaKindNonTextFileMarkerTriviaKindNumericLiteralKindBigIntLiteralKindStringLiteralKindJsxTextKindJsxTextAllWhiteSpacesKindRegularExpressionLiteralKindNoSubstitutionTemplateLiteralKindTemplateHeadKindTemplateMiddleKindTemplateTailKindOpenBraceTokenKindCloseBraceTokenKindOpenParenTokenKindCloseParenTokenKindOpenBracketTokenKindCloseBracketTokenKindDotTokenKindDotDotDotTokenKindSemicolonTokenKindCommaTokenKindQuestionDotTokenKindLessThanTokenKindLessThanSlashTokenKindGreaterThanTokenKindLessThanEqualsTokenKindGreaterThanEqualsTokenKindEqualsEqualsTokenKindExclamationEqualsTokenKindEqualsEqualsEqualsTokenKindExclamationEqualsEqualsTokenKindEqualsGreaterThanTokenKindPlusTokenKindMinusTokenKindAsteriskTokenKindAsteriskAsteriskTokenKindSlashTokenKindPercentTokenKindPlusPlusTokenKindMinusMinusTokenKindLessThanLessThanTokenKindGreaterThanGreaterThanTokenKindGreaterThanGreaterThanGreaterThanTokenKindAmpersandTokenKindBarTokenKindCaretTokenKindExclamationTokenKindTildeTokenKindAmpersandAmpersandTokenKindBarBarTokenKindQuestionTokenKindColonTokenKindAtTokenKindQuestionQuestionTokenKindBacktickTokenKindHashTokenKindEqualsTokenKindPlusEqualsTokenKindMinusEqualsTokenKindAsteriskEqualsTokenKindAsteriskAsteriskEqualsTokenKindSlashEqualsTokenKindPercentEqualsTokenKindLessThanLessThanEqualsTokenKindGreaterThanGreaterThanEqualsTokenKindGreaterThanGreaterThanGreaterThanEqualsTokenKindAmpersandEqualsTokenKindBarEqualsTokenKindBarBarEqualsTokenKindAmpersandAmpersandEqualsTokenKindQuestionQuestionEqualsTokenKindCaretEqualsTokenKindIdentifierKindPrivateIdentifierKindJSDocCommentTextTokenKindBreakKeywordKindCaseKeywordKindCatchKeywordKindClassKeywordKindConstKeywordKindContinueKeywordKindDebuggerKeywordKindDefaultKeywordKindDeleteKeywordKindDoKeywordKindElseKeywordKindEnumKeywordKindExportKeywordKindExtendsKeywordKindFalseKeywordKindFinallyKeywordKindForKeywordKindFunctionKeywordKindIfKeywordKindImportKeywordKindInKeywordKindInstanceOfKeywordKindNewKeywordKindNullKeywordKindReturnKeywordKindSuperKeywordKindSwitchKeywordKindThisKeywordKindThrowKeywordKindTrueKeywordKindTryKeywordKindTypeOfKeywordKindVarKeywordKindVoidKeywordKindWhileKeywordKindWithKeywordKindImplementsKeywordKindInterfaceKeywordKindLetKeywordKindPackageKeywordKindPrivateKeywordKindProtectedKeywordKindPublicKeywordKindStaticKeywordKindYieldKeywordKindAbstractKeywordKindAccessorKeywordKindAsKeywordKindAssertsKeywordKindAssertKeywordKindAnyKeywordKindAsyncKeywordKindAwaitKeywordKindBooleanKeywordKindConstructorKeywordKindDeclareKeywordKindGetKeywordKindImmediateKeywordKindInferKeywordKindIntrinsicKeywordKindIsKeywordKindKeyOfKeywordKindModuleKeywordKindNamespaceKeywordKindNeverKeywordKindOutKeywordKindReadonlyKeywordKindRequireKeywordKindNumberKeywordKindObjectKeywordKindSatisfiesKeywordKindSetKeywordKindStringKeywordKindSymbolKeywordKindTypeKeywordKindUndefinedKeywordKindUniqueKeywordKindUnknownKeywordKindUsingKeywordKindFromKeywordKindGlobalKeywordKindBigIntKeywordKindOverrideKeywordKindOfKeywordKindDeferKeywordKindQualifiedNameKindComputedPropertyNameKindTypeParameterKindParameterKindDecoratorKindPropertySignatureKindPropertyDeclarationKindMethodSignatureKindMethodDeclarationKindClassStaticBlockDeclarationKindConstructorKindGetAccessorKindSetAccessorKindCallSignatureKindConstructSignatureKindIndexSignatureKindTypePredicateKindTypeReferenceKindFunctionTypeKindConstructorTypeKindTypeQueryKindTypeLiteralKindArrayTypeKindTupleTypeKindOptionalTypeKindRestTypeKindUnionTypeKindIntersectionTypeKindConditionalTypeKindInferTypeKindParenthesizedTypeKindThisTypeKindTypeOperatorKindIndexedAccessTypeKindMappedTypeKindLiteralTypeKindNamedTupleMemberKindTemplateLiteralTypeKindTemplateLiteralTypeSpanKindQuantifiedTypeKindImportTypeKindObjectBindingPatternKindArrayBindingPatternKindBindingElementKindArrayLiteralExpressionKindObjectLiteralExpressionKindPropertyAccessExpressionKindElementAccessExpressionKindCallExpressionKindNewExpressionKindTaggedTemplateExpressionKindTypeAssertionExpressionKindParenthesizedExpressionKindFunctionExpressionKindArrowFunctionKindDeleteExpressionKindTypeOfExpressionKindVoidExpressionKindAwaitExpressionKindPrefixUnaryExpressionKindPostfixUnaryExpressionKindBinaryExpressionKindConditionalExpressionKindTemplateExpressionKindYieldExpressionKindSpreadElementKindClassExpressionKindOmittedExpressionKindExpressionWithTypeArgumentsKindAsExpressionKindNonNullExpressionKindMetaPropertyKindSyntheticExpressionKindSatisfiesExpressionKindTemplateSpanKindSemicolonClassElementKindBlockKindEmptyStatementKindVariableStatementKindExpressionStatementKindIfStatementKindDoStatementKindWhileStatementKindForStatementKindForInStatementKindForOfStatementKindContinueStatementKindBreakStatementKindReturnStatementKindWithStatementKindSwitchStatementKindLabeledStatementKindThrowStatementKindTryStatementKindDebuggerStatementKindVariableDeclarationKindVariableDeclarationListKindFunctionDeclarationKindClassDeclarationKindInterfaceDeclarationKindTypeAliasDeclarationKindEnumDeclarationKindModuleDeclarationKindModuleBlockKindCaseBlockKindNamespaceExportDeclarationKindImportEqualsDeclarationKindImportDeclarationKindImportClauseKindNamespaceImportKindNamedImportsKindImportSpecifierKindExportAssignmentKindExportDeclarationKindNamedExportsKindNamespaceExportKindExportSpecifierKindMissingDeclarationKindExternalModuleReferenceKindJsxElementKindJsxSelfClosingElementKindJsxOpeningElementKindJsxClosingElementKindJsxFragmentKindJsxOpeningFragmentKindJsxClosingFragmentKindJsxAttributeKindJsxAttributesKindJsxSpreadAttributeKindJsxExpressionKindJsxNamespacedNameKindCaseClauseKindDefaultClauseKindHeritageClauseKindCatchClauseKindImportAttributesKindImportAttributeKindPropertyAssignmentKindShorthandPropertyAssignmentKindSpreadAssignmentKindEnumMemberKindSourceFileKindJSDocTypeExpressionKindJSDocNameReferenceKindJSDocMemberNameKindJSDocAllTypeKindJSDocNullableTypeKindJSDocNonNullableTypeKindJSDocOptionalTypeKindJSDocVariadicTypeKindJSDocKindJSDocTextKindJSDocTypeLiteralKindJSDocSignatureKindJSDocLinkKindJSDocLinkCodeKindJSDocLinkPlainKindJSDocTagKindJSDocAugmentsTagKindJSDocImplementsTagKindJSDocDeprecatedTagKindJSDocPublicTagKindJSDocPrivateTagKindJSDocProtectedTagKindJSDocReadonlyTagKindJSDocOverrideTagKindJSDocCallbackTagKindJSDocOverloadTagKindJSDocParameterTagKindJSDocReturnTagKindJSDocThisTagKindJSDocTypeTagKindJSDocTemplateTagKindJSDocTypedefTagKindJSDocSeeTagKindJSDocPropertyTagKindJSDocSatisfiesTagKindJSDocImportTagKindSyntaxListKindJSTypeAliasDeclarationKindJSExportAssignmentKindCommonJSExportKindJSImportDeclarationKindNotEmittedStatementKindPartiallyEmittedExpressionKindCommaListExpressionKindSyntheticReferenceExpressionKindNotEmittedTypeElementKindCount" -var _Kind_index = [...]uint16{0, 11, 24, 51, 77, 94, 114, 138, 165, 183, 200, 217, 228, 253, 281, 314, 330, 348, 364, 382, 401, 419, 438, 458, 479, 491, 509, 527, 541, 561, 578, 600, 620, 643, 669, 690, 716, 743, 775, 801, 814, 828, 845, 870, 884, 900, 917, 936, 961, 992, 1034, 1052, 1064, 1078, 1098, 1112, 1139, 1154, 1171, 1185, 1196, 1221, 1238, 1251, 1266, 1285, 1305, 1328, 1359, 1379, 1401, 1432, 1469, 1517, 1541, 1559, 1580, 1613, 1644, 1664, 1678, 1699, 1724, 1740, 1755, 1771, 1787, 1803, 1822, 1841, 1859, 1876, 1889, 1904, 1919, 1936, 1954, 1970, 1988, 2002, 2021, 2034, 2051, 2064, 2085, 2099, 2114, 2131, 2147, 2164, 2179, 2195, 2210, 2224, 2241, 2255, 2270, 2286, 2301, 2322, 2342, 2356, 2374, 2392, 2412, 2429, 2446, 2462, 2481, 2500, 2513, 2531, 2548, 2562, 2578, 2594, 2612, 2634, 2652, 2666, 2686, 2702, 2722, 2735, 2751, 2768, 2788, 2804, 2818, 2837, 2855, 2872, 2889, 2909, 2923, 2940, 2957, 2972, 2992, 3009, 3027, 3043, 3058, 3075, 3092, 3111, 3124, 3140, 3157, 3181, 3198, 3211, 3224, 3245, 3268, 3287, 3308, 3339, 3354, 3369, 3384, 3401, 3423, 3441, 3458, 3475, 3491, 3510, 3523, 3538, 3551, 3564, 3580, 3592, 3605, 3625, 3644, 3657, 3678, 3690, 3706, 3727, 3741, 3756, 3776, 3799, 3826, 3840, 3864, 3887, 3905, 3931, 3958, 3986, 4013, 4031, 4048, 4076, 4103, 4130, 4152, 4169, 4189, 4209, 4227, 4246, 4271, 4297, 4317, 4342, 4364, 4383, 4400, 4419, 4440, 4471, 4487, 4508, 4524, 4547, 4570, 4586, 4611, 4620, 4638, 4659, 4682, 4697, 4712, 4730, 4746, 4764, 4782, 4803, 4821, 4840, 4857, 4876, 4896, 4914, 4930, 4951, 4974, 5001, 5024, 5044, 5068, 5092, 5111, 5132, 5147, 5160, 5190, 5217, 5238, 5254, 5273, 5289, 5308, 5328, 5349, 5365, 5384, 5403, 5425, 5452, 5466, 5491, 5512, 5533, 5548, 5570, 5592, 5608, 5625, 5647, 5664, 5685, 5699, 5716, 5734, 5749, 5769, 5788, 5810, 5841, 5861, 5875, 5889, 5912, 5934, 5953, 5969, 5990, 6014, 6035, 6056, 6065, 6078, 6098, 6116, 6129, 6146, 6164, 6176, 6196, 6218, 6240, 6258, 6277, 6298, 6318, 6338, 6358, 6378, 6399, 6417, 6433, 6449, 6469, 6488, 6503, 6523, 6544, 6562, 6576, 6602, 6624, 6642, 6665, 6688, 6718, 6741, 6773, 6798, 6807} +var _Kind_index = [...]uint16{0, 11, 24, 51, 77, 94, 114, 138, 165, 183, 200, 217, 228, 253, 281, 314, 330, 348, 364, 382, 401, 419, 438, 458, 479, 491, 509, 527, 541, 561, 578, 600, 620, 643, 669, 690, 716, 743, 775, 801, 814, 828, 845, 870, 884, 900, 917, 936, 961, 992, 1034, 1052, 1064, 1078, 1098, 1112, 1139, 1154, 1171, 1185, 1196, 1221, 1238, 1251, 1266, 1285, 1305, 1328, 1359, 1379, 1401, 1432, 1469, 1517, 1541, 1559, 1580, 1613, 1644, 1664, 1678, 1699, 1724, 1740, 1755, 1771, 1787, 1803, 1822, 1841, 1859, 1876, 1889, 1904, 1919, 1936, 1954, 1970, 1988, 2002, 2021, 2034, 2051, 2064, 2085, 2099, 2114, 2131, 2147, 2164, 2179, 2195, 2210, 2224, 2241, 2255, 2270, 2286, 2301, 2322, 2342, 2356, 2374, 2392, 2412, 2429, 2446, 2462, 2481, 2500, 2513, 2531, 2548, 2562, 2578, 2594, 2612, 2634, 2652, 2666, 2686, 2702, 2722, 2735, 2751, 2768, 2788, 2804, 2818, 2837, 2855, 2872, 2889, 2909, 2923, 2940, 2957, 2972, 2992, 3009, 3027, 3043, 3058, 3075, 3092, 3111, 3124, 3140, 3157, 3181, 3198, 3211, 3224, 3245, 3268, 3287, 3308, 3339, 3354, 3369, 3384, 3401, 3423, 3441, 3458, 3475, 3491, 3510, 3523, 3538, 3551, 3564, 3580, 3592, 3605, 3625, 3644, 3657, 3678, 3690, 3706, 3727, 3741, 3756, 3776, 3799, 3826, 3844, 3858, 3882, 3905, 3923, 3949, 3976, 4004, 4031, 4049, 4066, 4094, 4121, 4148, 4170, 4187, 4207, 4227, 4245, 4264, 4289, 4315, 4335, 4360, 4382, 4401, 4418, 4437, 4458, 4489, 4505, 4526, 4542, 4565, 4588, 4604, 4629, 4638, 4656, 4677, 4700, 4715, 4730, 4748, 4764, 4782, 4800, 4821, 4839, 4858, 4875, 4894, 4914, 4932, 4948, 4969, 4992, 5019, 5042, 5062, 5086, 5110, 5129, 5150, 5165, 5178, 5208, 5235, 5256, 5272, 5291, 5307, 5326, 5346, 5367, 5383, 5402, 5421, 5443, 5470, 5484, 5509, 5530, 5551, 5566, 5588, 5610, 5626, 5643, 5665, 5682, 5703, 5717, 5734, 5752, 5767, 5787, 5806, 5828, 5859, 5879, 5893, 5907, 5930, 5952, 5971, 5987, 6008, 6032, 6053, 6074, 6083, 6096, 6116, 6134, 6147, 6164, 6182, 6194, 6214, 6236, 6258, 6276, 6295, 6316, 6336, 6356, 6376, 6396, 6417, 6435, 6451, 6467, 6487, 6506, 6521, 6541, 6562, 6580, 6594, 6620, 6642, 6660, 6683, 6706, 6736, 6759, 6791, 6816, 6825} func (i Kind) String() string { idx := int(i) - 0 diff --git a/internal/ast/precedence.go b/internal/ast/precedence.go index 9acf84a78f4..b3113f62ef2 100644 --- a/internal/ast/precedence.go +++ b/internal/ast/precedence.go @@ -655,7 +655,8 @@ const ( // Gets the precedence of a TypeNode func GetTypeNodePrecedence(n *TypeNode) TypePrecedence { switch n.Kind { - case KindConditionalType: + case KindConditionalType, + KindQuantifiedType: return TypePrecedenceConditional case KindJSDocOptionalType, KindJSDocVariadicType: return TypePrecedenceJSDoc diff --git a/internal/binder/binder.go b/internal/binder/binder.go index f7339d98702..341beb946b7 100644 --- a/internal/binder/binder.go +++ b/internal/binder/binder.go @@ -447,7 +447,8 @@ func (b *Binder) declareSymbolAndAddToSymbolTable(node *ast.Node, symbolFlags as case ast.KindFunctionType, ast.KindConstructorType, ast.KindCallSignature, ast.KindConstructSignature, ast.KindIndexSignature, ast.KindMethodDeclaration, ast.KindMethodSignature, ast.KindConstructor, ast.KindGetAccessor, ast.KindSetAccessor, ast.KindFunctionDeclaration, ast.KindFunctionExpression, ast.KindArrowFunction, - ast.KindClassStaticBlockDeclaration, ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration, ast.KindMappedType: + ast.KindClassStaticBlockDeclaration, ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration, ast.KindMappedType, + ast.KindQuantifiedType: return b.declareSymbol(ast.GetLocals(b.container), nil /*parent*/, node, symbolFlags, symbolExcludes) } panic("Unhandled case in declareSymbolAndAddToSymbolTable") @@ -2467,7 +2468,7 @@ func GetContainerFlags(node *ast.Node) ContainerFlags { return ContainerFlagsIsContainer case ast.KindInterfaceDeclaration: return ContainerFlagsIsContainer | ContainerFlagsIsInterface - case ast.KindModuleDeclaration, ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration, ast.KindMappedType, ast.KindIndexSignature: + case ast.KindModuleDeclaration, ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration, ast.KindMappedType, ast.KindIndexSignature, ast.KindQuantifiedType: return ContainerFlagsIsContainer | ContainerFlagsHasLocals case ast.KindSourceFile: return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals diff --git a/internal/checker/checker.go b/internal/checker/checker.go index f2a212a0609..df49fca0ee6 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -614,6 +614,7 @@ type Checker struct { reverseMappedCache map[ReverseMappedTypeKey]*Type reverseHomomorphicMappedCache map[ReverseMappedTypeKey]*Type iterationTypesCache map[IterationTypesKey]IterationTypes + contextualTypeStack map[*ast.Node]bool markerTypes collections.Set[*Type] undefinedSymbol *ast.Symbol argumentsSymbol *ast.Symbol @@ -915,6 +916,7 @@ func NewChecker(program Program) (*Checker, *sync.Mutex) { c.reverseMappedCache = make(map[ReverseMappedTypeKey]*Type) c.reverseHomomorphicMappedCache = make(map[ReverseMappedTypeKey]*Type) c.iterationTypesCache = make(map[IterationTypesKey]IterationTypes) + c.contextualTypeStack = make(map[*ast.Node]bool) c.undefinedSymbol = c.newSymbol(ast.SymbolFlagsProperty, "undefined") c.argumentsSymbol = c.newSymbol(ast.SymbolFlagsProperty, "arguments") c.requireSymbol = c.newSymbol(ast.SymbolFlagsProperty, "require") @@ -7246,6 +7248,22 @@ func (c *Checker) reportObjectPossiblyNullOrUndefinedError(node *ast.Node, facts } func (c *Checker) checkExpressionWithContextualType(node *ast.Node, contextualType *Type, inferenceContext *InferenceContext, checkMode CheckMode) *Type { + if contextualType.flags&TypeFlagsQuantified == 0 { + return c.checkExpressionWithContextualTypeWorker(node, contextualType, inferenceContext, checkMode) + } + t0 := c.checkExpressionWithContextualTypeWorker(node, contextualType.AsQuantifiedType().baseType, nil, checkMode|CheckModeSkipContextSensitive|CheckModeSkipGenericFunctions) + ctx := c.newInferenceContext( + core.Map(contextualType.AsQuantifiedType().typeParameters, func(t *TypeParameter) *Type { return t.AsType() }), + nil, + InferenceFlagsNone, + nil, + ) + c.inferTypes(ctx.inferences, t0, contextualType.AsQuantifiedType().baseType, InferencePriorityNoConstraints|InferencePriorityAlwaysStrict, false) + newContextualType := c.instantiateType(contextualType.AsQuantifiedType().baseType, ctx.mapper) + return c.checkExpressionWithContextualTypeWorker(node, newContextualType, inferenceContext, checkMode) +} + +func (c *Checker) checkExpressionWithContextualTypeWorker(node *ast.Node, contextualType *Type, inferenceContext *InferenceContext, checkMode CheckMode) *Type { contextNode := c.getContextNode(node) c.pushContextualType(contextNode, contextualType, false /*isCache*/) c.pushInferenceContext(contextNode, inferenceContext) @@ -7322,8 +7340,30 @@ func (c *Checker) checkExpressionEx(node *ast.Node, checkMode CheckMode) *Type { saveCurrentNode := c.currentNode c.currentNode = node c.instantiationCount = 0 - uninstantiatedType := c.checkExpressionWorker(node, checkMode) - t := c.instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode) + var t *Type + var contextualType *Type + if !c.contextualTypeStack[node] { + // quickfix to avoid recursion TODO: come up with something better + c.contextualTypeStack[node] = true + contextualType = c.getContextualType(node, ContextFlagsNone) + delete(c.contextualTypeStack, node) + } + isAlreadyContextuallyChecking := core.Some(c.contextualInfos, func(info ContextualInfo) bool { return info.node == node }) + if contextualType != nil && contextualType.flags&TypeFlagsQuantified != 0 && !isAlreadyContextuallyChecking { + t0 := c.checkExpressionWithContextualType(node, contextualType.AsQuantifiedType().baseType, nil, checkMode|CheckModeSkipContextSensitive|CheckModeSkipGenericFunctions) + ctx := c.newInferenceContext( + core.Map(contextualType.AsQuantifiedType().typeParameters, func(t *TypeParameter) *Type { return t.AsType() }), + nil, + InferenceFlagsNone, + nil, + ) + c.inferTypes(ctx.inferences, t0, contextualType.AsQuantifiedType().baseType, InferencePriorityNoConstraints|InferencePriorityAlwaysStrict, false) + newContextualType := c.instantiateType(contextualType.AsQuantifiedType().baseType, ctx.mapper) + t = c.checkExpressionWithContextualType(node, newContextualType, nil, checkMode) + } else { + uninstantiatedType := c.checkExpressionWorker(node, checkMode) + t = c.instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode) + } if isConstEnumObjectType(t) { c.checkConstEnumAccess(node, t) } @@ -16821,7 +16861,7 @@ func (c *Checker) getDeclaredTypeOfClassOrInterface(symbol *ast.Symbol) *Type { t := c.newObjectType(kind, symbol) links.declaredType = t outerTypeParameters := c.getOuterTypeParametersOfClassOrInterface(symbol) - typeParameters := c.appendLocalTypeParametersOfClassOrInterfaceOrTypeAlias(outerTypeParameters, symbol) + typeParameters := c.appendLocalTypeParametersOfClassOrInterfaceOrTypeAliasOrQuantifiedType(outerTypeParameters, symbol) // A class or interface is generic if it has type parameters or a "this" type. We always give classes a "this" type // because it is not feasible to analyze all members to determine if the "this" type escapes the class (in particular, // property types inferred from initializers and method return types inferred from return statements are very hard @@ -20877,7 +20917,7 @@ func (c *Checker) createUnionOrIntersectionProperty(containingType *Type, name s // If we merged instantiations of a generic type, we replicate the symbol parent resetting behavior we used // to do when we recorded multiple distinct symbols so that we still get, eg, `Array.length` printed // back and not `Array.length` when we're looking at a `.length` access on a `string[] | number[]` - mergedInstantiations = singleProp.Parent != nil && len(c.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(singleProp.Parent)) != 0 + mergedInstantiations = singleProp.Parent != nil && len(c.getLocalTypeParametersOfClassOrInterfaceOrTypeAliasOrQuantifiedType(singleProp.Parent)) != 0 } else { if propSet.Size() == 0 { propSet.Add(singleProp) @@ -21606,6 +21646,17 @@ func (c *Checker) instantiateTypeWorker(t *Type, m *TypeMapper, alias *TypeAlias switch { case flags&TypeFlagsTypeParameter != 0: return m.Map(t) + case flags&TypeFlagsQuantified != 0: + return c.newQuantifiedType( + t.AsQuantifiedType().typeParameters, + // TODO: the following does not work figure out a way to do it + /*core.Map(t.AsQuantifiedType().typeParameters, func(tp *TypeParameter) *TypeParameter { + newTp := c.cloneTypeParameter(tp.AsType()) + newTp.AsTypeParameter().constraint = c.instantiateType(newTp.AsTypeParameter().constraint, m) + return newTp.AsTypeParameter() + }),*/ + c.instantiateType(t.AsQuantifiedType().baseType, m), + ) case flags&TypeFlagsObject != 0: objectFlags := t.objectFlags if objectFlags&(ObjectFlagsReference|ObjectFlagsAnonymous|ObjectFlagsMapped) != 0 { @@ -22277,6 +22328,8 @@ func (c *Checker) getTypeFromTypeNodeWorker(node *ast.Node) *Type { return c.getTypeFromInferTypeNode(node) case ast.KindImportType: return c.getTypeFromImportTypeNode(node) + case ast.KindQuantifiedType: + return c.getTypeFromQuantifiedTypeNode(node) default: return c.errorType } @@ -23043,7 +23096,7 @@ func (c *Checker) getAliasSymbolForTypeNode(node *ast.Node) *ast.Symbol { func (c *Checker) getTypeArgumentsForAliasSymbol(symbol *ast.Symbol) []*Type { if symbol != nil { - return c.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol) + return c.getLocalTypeParametersOfClassOrInterfaceOrTypeAliasOrQuantifiedType(symbol) } return nil } @@ -23078,7 +23131,7 @@ func (c *Checker) getOuterTypeParameters(node *ast.Node, includeThisTypes bool) case ast.KindClassDeclaration, ast.KindClassExpression, ast.KindInterfaceDeclaration, ast.KindCallSignature, ast.KindConstructSignature, ast.KindMethodSignature, ast.KindFunctionType, ast.KindConstructorType, ast.KindFunctionDeclaration, ast.KindMethodDeclaration, ast.KindFunctionExpression, ast.KindArrowFunction, ast.KindTypeAliasDeclaration, ast.KindJSTypeAliasDeclaration, ast.KindMappedType, - ast.KindConditionalType: + ast.KindConditionalType, ast.KindQuantifiedType: outerTypeParameters := c.getOuterTypeParameters(node, includeThisTypes) if (kind == ast.KindFunctionExpression || kind == ast.KindArrowFunction || ast.IsObjectLiteralMethod(node)) && c.isContextSensitive(node) { signature := core.FirstOrNil(c.getSignaturesOfType(c.getTypeOfSymbol(c.getSymbolOfDeclaration(node)), SignatureKindCall)) @@ -23116,14 +23169,14 @@ func (c *Checker) getInferTypeParameters(node *ast.Node) []*Type { } // The local type parameters are the combined set of type parameters from all declarations of the class, -// interface, or type alias. -func (c *Checker) getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol *ast.Symbol) []*Type { - return c.appendLocalTypeParametersOfClassOrInterfaceOrTypeAlias(nil, symbol) +// interface, type alias or quantified type +func (c *Checker) getLocalTypeParametersOfClassOrInterfaceOrTypeAliasOrQuantifiedType(symbol *ast.Symbol) []*Type { + return c.appendLocalTypeParametersOfClassOrInterfaceOrTypeAliasOrQuantifiedType(nil, symbol) } -func (c *Checker) appendLocalTypeParametersOfClassOrInterfaceOrTypeAlias(types []*Type, symbol *ast.Symbol) []*Type { +func (c *Checker) appendLocalTypeParametersOfClassOrInterfaceOrTypeAliasOrQuantifiedType(types []*Type, symbol *ast.Symbol) []*Type { for _, node := range symbol.Declarations { - if ast.NodeKindIs(node, ast.KindInterfaceDeclaration, ast.KindClassDeclaration, ast.KindClassExpression) || isTypeAlias(node) { + if ast.NodeKindIs(node, ast.KindInterfaceDeclaration, ast.KindClassDeclaration, ast.KindClassExpression, ast.KindQuantifiedType) || isTypeAlias(node) { types = c.appendTypeParameters(types, node.TypeParameters()) } } @@ -23160,7 +23213,7 @@ func (c *Checker) getDeclaredTypeOfTypeAlias(symbol *ast.Symbol) *Type { typeNode := declaration.Type() t := c.getTypeFromTypeNode(typeNode) if c.popTypeResolution() { - typeParameters := c.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol) + typeParameters := c.getLocalTypeParametersOfClassOrInterfaceOrTypeAliasOrQuantifiedType(symbol) if len(typeParameters) != 0 { // Initialize the instantiation cache for generic type aliases. The declared type corresponds to // an instantiation of the type alias with the type parameters supplied as type arguments. @@ -23954,6 +24007,19 @@ func (c *Checker) getTypeFromImportTypeNode(node *ast.Node) *Type { return links.resolvedType } +func (c *Checker) getTypeFromQuantifiedTypeNode(node *ast.Node) *Type { + links := c.typeNodeLinks.Get(node) + if links.resolvedType == nil { + links.resolvedType = c.newQuantifiedType( + core.Map(node.AsQuantifiedTypeNode().TypeParameters.Nodes, func(typeParameterNode *ast.Node) *TypeParameter { + return c.getDeclaredTypeOfTypeParameter(typeParameterNode.Symbol()).AsTypeParameter() + }), + c.getTypeFromTypeNode(node.AsQuantifiedTypeNode().BaseType), + ) + } + return links.resolvedType +} + func (c *Checker) getIdentifierChain(node *ast.Node) []*ast.Node { if ast.IsIdentifier(node) { return []*ast.Node{node} @@ -24545,6 +24611,13 @@ func (c *Checker) newSubstitutionType(baseType *Type, constraint *Type) *Type { return c.newType(TypeFlagsSubstitution, ObjectFlagsNone, data) } +func (c *Checker) newQuantifiedType(typeParamters []*TypeParameter, baseType *Type) *Type { + data := &QuantifiedType{} + data.typeParameters = typeParamters + data.baseType = baseType + return c.newType(TypeFlagsQuantified, ObjectFlagsNone, data) +} + func (c *Checker) newSignature(flags SignatureFlags, declaration *ast.Node, typeParameters []*Type, thisParameter *ast.Symbol, parameters []*ast.Symbol, resolvedReturnType *Type, resolvedTypePredicate *TypePredicate, minArgumentCount int) *Signature { sig := c.signaturePool.New() sig.flags = flags @@ -26681,6 +26754,11 @@ func (c *Checker) getBaseConstraintOrType(t *Type) *Type { } func (c *Checker) getBaseConstraintOfType(t *Type) *Type { + if t.flags&TypeFlagsQuantified != 0 { + return c.getBaseConstraintOfType( + t.AsQuantifiedType().baseType, + ) + } if t.flags&(TypeFlagsInstantiableNonPrimitive|TypeFlagsUnionOrIntersection|TypeFlagsTemplateLiteral|TypeFlagsStringMapping) != 0 || c.isGenericTupleType(t) { constraint := c.getResolvedBaseConstraint(t, nil) if constraint != c.noConstraintType && constraint != c.circularConstraintType { diff --git a/internal/checker/exports.go b/internal/checker/exports.go index 332a72569e7..4cbbc1f6edd 100644 --- a/internal/checker/exports.go +++ b/internal/checker/exports.go @@ -135,7 +135,7 @@ func (c *Checker) HasEffectiveRestParameter(signature *Signature) bool { } func (c *Checker) GetLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol *ast.Symbol) []*Type { - return c.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol) + return c.getLocalTypeParametersOfClassOrInterfaceOrTypeAliasOrQuantifiedType(symbol) } func (c *Checker) GetContextualTypeForObjectLiteralElement(element *ast.Node, contextFlags ContextFlags) *Type { diff --git a/internal/checker/jsx.go b/internal/checker/jsx.go index 9bf61948b98..f6f18c85bda 100644 --- a/internal/checker/jsx.go +++ b/internal/checker/jsx.go @@ -968,7 +968,7 @@ func (c *Checker) getJsxPropsTypeFromClassType(sig *Signature, context *ast.Node apparentAttributesType := attributesType intrinsicClassAttribs := c.getJsxType(JsxNames.IntrinsicClassAttributes, context) if !c.isErrorType(intrinsicClassAttribs) { - typeParams := c.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(intrinsicClassAttribs.symbol) + typeParams := c.getLocalTypeParametersOfClassOrInterfaceOrTypeAliasOrQuantifiedType(intrinsicClassAttribs.symbol) hostClassType := c.getReturnTypeOfSignature(sig) var libraryManagedAttributeType *Type if typeParams != nil { diff --git a/internal/checker/nodebuilderimpl.go b/internal/checker/nodebuilderimpl.go index 1fb4c357942..8d0bdc1fa9e 100644 --- a/internal/checker/nodebuilderimpl.go +++ b/internal/checker/nodebuilderimpl.go @@ -897,7 +897,7 @@ func (b *NodeBuilderImpl) getNameOfSymbolAsWritten(symbol *ast.Symbol) string { func (b *NodeBuilderImpl) getTypeParametersOfClassOrInterface(symbol *ast.Symbol) []*Type { result := make([]*Type, 0) result = append(result, b.ch.getOuterTypeParametersOfClassOrInterface(symbol)...) - result = append(result, b.ch.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol)...) + result = append(result, b.ch.getLocalTypeParametersOfClassOrInterfaceOrTypeAliasOrQuantifiedType(symbol)...) return result } @@ -1518,7 +1518,7 @@ func (b *NodeBuilderImpl) typeParametersToTypeParameterDeclarations(symbol *ast. targetSymbol := b.ch.getTargetSymbol(symbol) if targetSymbol.Flags&(ast.SymbolFlagsClass|ast.SymbolFlagsInterface|ast.SymbolFlagsAlias) != 0 { var results []*ast.Node - params := b.ch.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol) + params := b.ch.getLocalTypeParametersOfClassOrInterfaceOrTypeAliasOrQuantifiedType(symbol) for _, param := range params { results = append(results, b.typeParameterToDeclaration(param)) } @@ -3091,6 +3091,16 @@ func (b *NodeBuilderImpl) typeToTypeNode(t *Type) *ast.TypeNode { return typeNode } } + if t.flags&TypeFlagsQuantified != 0 { + return b.f.NewQuantifiedTypeNode( + b.f.NewNodeList( + core.Map(t.AsQuantifiedType().typeParameters, func(typeParamter *TypeParameter) *ast.Node { + return b.typeParameterToDeclaration(typeParamter.AsType()) + }), + ), + b.typeToTypeNode(t.AsQuantifiedType().baseType), + ) + } panic("Should be unreachable.") } diff --git a/internal/checker/relater.go b/internal/checker/relater.go index bf65552c7f3..28d74c049ce 100644 --- a/internal/checker/relater.go +++ b/internal/checker/relater.go @@ -168,6 +168,19 @@ func (c *Checker) areTypesComparable(type1 *Type, type2 *Type) bool { } func (c *Checker) isTypeRelatedTo(source *Type, target *Type, relation *Relation) bool { + if target.flags&TypeFlagsQuantified != 0 { + if source.flags&TypeFlagsQuantified != 0 { + return source == target + } + ctx := c.newInferenceContext( + core.Map(target.AsQuantifiedType().typeParameters, func(t *TypeParameter) *Type { return t.AsType() }), + nil, + InferenceFlagsNone, + nil, + ) + c.inferTypes(ctx.inferences, source, target.AsQuantifiedType().baseType, InferencePriorityNoConstraints|InferencePriorityAlwaysStrict, false) + return c.isTypeRelatedTo(source, c.instantiateType(target.AsQuantifiedType().baseType, ctx.mapper), relation) + } if isFreshLiteralType(source) { source = source.AsLiteralType().regularType } @@ -2553,6 +2566,20 @@ func (r *Relater) isRelatedTo(source *Type, target *Type, recursionFlags Recursi } func (r *Relater) isRelatedToEx(originalSource *Type, originalTarget *Type, recursionFlags RecursionFlags, reportErrors bool, headMessage *diagnostics.Message, intersectionState IntersectionState) Ternary { + if originalTarget.flags&TypeFlagsQuantified != 0 { + if originalSource.flags&TypeFlagsQuantified != 0 && originalSource == originalTarget { + return TernaryTrue + } + ctx := r.c.newInferenceContext( + core.Map(originalTarget.AsQuantifiedType().typeParameters, func(t *TypeParameter) *Type { return t.AsType() }), + nil, + InferenceFlagsNone, + nil, + ) + r.c.inferTypes(ctx.inferences, originalSource, originalTarget.AsQuantifiedType().baseType, InferencePriorityNoConstraints|InferencePriorityAlwaysStrict, false) + return r.isRelatedToEx(originalSource, r.c.instantiateType(originalTarget.AsQuantifiedType().baseType, ctx.mapper), recursionFlags, reportErrors, headMessage, intersectionState) + } + if originalSource == originalTarget { return TernaryTrue } diff --git a/internal/checker/types.go b/internal/checker/types.go index 3e2aafbd4c3..b872bd7b510 100644 --- a/internal/checker/types.go +++ b/internal/checker/types.go @@ -379,7 +379,7 @@ type SignatureLinks struct { decoratorSignature *Signature // Signature for decorator as if invoked by the runtime } -type TypeFlags uint32 +type TypeFlags uint64 // Note that for types of different kinds, the numeric values of TypeFlags determine the order // computed by the CompareTypes function and therefore the order of constituent types in union types. @@ -421,6 +421,7 @@ const ( TypeFlagsReserved1 TypeFlags = 1 << 29 // Used by union/intersection type construction TypeFlagsReserved2 TypeFlags = 1 << 30 // Used by union/intersection type construction TypeFlagsReserved3 TypeFlags = 1 << 31 + TypeFlagsQuantified TypeFlags = 1 << 32 TypeFlagsAnyOrUnknown = TypeFlagsAny | TypeFlagsUnknown TypeFlagsNullable = TypeFlagsUndefined | TypeFlagsNull @@ -445,7 +446,7 @@ const ( TypeFlagsUnionOrIntersection = TypeFlagsUnion | TypeFlagsIntersection TypeFlagsStructuredType = TypeFlagsObject | TypeFlagsUnion | TypeFlagsIntersection TypeFlagsTypeVariable = TypeFlagsTypeParameter | TypeFlagsIndexedAccess - TypeFlagsInstantiableNonPrimitive = TypeFlagsTypeVariable | TypeFlagsConditional | TypeFlagsSubstitution + TypeFlagsInstantiableNonPrimitive = TypeFlagsTypeVariable | TypeFlagsConditional | TypeFlagsSubstitution | TypeFlagsQuantified TypeFlagsInstantiablePrimitive = TypeFlagsIndex | TypeFlagsTemplateLiteral | TypeFlagsStringMapping TypeFlagsInstantiable = TypeFlagsInstantiableNonPrimitive | TypeFlagsInstantiablePrimitive TypeFlagsStructuredOrInstantiable = TypeFlagsStructuredType | TypeFlagsInstantiable @@ -594,6 +595,7 @@ func (t *Type) AsTemplateLiteralType() *TemplateLiteralType { return t.data.(*Te func (t *Type) AsStringMappingType() *StringMappingType { return t.data.(*StringMappingType) } func (t *Type) AsSubstitutionType() *SubstitutionType { return t.data.(*SubstitutionType) } func (t *Type) AsConditionalType() *ConditionalType { return t.data.(*ConditionalType) } +func (t *Type) AsQuantifiedType() *QuantifiedType { return t.data.(*QuantifiedType) } // Casts for embedded struct types @@ -1100,6 +1102,12 @@ type ConditionalType struct { combinedMapper *TypeMapper } +type QuantifiedType struct { + ConstrainedType + typeParameters []*TypeParameter + baseType *Type +} + // SignatureFlags type SignatureFlags uint32 diff --git a/internal/parser/parser.go b/internal/parser/parser.go index 00436c0a1b0..8b982b40b7d 100644 --- a/internal/parser/parser.go +++ b/internal/parser/parser.go @@ -2480,6 +2480,21 @@ func (p *Parser) parseType() *ast.TypeNode { saveContextFlags := p.contextFlags p.setContextFlags(ast.NodeFlagsTypeExcludesFlags, false) var typeNode *ast.TypeNode + if p.token == ast.KindLessThanToken { + state := p.mark() + p.parseFunctionOrConstructorType() + couldParseFunctionType := len(p.diagnostics) == state.diagnosticsLen + // TODO: see if there's a more standard way to do "try" parse + p.rewind(state) + if !couldParseFunctionType { + pos := p.nodePos() + typeParameters := p.parseTypeParameters() + baseType := p.parseType() + typeNode = p.finishNode(p.factory.NewQuantifiedTypeNode(typeParameters, baseType), pos) + p.contextFlags = saveContextFlags + return typeNode + } + } if p.isStartOfFunctionTypeOrConstructorType() { typeNode = p.parseFunctionOrConstructorType() } else { diff --git a/internal/printer/printer.go b/internal/printer/printer.go index fec95a7ab13..8b37ec0d9b5 100644 --- a/internal/printer/printer.go +++ b/internal/printer/printer.go @@ -2182,6 +2182,14 @@ func (p *Printer) emitImportTypeNode(node *ast.ImportTypeNode) { p.exitNode(node.AsNode(), state) } +func (p *Printer) emitQuantifiedTypeNpde(node *ast.QuantifiedTypeNode) { + state := p.enterNode(node.AsNode()) + p.emitTypeParameters(node.AsNode(), node.TypeParameters) + p.writeSpace() + p.emitTypeNode(node.BaseType, ast.TypePrecedenceConditional) + p.exitNode(node.AsNode(), state) +} + // emits a Type node in the `extends` clause of a ConditionalType func (p *Printer) emitTypeNodeInExtends(node *ast.TypeNode) { savedInExtends := p.inExtends @@ -2281,6 +2289,8 @@ func (p *Printer) emitTypeNode(node *ast.TypeNode, precedence ast.TypePrecedence p.emitTemplateTypeSpan(node.AsTemplateLiteralTypeSpan()) case ast.KindImportType: p.emitImportTypeNode(node.AsImportTypeNode()) + case ast.KindQuantifiedType: + p.emitQuantifiedTypeNpde(node.AsQuantifiedTypeNode()) case ast.KindExpressionWithTypeArguments: // !!! Should this actually be considered a type? diff --git a/testdata/baselines/reference/compiler/allowQuantifiedTypes.js b/testdata/baselines/reference/compiler/allowQuantifiedTypes.js new file mode 100644 index 00000000000..94e01d9ba65 --- /dev/null +++ b/testdata/baselines/reference/compiler/allowQuantifiedTypes.js @@ -0,0 +1,8 @@ +//// [tests/cases/compiler/allowQuantifiedTypes.ts] //// + +//// [allowQuantifiedTypes.ts] +type T0 = { values: T[], identifier: (value: T) => string } +type T1 = (t: T) => T +type T2 = (u: U) => U + +//// [allowQuantifiedTypes.js] diff --git a/testdata/baselines/reference/compiler/allowQuantifiedTypes.symbols b/testdata/baselines/reference/compiler/allowQuantifiedTypes.symbols new file mode 100644 index 00000000000..e8ead920d75 --- /dev/null +++ b/testdata/baselines/reference/compiler/allowQuantifiedTypes.symbols @@ -0,0 +1,28 @@ +//// [tests/cases/compiler/allowQuantifiedTypes.ts] //// + +=== allowQuantifiedTypes.ts === +type T0 = { values: T[], identifier: (value: T) => string } +>T0 : Symbol(T0, Decl(allowQuantifiedTypes.ts, 0, 0)) +>T : Symbol(T, Decl(allowQuantifiedTypes.ts, 0, 11)) +>values : Symbol(values, Decl(allowQuantifiedTypes.ts, 0, 30)) +>T : Symbol(T, Decl(allowQuantifiedTypes.ts, 0, 11)) +>identifier : Symbol(identifier, Decl(allowQuantifiedTypes.ts, 0, 43)) +>value : Symbol(value, Decl(allowQuantifiedTypes.ts, 0, 57)) +>T : Symbol(T, Decl(allowQuantifiedTypes.ts, 0, 11)) + +type T1 = (t: T) => T +>T1 : Symbol(T1, Decl(allowQuantifiedTypes.ts, 0, 78)) +>T : Symbol(T, Decl(allowQuantifiedTypes.ts, 1, 11)) +>t : Symbol(t, Decl(allowQuantifiedTypes.ts, 1, 29)) +>T : Symbol(T, Decl(allowQuantifiedTypes.ts, 1, 11)) +>T : Symbol(T, Decl(allowQuantifiedTypes.ts, 1, 11)) + +type T2 = (u: U) => U +>T2 : Symbol(T2, Decl(allowQuantifiedTypes.ts, 1, 39)) +>T : Symbol(T, Decl(allowQuantifiedTypes.ts, 2, 11)) +>U : Symbol(U, Decl(allowQuantifiedTypes.ts, 2, 30)) +>T : Symbol(T, Decl(allowQuantifiedTypes.ts, 2, 11)) +>u : Symbol(u, Decl(allowQuantifiedTypes.ts, 2, 43)) +>U : Symbol(U, Decl(allowQuantifiedTypes.ts, 2, 30)) +>U : Symbol(U, Decl(allowQuantifiedTypes.ts, 2, 30)) + diff --git a/testdata/baselines/reference/compiler/allowQuantifiedTypes.types b/testdata/baselines/reference/compiler/allowQuantifiedTypes.types new file mode 100644 index 00000000000..600f750c1de --- /dev/null +++ b/testdata/baselines/reference/compiler/allowQuantifiedTypes.types @@ -0,0 +1,17 @@ +//// [tests/cases/compiler/allowQuantifiedTypes.ts] //// + +=== allowQuantifiedTypes.ts === +type T0 = { values: T[], identifier: (value: T) => string } +>T0 : { values: T[]; identifier: (value: T) => string; } +>values : T[] +>identifier : (value: T) => string +>value : T + +type T1 = (t: T) => T +>T1 : T1 +>t : T + +type T2 = (u: U) => U +>T2 : (u: U) => U +>u : U + diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBasic.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesBasic.errors.txt new file mode 100644 index 00000000000..8b17ec27ca0 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesBasic.errors.txt @@ -0,0 +1,24 @@ +quantifiedTypesBasic.ts(8,5): error TS2322: Type '{ values: ({ key: string; } | { key: number; })[]; identifier: (v: { key: string; } | { key: number; }) => string | number; }' is not assignable to type '{ values: ({ key: string; } | { key: number; })[]; identifier: (value: { key: string; } | { key: number; }) => string; }'. + The types returned by 'identifier(...)' are incompatible between these types. + Type 'string | number' is not assignable to type 'string'. + Type 'number' is not assignable to type 'string'. + + +==== quantifiedTypesBasic.ts (1 errors) ==== + let t0: T = "hello" + + let t1: { values: T[], identifier: (value: T) => string } = { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => v.key + } + + let t2: { values: T[], identifier: (value: T) => string } = { + ~~ +!!! error TS2322: Type '{ values: ({ key: string; } | { key: number; })[]; identifier: (v: { key: string; } | { key: number; }) => string | number; }' is not assignable to type '{ values: ({ key: string; } | { key: number; })[]; identifier: (value: { key: string; } | { key: number; }) => string; }'. +!!! error TS2322: The types returned by 'identifier(...)' are incompatible between these types. +!!! error TS2322: Type 'string | number' is not assignable to type 'string'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + values: [{ key: "a" }, { key: "b" }, { key: 0 }], + identifier: v => v.key + } + \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBasic.js b/testdata/baselines/reference/compiler/quantifiedTypesBasic.js new file mode 100644 index 00000000000..d4bdf87766f --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesBasic.js @@ -0,0 +1,26 @@ +//// [tests/cases/compiler/quantifiedTypesBasic.ts] //// + +//// [quantifiedTypesBasic.ts] +let t0: T = "hello" + +let t1: { values: T[], identifier: (value: T) => string } = { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => v.key +} + +let t2: { values: T[], identifier: (value: T) => string } = { + values: [{ key: "a" }, { key: "b" }, { key: 0 }], + identifier: v => v.key +} + + +//// [quantifiedTypesBasic.js] +let t0 = "hello"; +let t1 = { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => v.key +}; +let t2 = { + values: [{ key: "a" }, { key: "b" }, { key: 0 }], + identifier: v => v.key +}; diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBasic.symbols b/testdata/baselines/reference/compiler/quantifiedTypesBasic.symbols new file mode 100644 index 00000000000..cf4677eeb3b --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesBasic.symbols @@ -0,0 +1,54 @@ +//// [tests/cases/compiler/quantifiedTypesBasic.ts] //// + +=== quantifiedTypesBasic.ts === +let t0: T = "hello" +>t0 : Symbol(t0, Decl(quantifiedTypesBasic.ts, 0, 3)) +>T : Symbol(T, Decl(quantifiedTypesBasic.ts, 0, 9)) +>T : Symbol(T, Decl(quantifiedTypesBasic.ts, 0, 9)) + +let t1: { values: T[], identifier: (value: T) => string } = { +>t1 : Symbol(t1, Decl(quantifiedTypesBasic.ts, 2, 3)) +>T : Symbol(T, Decl(quantifiedTypesBasic.ts, 2, 9)) +>values : Symbol(values, Decl(quantifiedTypesBasic.ts, 2, 13)) +>T : Symbol(T, Decl(quantifiedTypesBasic.ts, 2, 9)) +>identifier : Symbol(identifier, Decl(quantifiedTypesBasic.ts, 2, 26)) +>value : Symbol(value, Decl(quantifiedTypesBasic.ts, 2, 40)) +>T : Symbol(T, Decl(quantifiedTypesBasic.ts, 2, 9)) + + values: [{ key: "a" }, { key: "b" }, { key: "c" }], +>values : Symbol(values, Decl(quantifiedTypesBasic.ts, 2, 65)) +>key : Symbol(key, Decl(quantifiedTypesBasic.ts, 3, 12)) +>key : Symbol(key, Decl(quantifiedTypesBasic.ts, 3, 26)) +>key : Symbol(key, Decl(quantifiedTypesBasic.ts, 3, 40)) + + identifier: v => v.key +>identifier : Symbol(identifier, Decl(quantifiedTypesBasic.ts, 3, 53)) +>v : Symbol(v, Decl(quantifiedTypesBasic.ts, 4, 13)) +>v.key : Symbol(key, Decl(quantifiedTypesBasic.ts, 3, 12)) +>v : Symbol(v, Decl(quantifiedTypesBasic.ts, 4, 13)) +>key : Symbol(key, Decl(quantifiedTypesBasic.ts, 3, 12)) +} + +let t2: { values: T[], identifier: (value: T) => string } = { +>t2 : Symbol(t2, Decl(quantifiedTypesBasic.ts, 7, 3)) +>T : Symbol(T, Decl(quantifiedTypesBasic.ts, 7, 9)) +>values : Symbol(values, Decl(quantifiedTypesBasic.ts, 7, 13)) +>T : Symbol(T, Decl(quantifiedTypesBasic.ts, 7, 9)) +>identifier : Symbol(identifier, Decl(quantifiedTypesBasic.ts, 7, 26)) +>value : Symbol(value, Decl(quantifiedTypesBasic.ts, 7, 40)) +>T : Symbol(T, Decl(quantifiedTypesBasic.ts, 7, 9)) + + values: [{ key: "a" }, { key: "b" }, { key: 0 }], +>values : Symbol(values, Decl(quantifiedTypesBasic.ts, 7, 65)) +>key : Symbol(key, Decl(quantifiedTypesBasic.ts, 8, 12)) +>key : Symbol(key, Decl(quantifiedTypesBasic.ts, 8, 26)) +>key : Symbol(key, Decl(quantifiedTypesBasic.ts, 8, 40)) + + identifier: v => v.key +>identifier : Symbol(identifier, Decl(quantifiedTypesBasic.ts, 8, 51)) +>v : Symbol(v, Decl(quantifiedTypesBasic.ts, 9, 13)) +>v.key : Symbol(key, Decl(quantifiedTypesBasic.ts, 8, 12), Decl(quantifiedTypesBasic.ts, 8, 40)) +>v : Symbol(v, Decl(quantifiedTypesBasic.ts, 9, 13)) +>key : Symbol(key, Decl(quantifiedTypesBasic.ts, 8, 12), Decl(quantifiedTypesBasic.ts, 8, 40)) +} + diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBasic.types b/testdata/baselines/reference/compiler/quantifiedTypesBasic.types new file mode 100644 index 00000000000..0ee31693457 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesBasic.types @@ -0,0 +1,65 @@ +//// [tests/cases/compiler/quantifiedTypesBasic.ts] //// + +=== quantifiedTypesBasic.ts === +let t0: T = "hello" +>t0 : T +>"hello" : "hello" + +let t1: { values: T[], identifier: (value: T) => string } = { +>t1 : { values: T[]; identifier: (value: T) => string; } +>values : T[] +>identifier : (value: T) => string +>value : T +>{ values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => v.key} : { values: { key: string; }[]; identifier: (v: { key: string; }) => string; } + + values: [{ key: "a" }, { key: "b" }, { key: "c" }], +>values : { key: string; }[] +>[{ key: "a" }, { key: "b" }, { key: "c" }] : { key: string; }[] +>{ key: "a" } : { key: string; } +>key : string +>"a" : "a" +>{ key: "b" } : { key: string; } +>key : string +>"b" : "b" +>{ key: "c" } : { key: string; } +>key : string +>"c" : "c" + + identifier: v => v.key +>identifier : (v: { key: string; }) => string +>v => v.key : (v: { key: string; }) => string +>v : { key: string; } +>v.key : string +>v : { key: string; } +>key : string +} + +let t2: { values: T[], identifier: (value: T) => string } = { +>t2 : { values: T[]; identifier: (value: T) => string; } +>values : T[] +>identifier : (value: T) => string +>value : T +>{ values: [{ key: "a" }, { key: "b" }, { key: 0 }], identifier: v => v.key} : { values: ({ key: string; } | { key: number; })[]; identifier: (v: { key: string; } | { key: number; }) => string | number; } + + values: [{ key: "a" }, { key: "b" }, { key: 0 }], +>values : ({ key: string; } | { key: number; })[] +>[{ key: "a" }, { key: "b" }, { key: 0 }] : ({ key: string; } | { key: number; })[] +>{ key: "a" } : { key: string; } +>key : string +>"a" : "a" +>{ key: "b" } : { key: string; } +>key : string +>"b" : "b" +>{ key: 0 } : { key: number; } +>key : number +>0 : 0 + + identifier: v => v.key +>identifier : (v: { key: string; } | { key: number; }) => string | number +>v => v.key : (v: { key: string; } | { key: number; }) => string | number +>v : { key: string; } | { key: number; } +>v.key : string | number +>v : { key: string; } | { key: number; } +>key : string | number +} + diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBasic2.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesBasic2.errors.txt new file mode 100644 index 00000000000..c3f9c3a878f --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesBasic2.errors.txt @@ -0,0 +1,28 @@ +quantifiedTypesBasic2.ts(9,4): error TS2345: Argument of type '{ values: ({ key: string; } | { key: number; })[]; identifier: (v: { key: string; } | { key: number; }) => string | number; }' is not assignable to parameter of type '{ values: ({ key: string; } | { key: number; })[]; identifier: (value: { key: string; } | { key: number; }) => string; }'. + The types returned by 'identifier(...)' are incompatible between these types. + Type 'string | number' is not assignable to type 'string'. + Type 'number' is not assignable to type 'string'. + + +==== quantifiedTypesBasic2.ts (1 errors) ==== + declare const f1: (t: T) => void + f1("hello") + + declare const f2: (t: { values: T[], identifier: (value: T) => string }) => void + f2({ + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => v.key + }) + f2({ + ~ + values: [{ key: "a" }, { key: "b" }, { key: 0 }], + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + identifier: v => v.key + ~~~~~~~~~~~~~~~~~~~~~~~~ + }) + ~ +!!! error TS2345: Argument of type '{ values: ({ key: string; } | { key: number; })[]; identifier: (v: { key: string; } | { key: number; }) => string | number; }' is not assignable to parameter of type '{ values: ({ key: string; } | { key: number; })[]; identifier: (value: { key: string; } | { key: number; }) => string; }'. +!!! error TS2345: The types returned by 'identifier(...)' are incompatible between these types. +!!! error TS2345: Type 'string | number' is not assignable to type 'string'. +!!! error TS2345: Type 'number' is not assignable to type 'string'. + \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBasic2.js b/testdata/baselines/reference/compiler/quantifiedTypesBasic2.js new file mode 100644 index 00000000000..014c66f234e --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesBasic2.js @@ -0,0 +1,27 @@ +//// [tests/cases/compiler/quantifiedTypesBasic2.ts] //// + +//// [quantifiedTypesBasic2.ts] +declare const f1: (t: T) => void +f1("hello") + +declare const f2: (t: { values: T[], identifier: (value: T) => string }) => void +f2({ + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => v.key +}) +f2({ + values: [{ key: "a" }, { key: "b" }, { key: 0 }], + identifier: v => v.key +}) + + +//// [quantifiedTypesBasic2.js] +f1("hello"); +f2({ + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => v.key +}); +f2({ + values: [{ key: "a" }, { key: "b" }, { key: 0 }], + identifier: v => v.key +}); diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBasic2.symbols b/testdata/baselines/reference/compiler/quantifiedTypesBasic2.symbols new file mode 100644 index 00000000000..a5cca619d14 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesBasic2.symbols @@ -0,0 +1,57 @@ +//// [tests/cases/compiler/quantifiedTypesBasic2.ts] //// + +=== quantifiedTypesBasic2.ts === +declare const f1: (t: T) => void +>f1 : Symbol(f1, Decl(quantifiedTypesBasic2.ts, 0, 13)) +>t : Symbol(t, Decl(quantifiedTypesBasic2.ts, 0, 19)) +>T : Symbol(T, Decl(quantifiedTypesBasic2.ts, 0, 23)) +>T : Symbol(T, Decl(quantifiedTypesBasic2.ts, 0, 23)) + +f1("hello") +>f1 : Symbol(f1, Decl(quantifiedTypesBasic2.ts, 0, 13)) + +declare const f2: (t: { values: T[], identifier: (value: T) => string }) => void +>f2 : Symbol(f2, Decl(quantifiedTypesBasic2.ts, 3, 13)) +>t : Symbol(t, Decl(quantifiedTypesBasic2.ts, 3, 19)) +>T : Symbol(T, Decl(quantifiedTypesBasic2.ts, 3, 23)) +>values : Symbol(values, Decl(quantifiedTypesBasic2.ts, 3, 27)) +>T : Symbol(T, Decl(quantifiedTypesBasic2.ts, 3, 23)) +>identifier : Symbol(identifier, Decl(quantifiedTypesBasic2.ts, 3, 40)) +>value : Symbol(value, Decl(quantifiedTypesBasic2.ts, 3, 54)) +>T : Symbol(T, Decl(quantifiedTypesBasic2.ts, 3, 23)) + +f2({ +>f2 : Symbol(f2, Decl(quantifiedTypesBasic2.ts, 3, 13)) + + values: [{ key: "a" }, { key: "b" }, { key: "c" }], +>values : Symbol(values, Decl(quantifiedTypesBasic2.ts, 4, 4)) +>key : Symbol(key, Decl(quantifiedTypesBasic2.ts, 5, 12)) +>key : Symbol(key, Decl(quantifiedTypesBasic2.ts, 5, 26)) +>key : Symbol(key, Decl(quantifiedTypesBasic2.ts, 5, 40)) + + identifier: v => v.key +>identifier : Symbol(identifier, Decl(quantifiedTypesBasic2.ts, 5, 53)) +>v : Symbol(v, Decl(quantifiedTypesBasic2.ts, 6, 13)) +>v.key : Symbol(key, Decl(quantifiedTypesBasic2.ts, 5, 12)) +>v : Symbol(v, Decl(quantifiedTypesBasic2.ts, 6, 13)) +>key : Symbol(key, Decl(quantifiedTypesBasic2.ts, 5, 12)) + +}) +f2({ +>f2 : Symbol(f2, Decl(quantifiedTypesBasic2.ts, 3, 13)) + + values: [{ key: "a" }, { key: "b" }, { key: 0 }], +>values : Symbol(values, Decl(quantifiedTypesBasic2.ts, 8, 4)) +>key : Symbol(key, Decl(quantifiedTypesBasic2.ts, 9, 12)) +>key : Symbol(key, Decl(quantifiedTypesBasic2.ts, 9, 26)) +>key : Symbol(key, Decl(quantifiedTypesBasic2.ts, 9, 40)) + + identifier: v => v.key +>identifier : Symbol(identifier, Decl(quantifiedTypesBasic2.ts, 9, 51)) +>v : Symbol(v, Decl(quantifiedTypesBasic2.ts, 10, 13)) +>v.key : Symbol(key, Decl(quantifiedTypesBasic2.ts, 9, 12), Decl(quantifiedTypesBasic2.ts, 9, 40)) +>v : Symbol(v, Decl(quantifiedTypesBasic2.ts, 10, 13)) +>key : Symbol(key, Decl(quantifiedTypesBasic2.ts, 9, 12), Decl(quantifiedTypesBasic2.ts, 9, 40)) + +}) + diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBasic2.types b/testdata/baselines/reference/compiler/quantifiedTypesBasic2.types new file mode 100644 index 00000000000..62c7cbe1e5b --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesBasic2.types @@ -0,0 +1,74 @@ +//// [tests/cases/compiler/quantifiedTypesBasic2.ts] //// + +=== quantifiedTypesBasic2.ts === +declare const f1: (t: T) => void +>f1 : (t: T) => void +>t : T + +f1("hello") +>f1("hello") : void +>f1 : (t: T) => void +>"hello" : "hello" + +declare const f2: (t: { values: T[], identifier: (value: T) => string }) => void +>f2 : (t: { values: T[]; identifier: (value: T) => string; }) => void +>t : { values: T[]; identifier: (value: T) => string; } +>values : T[] +>identifier : (value: T) => string +>value : T + +f2({ +>f2({ values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => v.key}) : void +>f2 : (t: { values: T[]; identifier: (value: T) => string; }) => void +>{ values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => v.key} : { values: { key: string; }[]; identifier: (v: { key: string; }) => string; } + + values: [{ key: "a" }, { key: "b" }, { key: "c" }], +>values : { key: string; }[] +>[{ key: "a" }, { key: "b" }, { key: "c" }] : { key: string; }[] +>{ key: "a" } : { key: string; } +>key : string +>"a" : "a" +>{ key: "b" } : { key: string; } +>key : string +>"b" : "b" +>{ key: "c" } : { key: string; } +>key : string +>"c" : "c" + + identifier: v => v.key +>identifier : (v: { key: string; }) => string +>v => v.key : (v: { key: string; }) => string +>v : { key: string; } +>v.key : string +>v : { key: string; } +>key : string + +}) +f2({ +>f2({ values: [{ key: "a" }, { key: "b" }, { key: 0 }], identifier: v => v.key}) : void +>f2 : (t: { values: T[]; identifier: (value: T) => string; }) => void +>{ values: [{ key: "a" }, { key: "b" }, { key: 0 }], identifier: v => v.key} : { values: ({ key: string; } | { key: number; })[]; identifier: (v: { key: string; } | { key: number; }) => string | number; } + + values: [{ key: "a" }, { key: "b" }, { key: 0 }], +>values : ({ key: string; } | { key: number; })[] +>[{ key: "a" }, { key: "b" }, { key: 0 }] : ({ key: string; } | { key: number; })[] +>{ key: "a" } : { key: string; } +>key : string +>"a" : "a" +>{ key: "b" } : { key: string; } +>key : string +>"b" : "b" +>{ key: 0 } : { key: number; } +>key : number +>0 : 0 + + identifier: v => v.key +>identifier : (v: { key: string; } | { key: number; }) => string | number +>v => v.key : (v: { key: string; } | { key: number; }) => string | number +>v : { key: string; } | { key: number; } +>v.key : string | number +>v : { key: string; } | { key: number; } +>key : string | number + +}) + diff --git a/testdata/baselines/reference/compiler/quantifiedTypesConstraints.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesConstraints.errors.txt new file mode 100644 index 00000000000..14214eb5c20 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesConstraints.errors.txt @@ -0,0 +1,22 @@ +quantifiedTypesConstraints.ts(4,3): error TS2345: Argument of type '{ values: string[]; identifier: (v: object) => object; }' is not assignable to parameter of type 'Input'. + Types of property 'values' are incompatible. + Type 'string[]' is not assignable to type 'object[]'. + Type 'string' is not assignable to type 'object'. + + +==== quantifiedTypesConstraints.ts (1 errors) ==== + type Input = { values: T[], identifier: (value: T) => string } + declare const f: (t: Input) => void + + f({ + ~ + values: ["a", "b", "c"], + ~~~~~~~~~~~~~~~~~~~~~~~~~~ + identifier: v => v + ~~~~~~~~~~~~~~~~~~~~ + }) + ~ +!!! error TS2345: Argument of type '{ values: string[]; identifier: (v: object) => object; }' is not assignable to parameter of type 'Input'. +!!! error TS2345: Types of property 'values' are incompatible. +!!! error TS2345: Type 'string[]' is not assignable to type 'object[]'. +!!! error TS2345: Type 'string' is not assignable to type 'object'. \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesConstraints.js b/testdata/baselines/reference/compiler/quantifiedTypesConstraints.js new file mode 100644 index 00000000000..957017a7b0c --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesConstraints.js @@ -0,0 +1,16 @@ +//// [tests/cases/compiler/quantifiedTypesConstraints.ts] //// + +//// [quantifiedTypesConstraints.ts] +type Input = { values: T[], identifier: (value: T) => string } +declare const f: (t: Input) => void + +f({ + values: ["a", "b", "c"], + identifier: v => v +}) + +//// [quantifiedTypesConstraints.js] +f({ + values: ["a", "b", "c"], + identifier: v => v +}); diff --git a/testdata/baselines/reference/compiler/quantifiedTypesConstraints.symbols b/testdata/baselines/reference/compiler/quantifiedTypesConstraints.symbols new file mode 100644 index 00000000000..3099c513f40 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesConstraints.symbols @@ -0,0 +1,31 @@ +//// [tests/cases/compiler/quantifiedTypesConstraints.ts] //// + +=== quantifiedTypesConstraints.ts === +type Input = { values: T[], identifier: (value: T) => string } +>Input : Symbol(Input, Decl(quantifiedTypesConstraints.ts, 0, 0)) +>T : Symbol(T, Decl(quantifiedTypesConstraints.ts, 0, 11)) +>values : Symbol(values, Decl(quantifiedTypesConstraints.ts, 0, 17)) +>T : Symbol(T, Decl(quantifiedTypesConstraints.ts, 0, 11)) +>identifier : Symbol(identifier, Decl(quantifiedTypesConstraints.ts, 0, 30)) +>value : Symbol(value, Decl(quantifiedTypesConstraints.ts, 0, 44)) +>T : Symbol(T, Decl(quantifiedTypesConstraints.ts, 0, 11)) + +declare const f: (t: Input) => void +>f : Symbol(f, Decl(quantifiedTypesConstraints.ts, 1, 13)) +>t : Symbol(t, Decl(quantifiedTypesConstraints.ts, 1, 18)) +>T : Symbol(T, Decl(quantifiedTypesConstraints.ts, 1, 22)) +>Input : Symbol(Input, Decl(quantifiedTypesConstraints.ts, 0, 0)) +>T : Symbol(T, Decl(quantifiedTypesConstraints.ts, 1, 22)) + +f({ +>f : Symbol(f, Decl(quantifiedTypesConstraints.ts, 1, 13)) + + values: ["a", "b", "c"], +>values : Symbol(values, Decl(quantifiedTypesConstraints.ts, 3, 3)) + + identifier: v => v +>identifier : Symbol(identifier, Decl(quantifiedTypesConstraints.ts, 4, 26)) +>v : Symbol(v, Decl(quantifiedTypesConstraints.ts, 5, 13)) +>v : Symbol(v, Decl(quantifiedTypesConstraints.ts, 5, 13)) + +}) diff --git a/testdata/baselines/reference/compiler/quantifiedTypesConstraints.types b/testdata/baselines/reference/compiler/quantifiedTypesConstraints.types new file mode 100644 index 00000000000..c3021a7a172 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesConstraints.types @@ -0,0 +1,32 @@ +//// [tests/cases/compiler/quantifiedTypesConstraints.ts] //// + +=== quantifiedTypesConstraints.ts === +type Input = { values: T[], identifier: (value: T) => string } +>Input : Input +>values : T[] +>identifier : (value: T) => string +>value : T + +declare const f: (t: Input) => void +>f : (t: Input) => void +>t : Input + +f({ +>f({ values: ["a", "b", "c"], identifier: v => v}) : void +>f : (t: Input) => void +>{ values: ["a", "b", "c"], identifier: v => v} : { values: string[]; identifier: (v: object) => object; } + + values: ["a", "b", "c"], +>values : string[] +>["a", "b", "c"] : string[] +>"a" : "a" +>"b" : "b" +>"c" : "c" + + identifier: v => v +>identifier : (v: object) => object +>v => v : (v: object) => object +>v : object +>v : object + +}) diff --git a/testdata/baselines/reference/compiler/quantifiedTypesIntermediate.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesIntermediate.errors.txt new file mode 100644 index 00000000000..be578a75d10 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesIntermediate.errors.txt @@ -0,0 +1,64 @@ +quantifiedTypesIntermediate.ts(12,3): error TS2322: Type '{ values: [{ key: string; }, { key: string; }, { key: string; }]; identifier: (v: { key: string; }) => number; }' is not assignable to type 'Input<{ key: string; } | { key: string; } | { key: string; }>'. + The types returned by 'identifier(...)' are incompatible between these types. + Type 'number' is not assignable to type 'string'. +quantifiedTypesIntermediate.ts(24,3): error TS2322: Type '{ values: [{ key: string; }, { key: string; }, { key: string; }]; identifier: (v: { key: string; }) => number; }' is not assignable to type 'Input<{ key: string; } | { key: string; } | { key: string; }>'. + The types returned by 'identifier(...)' are incompatible between these types. + Type 'number' is not assignable to type 'string'. + + +==== quantifiedTypesIntermediate.ts (2 errors) ==== + type Input = { values: T[], identifier: (value: T) => string } + declare const f: (t: ( Input)[]) => void + + f([ + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => v.key + } + ]) + + f([ + { + ~ + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + identifier: v => Number(v.key) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + } + ~~~ +!!! error TS2322: Type '{ values: [{ key: string; }, { key: string; }, { key: string; }]; identifier: (v: { key: string; }) => number; }' is not assignable to type 'Input<{ key: string; } | { key: string; } | { key: string; }>'. +!!! error TS2322: The types returned by 'identifier(...)' are incompatible between these types. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + ]) + + + f([ + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => v.key + }, + { + ~ + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + identifier: v => Number(v.key) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + } + ~~~ +!!! error TS2322: Type '{ values: [{ key: string; }, { key: string; }, { key: string; }]; identifier: (v: { key: string; }) => number; }' is not assignable to type 'Input<{ key: string; } | { key: string; } | { key: string; }>'. +!!! error TS2322: The types returned by 'identifier(...)' are incompatible between these types. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + ]) + + + f([ + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => v.key + }, + { + values: [{ id: 1 }, { id: 2 }, { id: 3 }], + identifier: v => v.id.toString() + } + ]) + \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesIntermediate.js b/testdata/baselines/reference/compiler/quantifiedTypesIntermediate.js new file mode 100644 index 00000000000..eb438b60786 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesIntermediate.js @@ -0,0 +1,78 @@ +//// [tests/cases/compiler/quantifiedTypesIntermediate.ts] //// + +//// [quantifiedTypesIntermediate.ts] +type Input = { values: T[], identifier: (value: T) => string } +declare const f: (t: ( Input)[]) => void + +f([ + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => v.key + } +]) + +f([ + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => Number(v.key) + } +]) + + +f([ + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => v.key + }, + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => Number(v.key) + } +]) + + +f([ + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => v.key + }, + { + values: [{ id: 1 }, { id: 2 }, { id: 3 }], + identifier: v => v.id.toString() + } +]) + + +//// [quantifiedTypesIntermediate.js] +f([ + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => v.key + } +]); +f([ + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => Number(v.key) + } +]); +f([ + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => v.key + }, + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => Number(v.key) + } +]); +f([ + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => v.key + }, + { + values: [{ id: 1 }, { id: 2 }, { id: 3 }], + identifier: v => v.id.toString() + } +]); diff --git a/testdata/baselines/reference/compiler/quantifiedTypesIntermediate.symbols b/testdata/baselines/reference/compiler/quantifiedTypesIntermediate.symbols new file mode 100644 index 00000000000..382b53bd891 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesIntermediate.symbols @@ -0,0 +1,127 @@ +//// [tests/cases/compiler/quantifiedTypesIntermediate.ts] //// + +=== quantifiedTypesIntermediate.ts === +type Input = { values: T[], identifier: (value: T) => string } +>Input : Symbol(Input, Decl(quantifiedTypesIntermediate.ts, 0, 0)) +>T : Symbol(T, Decl(quantifiedTypesIntermediate.ts, 0, 11)) +>values : Symbol(values, Decl(quantifiedTypesIntermediate.ts, 0, 17)) +>T : Symbol(T, Decl(quantifiedTypesIntermediate.ts, 0, 11)) +>identifier : Symbol(identifier, Decl(quantifiedTypesIntermediate.ts, 0, 30)) +>value : Symbol(value, Decl(quantifiedTypesIntermediate.ts, 0, 44)) +>T : Symbol(T, Decl(quantifiedTypesIntermediate.ts, 0, 11)) + +declare const f: (t: ( Input)[]) => void +>f : Symbol(f, Decl(quantifiedTypesIntermediate.ts, 1, 13)) +>t : Symbol(t, Decl(quantifiedTypesIntermediate.ts, 1, 18)) +>T : Symbol(T, Decl(quantifiedTypesIntermediate.ts, 1, 23)) +>Input : Symbol(Input, Decl(quantifiedTypesIntermediate.ts, 0, 0)) +>T : Symbol(T, Decl(quantifiedTypesIntermediate.ts, 1, 23)) + +f([ +>f : Symbol(f, Decl(quantifiedTypesIntermediate.ts, 1, 13)) + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], +>values : Symbol(values, Decl(quantifiedTypesIntermediate.ts, 4, 3)) +>key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 5, 14)) +>key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 5, 28)) +>key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 5, 42)) + + identifier: v => v.key +>identifier : Symbol(identifier, Decl(quantifiedTypesIntermediate.ts, 5, 55)) +>v : Symbol(v, Decl(quantifiedTypesIntermediate.ts, 6, 15)) +>v.key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 5, 14)) +>v : Symbol(v, Decl(quantifiedTypesIntermediate.ts, 6, 15)) +>key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 5, 14)) + } +]) + +f([ +>f : Symbol(f, Decl(quantifiedTypesIntermediate.ts, 1, 13)) + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], +>values : Symbol(values, Decl(quantifiedTypesIntermediate.ts, 11, 3)) +>key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 12, 14)) +>key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 12, 28)) +>key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 12, 42)) + + identifier: v => Number(v.key) +>identifier : Symbol(identifier, Decl(quantifiedTypesIntermediate.ts, 12, 55)) +>v : Symbol(v, Decl(quantifiedTypesIntermediate.ts, 13, 15)) +>Number : Symbol(Number, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>v.key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 12, 14)) +>v : Symbol(v, Decl(quantifiedTypesIntermediate.ts, 13, 15)) +>key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 12, 14)) + } +]) + + +f([ +>f : Symbol(f, Decl(quantifiedTypesIntermediate.ts, 1, 13)) + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], +>values : Symbol(values, Decl(quantifiedTypesIntermediate.ts, 19, 3)) +>key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 20, 14)) +>key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 20, 28)) +>key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 20, 42)) + + identifier: v => v.key +>identifier : Symbol(identifier, Decl(quantifiedTypesIntermediate.ts, 20, 55)) +>v : Symbol(v, Decl(quantifiedTypesIntermediate.ts, 21, 15)) +>v.key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 20, 14)) +>v : Symbol(v, Decl(quantifiedTypesIntermediate.ts, 21, 15)) +>key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 20, 14)) + + }, + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], +>values : Symbol(values, Decl(quantifiedTypesIntermediate.ts, 23, 3)) +>key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 24, 14)) +>key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 24, 28)) +>key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 24, 42)) + + identifier: v => Number(v.key) +>identifier : Symbol(identifier, Decl(quantifiedTypesIntermediate.ts, 24, 55)) +>v : Symbol(v, Decl(quantifiedTypesIntermediate.ts, 25, 15)) +>Number : Symbol(Number, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>v.key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 24, 14)) +>v : Symbol(v, Decl(quantifiedTypesIntermediate.ts, 25, 15)) +>key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 24, 14)) + } +]) + + +f([ +>f : Symbol(f, Decl(quantifiedTypesIntermediate.ts, 1, 13)) + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], +>values : Symbol(values, Decl(quantifiedTypesIntermediate.ts, 31, 3)) +>key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 32, 14)) +>key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 32, 28)) +>key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 32, 42)) + + identifier: v => v.key +>identifier : Symbol(identifier, Decl(quantifiedTypesIntermediate.ts, 32, 55)) +>v : Symbol(v, Decl(quantifiedTypesIntermediate.ts, 33, 15)) +>v.key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 32, 14)) +>v : Symbol(v, Decl(quantifiedTypesIntermediate.ts, 33, 15)) +>key : Symbol(key, Decl(quantifiedTypesIntermediate.ts, 32, 14)) + + }, + { + values: [{ id: 1 }, { id: 2 }, { id: 3 }], +>values : Symbol(values, Decl(quantifiedTypesIntermediate.ts, 35, 3)) +>id : Symbol(id, Decl(quantifiedTypesIntermediate.ts, 36, 14)) +>id : Symbol(id, Decl(quantifiedTypesIntermediate.ts, 36, 25)) +>id : Symbol(id, Decl(quantifiedTypesIntermediate.ts, 36, 36)) + + identifier: v => v.id.toString() +>identifier : Symbol(identifier, Decl(quantifiedTypesIntermediate.ts, 36, 46)) +>v : Symbol(v, Decl(quantifiedTypesIntermediate.ts, 37, 15)) +>v.id.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>v.id : Symbol(id, Decl(quantifiedTypesIntermediate.ts, 36, 14)) +>v : Symbol(v, Decl(quantifiedTypesIntermediate.ts, 37, 15)) +>id : Symbol(id, Decl(quantifiedTypesIntermediate.ts, 36, 14)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + } +]) + diff --git a/testdata/baselines/reference/compiler/quantifiedTypesIntermediate.types b/testdata/baselines/reference/compiler/quantifiedTypesIntermediate.types new file mode 100644 index 00000000000..df6663b3dd4 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesIntermediate.types @@ -0,0 +1,192 @@ +//// [tests/cases/compiler/quantifiedTypesIntermediate.ts] //// + +=== quantifiedTypesIntermediate.ts === +type Input = { values: T[], identifier: (value: T) => string } +>Input : Input +>values : T[] +>identifier : (value: T) => string +>value : T + +declare const f: (t: ( Input)[]) => void +>f : (t: ( Input)[]) => void +>t : ( Input)[] + +f([ +>f([ { values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => v.key }]) : void +>f : (t: ( Input)[]) => void +>[ { values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => v.key }] : { values: { key: string; }[]; identifier: (v: { key: string; }) => string; }[] + { +>{ values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => v.key } : { values: { key: string; }[]; identifier: (v: { key: string; }) => string; } + + values: [{ key: "a" }, { key: "b" }, { key: "c" }], +>values : { key: string; }[] +>[{ key: "a" }, { key: "b" }, { key: "c" }] : { key: string; }[] +>{ key: "a" } : { key: string; } +>key : string +>"a" : "a" +>{ key: "b" } : { key: string; } +>key : string +>"b" : "b" +>{ key: "c" } : { key: string; } +>key : string +>"c" : "c" + + identifier: v => v.key +>identifier : (v: { key: string; }) => string +>v => v.key : (v: { key: string; }) => string +>v : { key: string; } +>v.key : string +>v : { key: string; } +>key : string + } +]) + +f([ +>f([ { values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => Number(v.key) }]) : void +>f : (t: ( Input)[]) => void +>[ { values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => Number(v.key) }] : { values: { key: string; }[]; identifier: (v: { key: string; }) => number; }[] + { +>{ values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => Number(v.key) } : { values: { key: string; }[]; identifier: (v: { key: string; }) => number; } + + values: [{ key: "a" }, { key: "b" }, { key: "c" }], +>values : { key: string; }[] +>[{ key: "a" }, { key: "b" }, { key: "c" }] : { key: string; }[] +>{ key: "a" } : { key: string; } +>key : string +>"a" : "a" +>{ key: "b" } : { key: string; } +>key : string +>"b" : "b" +>{ key: "c" } : { key: string; } +>key : string +>"c" : "c" + + identifier: v => Number(v.key) +>identifier : (v: { key: string; }) => number +>v => Number(v.key) : (v: { key: string; }) => number +>v : { key: string; } +>Number(v.key) : number +>Number : NumberConstructor +>v.key : string +>v : { key: string; } +>key : string + } +]) + + +f([ +>f([ { values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => v.key }, { values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => Number(v.key) }]) : void +>f : (t: ( Input)[]) => void +>[ { values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => v.key }, { values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => Number(v.key) }] : ({ values: { key: string; }[]; identifier: (v: { key: string; }) => string; } | { values: { key: string; }[]; identifier: (v: { key: string; }) => number; })[] + { +>{ values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => v.key } : { values: { key: string; }[]; identifier: (v: { key: string; }) => string; } + + values: [{ key: "a" }, { key: "b" }, { key: "c" }], +>values : { key: string; }[] +>[{ key: "a" }, { key: "b" }, { key: "c" }] : { key: string; }[] +>{ key: "a" } : { key: string; } +>key : string +>"a" : "a" +>{ key: "b" } : { key: string; } +>key : string +>"b" : "b" +>{ key: "c" } : { key: string; } +>key : string +>"c" : "c" + + identifier: v => v.key +>identifier : (v: { key: string; }) => string +>v => v.key : (v: { key: string; }) => string +>v : { key: string; } +>v.key : string +>v : { key: string; } +>key : string + + }, + { +>{ values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => Number(v.key) } : { values: { key: string; }[]; identifier: (v: { key: string; }) => number; } + + values: [{ key: "a" }, { key: "b" }, { key: "c" }], +>values : { key: string; }[] +>[{ key: "a" }, { key: "b" }, { key: "c" }] : { key: string; }[] +>{ key: "a" } : { key: string; } +>key : string +>"a" : "a" +>{ key: "b" } : { key: string; } +>key : string +>"b" : "b" +>{ key: "c" } : { key: string; } +>key : string +>"c" : "c" + + identifier: v => Number(v.key) +>identifier : (v: { key: string; }) => number +>v => Number(v.key) : (v: { key: string; }) => number +>v : { key: string; } +>Number(v.key) : number +>Number : NumberConstructor +>v.key : string +>v : { key: string; } +>key : string + } +]) + + +f([ +>f([ { values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => v.key }, { values: [{ id: 1 }, { id: 2 }, { id: 3 }], identifier: v => v.id.toString() }]) : void +>f : (t: ( Input)[]) => void +>[ { values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => v.key }, { values: [{ id: 1 }, { id: 2 }, { id: 3 }], identifier: v => v.id.toString() }] : ({ values: { key: string; }[]; identifier: (v: { key: string; }) => string; } | { values: { id: number; }[]; identifier: (v: { id: number; }) => string; })[] + { +>{ values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => v.key } : { values: { key: string; }[]; identifier: (v: { key: string; }) => string; } + + values: [{ key: "a" }, { key: "b" }, { key: "c" }], +>values : { key: string; }[] +>[{ key: "a" }, { key: "b" }, { key: "c" }] : { key: string; }[] +>{ key: "a" } : { key: string; } +>key : string +>"a" : "a" +>{ key: "b" } : { key: string; } +>key : string +>"b" : "b" +>{ key: "c" } : { key: string; } +>key : string +>"c" : "c" + + identifier: v => v.key +>identifier : (v: { key: string; }) => string +>v => v.key : (v: { key: string; }) => string +>v : { key: string; } +>v.key : string +>v : { key: string; } +>key : string + + }, + { +>{ values: [{ id: 1 }, { id: 2 }, { id: 3 }], identifier: v => v.id.toString() } : { values: { id: number; }[]; identifier: (v: { id: number; }) => string; } + + values: [{ id: 1 }, { id: 2 }, { id: 3 }], +>values : { id: number; }[] +>[{ id: 1 }, { id: 2 }, { id: 3 }] : { id: number; }[] +>{ id: 1 } : { id: number; } +>id : number +>1 : 1 +>{ id: 2 } : { id: number; } +>id : number +>2 : 2 +>{ id: 3 } : { id: number; } +>id : number +>3 : 3 + + identifier: v => v.id.toString() +>identifier : (v: { id: number; }) => string +>v => v.id.toString() : (v: { id: number; }) => string +>v : { id: number; } +>v.id.toString() : string +>v.id.toString : (radix?: number) => string +>v.id : number +>v : { id: number; } +>id : number +>toString : (radix?: number) => string + } +]) + diff --git a/testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.errors.txt new file mode 100644 index 00000000000..9f7e3c33325 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.errors.txt @@ -0,0 +1,35 @@ +quantifiedTypesNormalizedShapes.ts(9,5): error TS2322: Type '{ a: { id: "a"; color: string; }; b: { id: "a"; color: string; }; }' is not assignable to type '{ a: Omit & { id: "a"; }; b: Omit & { id: "b"; }; }'. + Types of property 'b' are incompatible. + Type '{ id: "a"; color: string; }' is not assignable to type 'Omit & { id: "b"; }'. + Type '{ id: "a"; color: string; }' is not assignable to type '{ id: "b"; }'. + Types of property 'id' are incompatible. + Type '"a"' is not assignable to type '"b"'. + + +==== quantifiedTypesNormalizedShapes.ts (1 errors) ==== + type NormalizedRecord = + { [K in Id]: Omit & { id: K } } + + interface Layer { + id: string + color: string + } + + let layers: NormalizedRecord = { + ~~~~~~ +!!! error TS2322: Type '{ a: { id: "a"; color: string; }; b: { id: "a"; color: string; }; }' is not assignable to type '{ a: Omit & { id: "a"; }; b: Omit & { id: "b"; }; }'. +!!! error TS2322: Types of property 'b' are incompatible. +!!! error TS2322: Type '{ id: "a"; color: string; }' is not assignable to type 'Omit & { id: "b"; }'. +!!! error TS2322: Type '{ id: "a"; color: string; }' is not assignable to type '{ id: "b"; }'. +!!! error TS2322: Types of property 'id' are incompatible. +!!! error TS2322: Type '"a"' is not assignable to type '"b"'. + a: { + id: "a", + color: "green" + }, + b: { + id: "a", // should have been "b" + color: "blue" + } + } + \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.js b/testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.js new file mode 100644 index 00000000000..a0bc31d741a --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.js @@ -0,0 +1,34 @@ +//// [tests/cases/compiler/quantifiedTypesNormalizedShapes.ts] //// + +//// [quantifiedTypesNormalizedShapes.ts] +type NormalizedRecord = + { [K in Id]: Omit & { id: K } } + +interface Layer { + id: string + color: string +} + +let layers: NormalizedRecord = { + a: { + id: "a", + color: "green" + }, + b: { + id: "a", // should have been "b" + color: "blue" + } +} + + +//// [quantifiedTypesNormalizedShapes.js] +let layers = { + a: { + id: "a", + color: "green" + }, + b: { + id: "a", // should have been "b" + color: "blue" + } +}; diff --git a/testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.symbols b/testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.symbols new file mode 100644 index 00000000000..1ff71c460c6 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.symbols @@ -0,0 +1,53 @@ +//// [tests/cases/compiler/quantifiedTypesNormalizedShapes.ts] //// + +=== quantifiedTypesNormalizedShapes.ts === +type NormalizedRecord = +>NormalizedRecord : Symbol(NormalizedRecord, Decl(quantifiedTypesNormalizedShapes.ts, 0, 0)) +>T : Symbol(T, Decl(quantifiedTypesNormalizedShapes.ts, 0, 22)) +>id : Symbol(id, Decl(quantifiedTypesNormalizedShapes.ts, 0, 33)) + + { [K in Id]: Omit & { id: K } } +>Id : Symbol(Id, Decl(quantifiedTypesNormalizedShapes.ts, 1, 3)) +>K : Symbol(K, Decl(quantifiedTypesNormalizedShapes.ts, 1, 25)) +>Id : Symbol(Id, Decl(quantifiedTypesNormalizedShapes.ts, 1, 3)) +>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(quantifiedTypesNormalizedShapes.ts, 0, 22)) +>id : Symbol(id, Decl(quantifiedTypesNormalizedShapes.ts, 1, 52)) +>K : Symbol(K, Decl(quantifiedTypesNormalizedShapes.ts, 1, 25)) + +interface Layer { +>Layer : Symbol(Layer, Decl(quantifiedTypesNormalizedShapes.ts, 1, 62)) + + id: string +>id : Symbol(Layer.id, Decl(quantifiedTypesNormalizedShapes.ts, 3, 17)) + + color: string +>color : Symbol(Layer.color, Decl(quantifiedTypesNormalizedShapes.ts, 4, 12)) +} + +let layers: NormalizedRecord = { +>layers : Symbol(layers, Decl(quantifiedTypesNormalizedShapes.ts, 8, 3)) +>NormalizedRecord : Symbol(NormalizedRecord, Decl(quantifiedTypesNormalizedShapes.ts, 0, 0)) +>Layer : Symbol(Layer, Decl(quantifiedTypesNormalizedShapes.ts, 1, 62)) + + a: { +>a : Symbol(a, Decl(quantifiedTypesNormalizedShapes.ts, 8, 39)) + + id: "a", +>id : Symbol(id, Decl(quantifiedTypesNormalizedShapes.ts, 9, 6)) + + color: "green" +>color : Symbol(color, Decl(quantifiedTypesNormalizedShapes.ts, 10, 12)) + + }, + b: { +>b : Symbol(b, Decl(quantifiedTypesNormalizedShapes.ts, 12, 4)) + + id: "a", // should have been "b" +>id : Symbol(id, Decl(quantifiedTypesNormalizedShapes.ts, 13, 6)) + + color: "blue" +>color : Symbol(color, Decl(quantifiedTypesNormalizedShapes.ts, 14, 12)) + } +} + diff --git a/testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.types b/testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.types new file mode 100644 index 00000000000..7e2c259a0ec --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.types @@ -0,0 +1,49 @@ +//// [tests/cases/compiler/quantifiedTypesNormalizedShapes.ts] //// + +=== quantifiedTypesNormalizedShapes.ts === +type NormalizedRecord = +>NormalizedRecord : { [K in Id]: Omit & { id: K; }; } +>id : string + + { [K in Id]: Omit & { id: K } } +>id : K + +interface Layer { + id: string +>id : string + + color: string +>color : string +} + +let layers: NormalizedRecord = { +>layers : { [K in Id]: Omit & { id: K; }; } +>{ a: { id: "a", color: "green" }, b: { id: "a", // should have been "b" color: "blue" }} : { a: { id: "a"; color: string; }; b: { id: "a"; color: string; }; } + + a: { +>a : { id: string; color: string; } +>{ id: "a", color: "green" } : { id: string; color: string; } + + id: "a", +>id : string +>"a" : "a" + + color: "green" +>color : string +>"green" : "green" + + }, + b: { +>b : { id: string; color: string; } +>{ id: "a", // should have been "b" color: "blue" } : { id: string; color: string; } + + id: "a", // should have been "b" +>id : string +>"a" : "a" + + color: "blue" +>color : string +>"blue" : "blue" + } +} + diff --git a/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.errors.txt new file mode 100644 index 00000000000..6dfb104ba1f --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.errors.txt @@ -0,0 +1,22 @@ +quantifiedTypesSelfTypesCaseInsensitve.ts(16,11): error TS2345: Argument of type '"Acept"' is not assignable to parameter of type '"Error: Type 'Acept' is not assignable to type 'CaseInsensitive'" | "Error: Type 'Acept' is not assignable to type 'CaseInsensitive'"'. + + +==== quantifiedTypesSelfTypesCaseInsensitve.ts (1 errors) ==== + type PasreCaseInsensitive = + Self extends string + ? Lowercase extends Lowercase + ? Self + : `Error: Type '${Self}' is not assignable to type 'CaseInsensitive<${T}>'` + : T + + type CaseInsensitive = PasreCaseInsensitive + + declare const setHeader: + (key: CaseInsensitive<"Set-Cookie" | "Accept">, value: string) => void + + setHeader("Set-Cookie", "test") + setHeader("Accept", "test2") + setHeader("sEt-cOoKiE", "stop writing headers like this but ok") + setHeader("Acept", "nah this has a typo") + ~~~~~~~ +!!! error TS2345: Argument of type '"Acept"' is not assignable to parameter of type '"Error: Type 'Acept' is not assignable to type 'CaseInsensitive'" | "Error: Type 'Acept' is not assignable to type 'CaseInsensitive'"'. \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.js b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.js new file mode 100644 index 00000000000..6175a59ba07 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.js @@ -0,0 +1,25 @@ +//// [tests/cases/compiler/quantifiedTypesSelfTypesCaseInsensitve.ts] //// + +//// [quantifiedTypesSelfTypesCaseInsensitve.ts] +type PasreCaseInsensitive = + Self extends string + ? Lowercase extends Lowercase + ? Self + : `Error: Type '${Self}' is not assignable to type 'CaseInsensitive<${T}>'` + : T + +type CaseInsensitive = PasreCaseInsensitive + +declare const setHeader: + (key: CaseInsensitive<"Set-Cookie" | "Accept">, value: string) => void + +setHeader("Set-Cookie", "test") +setHeader("Accept", "test2") +setHeader("sEt-cOoKiE", "stop writing headers like this but ok") +setHeader("Acept", "nah this has a typo") + +//// [quantifiedTypesSelfTypesCaseInsensitve.js] +setHeader("Set-Cookie", "test"); +setHeader("Accept", "test2"); +setHeader("sEt-cOoKiE", "stop writing headers like this but ok"); +setHeader("Acept", "nah this has a typo"); diff --git a/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.symbols b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.symbols new file mode 100644 index 00000000000..0ce23b02878 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.symbols @@ -0,0 +1,55 @@ +//// [tests/cases/compiler/quantifiedTypesSelfTypesCaseInsensitve.ts] //// + +=== quantifiedTypesSelfTypesCaseInsensitve.ts === +type PasreCaseInsensitive = +>PasreCaseInsensitive : Symbol(PasreCaseInsensitive, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 0, 0)) +>Self : Symbol(Self, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 0, 26)) +>T : Symbol(T, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 0, 31)) + + Self extends string +>Self : Symbol(Self, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 0, 26)) + + ? Lowercase extends Lowercase +>Lowercase : Symbol(Lowercase, Decl(lib.es5.d.ts, --, --)) +>Self : Symbol(Self, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 0, 26)) +>Lowercase : Symbol(Lowercase, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 0, 31)) + + ? Self +>Self : Symbol(Self, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 0, 26)) + + : `Error: Type '${Self}' is not assignable to type 'CaseInsensitive<${T}>'` +>Self : Symbol(Self, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 0, 26)) +>T : Symbol(T, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 0, 31)) + + : T +>T : Symbol(T, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 0, 31)) + +type CaseInsensitive = PasreCaseInsensitive +>CaseInsensitive : Symbol(CaseInsensitive, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 5, 7)) +>T : Symbol(T, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 7, 21)) +>Self : Symbol(Self, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 7, 42)) +>PasreCaseInsensitive : Symbol(PasreCaseInsensitive, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 0, 0)) +>Self : Symbol(Self, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 7, 42)) +>T : Symbol(T, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 7, 21)) + +declare const setHeader: +>setHeader : Symbol(setHeader, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 9, 13)) + + (key: CaseInsensitive<"Set-Cookie" | "Accept">, value: string) => void +>key : Symbol(key, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 10, 3)) +>CaseInsensitive : Symbol(CaseInsensitive, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 5, 7)) +>value : Symbol(value, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 10, 49)) + +setHeader("Set-Cookie", "test") +>setHeader : Symbol(setHeader, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 9, 13)) + +setHeader("Accept", "test2") +>setHeader : Symbol(setHeader, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 9, 13)) + +setHeader("sEt-cOoKiE", "stop writing headers like this but ok") +>setHeader : Symbol(setHeader, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 9, 13)) + +setHeader("Acept", "nah this has a typo") +>setHeader : Symbol(setHeader, Decl(quantifiedTypesSelfTypesCaseInsensitve.ts, 9, 13)) + diff --git a/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.types b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.types new file mode 100644 index 00000000000..393ffb003cc --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.types @@ -0,0 +1,46 @@ +//// [tests/cases/compiler/quantifiedTypesSelfTypesCaseInsensitve.ts] //// + +=== quantifiedTypesSelfTypesCaseInsensitve.ts === +type PasreCaseInsensitive = +>PasreCaseInsensitive : PasreCaseInsensitive + + Self extends string + ? Lowercase extends Lowercase + ? Self + : `Error: Type '${Self}' is not assignable to type 'CaseInsensitive<${T}>'` + : T + +type CaseInsensitive = PasreCaseInsensitive +>CaseInsensitive : PasreCaseInsensitive + +declare const setHeader: +>setHeader : (key: PasreCaseInsensitive, value: string) => void + + (key: CaseInsensitive<"Set-Cookie" | "Accept">, value: string) => void +>key : PasreCaseInsensitive +>value : string + +setHeader("Set-Cookie", "test") +>setHeader("Set-Cookie", "test") : void +>setHeader : (key: PasreCaseInsensitive, value: string) => void +>"Set-Cookie" : "Set-Cookie" +>"test" : "test" + +setHeader("Accept", "test2") +>setHeader("Accept", "test2") : void +>setHeader : (key: PasreCaseInsensitive, value: string) => void +>"Accept" : "Accept" +>"test2" : "test2" + +setHeader("sEt-cOoKiE", "stop writing headers like this but ok") +>setHeader("sEt-cOoKiE", "stop writing headers like this but ok") : void +>setHeader : (key: PasreCaseInsensitive, value: string) => void +>"sEt-cOoKiE" : "sEt-cOoKiE" +>"stop writing headers like this but ok" : "stop writing headers like this but ok" + +setHeader("Acept", "nah this has a typo") +>setHeader("Acept", "nah this has a typo") : void +>setHeader : (key: PasreCaseInsensitive, value: string) => void +>"Acept" : "Acept" +>"nah this has a typo" : "nah this has a typo" + diff --git a/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.errors.txt new file mode 100644 index 00000000000..71ba0c99c88 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.errors.txt @@ -0,0 +1,48 @@ +quantifiedTypesSelfTypesStateMachine.ts(22,5): error TS2322: Type '{ off: { ON: "red"; }; red: { TICK: "yellow"; OFF: "off"; }; yellow: { TICK: "green"; OFF: "off"; }; green: { TICK: "reddd"; OFF: "off"; }; }' is not assignable to type 'ParseStateMachine<{ off: { ON: "red"; }; red: { TICK: "yellow"; OFF: "off"; }; yellow: { TICK: "green"; OFF: "off"; }; green: { TICK: "reddd"; OFF: "off"; }; }>'. + The types of 'green.TICK' are incompatible between these types. + Type '"reddd"' is not assignable to type '"green" | "off" | "red" | "yellow"'. Did you mean '"red"'? + + +==== quantifiedTypesSelfTypesStateMachine.ts (1 errors) ==== + type ParseStateMachine = { [S in keyof Self]: { [E in keyof Self[S]]: keyof Self } } + type StateMachine = > Self + + let trafficLights: StateMachine = { + off: { + ON: "red" + }, + red: { + TICK: "yellow", + OFF: "off" + }, + yellow: { + TICK: "green", + OFF: "off" + }, + green: { + TICK: "red", + OFF: "off" + } + } + + let trafficLightsInvalid: StateMachine = { + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type '{ off: { ON: "red"; }; red: { TICK: "yellow"; OFF: "off"; }; yellow: { TICK: "green"; OFF: "off"; }; green: { TICK: "reddd"; OFF: "off"; }; }' is not assignable to type 'ParseStateMachine<{ off: { ON: "red"; }; red: { TICK: "yellow"; OFF: "off"; }; yellow: { TICK: "green"; OFF: "off"; }; green: { TICK: "reddd"; OFF: "off"; }; }>'. +!!! error TS2322: The types of 'green.TICK' are incompatible between these types. +!!! error TS2322: Type '"reddd"' is not assignable to type '"green" | "off" | "red" | "yellow"'. Did you mean '"red"'? + off: { + ON: "red" + }, + red: { + TICK: "yellow", + OFF: "off" + }, + yellow: { + TICK: "green", + OFF: "off" + }, + green: { + TICK: "reddd", + OFF: "off" + } + } \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.js b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.js new file mode 100644 index 00000000000..ac06e2aedbc --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.js @@ -0,0 +1,77 @@ +//// [tests/cases/compiler/quantifiedTypesSelfTypesStateMachine.ts] //// + +//// [quantifiedTypesSelfTypesStateMachine.ts] +type ParseStateMachine = { [S in keyof Self]: { [E in keyof Self[S]]: keyof Self } } +type StateMachine = > Self + +let trafficLights: StateMachine = { + off: { + ON: "red" + }, + red: { + TICK: "yellow", + OFF: "off" + }, + yellow: { + TICK: "green", + OFF: "off" + }, + green: { + TICK: "red", + OFF: "off" + } +} + +let trafficLightsInvalid: StateMachine = { + off: { + ON: "red" + }, + red: { + TICK: "yellow", + OFF: "off" + }, + yellow: { + TICK: "green", + OFF: "off" + }, + green: { + TICK: "reddd", + OFF: "off" + } +} + +//// [quantifiedTypesSelfTypesStateMachine.js] +let trafficLights = { + off: { + ON: "red" + }, + red: { + TICK: "yellow", + OFF: "off" + }, + yellow: { + TICK: "green", + OFF: "off" + }, + green: { + TICK: "red", + OFF: "off" + } +}; +let trafficLightsInvalid = { + off: { + ON: "red" + }, + red: { + TICK: "yellow", + OFF: "off" + }, + yellow: { + TICK: "green", + OFF: "off" + }, + green: { + TICK: "reddd", + OFF: "off" + } +}; diff --git a/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.symbols b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.symbols new file mode 100644 index 00000000000..3c5167ee4d0 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.symbols @@ -0,0 +1,103 @@ +//// [tests/cases/compiler/quantifiedTypesSelfTypesStateMachine.ts] //// + +=== quantifiedTypesSelfTypesStateMachine.ts === +type ParseStateMachine = { [S in keyof Self]: { [E in keyof Self[S]]: keyof Self } } +>ParseStateMachine : Symbol(ParseStateMachine, Decl(quantifiedTypesSelfTypesStateMachine.ts, 0, 0)) +>Self : Symbol(Self, Decl(quantifiedTypesSelfTypesStateMachine.ts, 0, 23)) +>S : Symbol(S, Decl(quantifiedTypesSelfTypesStateMachine.ts, 0, 34)) +>Self : Symbol(Self, Decl(quantifiedTypesSelfTypesStateMachine.ts, 0, 23)) +>E : Symbol(E, Decl(quantifiedTypesSelfTypesStateMachine.ts, 0, 55)) +>Self : Symbol(Self, Decl(quantifiedTypesSelfTypesStateMachine.ts, 0, 23)) +>S : Symbol(S, Decl(quantifiedTypesSelfTypesStateMachine.ts, 0, 34)) +>Self : Symbol(Self, Decl(quantifiedTypesSelfTypesStateMachine.ts, 0, 23)) + +type StateMachine = > Self +>StateMachine : Symbol(StateMachine, Decl(quantifiedTypesSelfTypesStateMachine.ts, 0, 90)) +>Self : Symbol(Self, Decl(quantifiedTypesSelfTypesStateMachine.ts, 1, 21)) +>ParseStateMachine : Symbol(ParseStateMachine, Decl(quantifiedTypesSelfTypesStateMachine.ts, 0, 0)) +>Self : Symbol(Self, Decl(quantifiedTypesSelfTypesStateMachine.ts, 1, 21)) +>Self : Symbol(Self, Decl(quantifiedTypesSelfTypesStateMachine.ts, 1, 21)) + +let trafficLights: StateMachine = { +>trafficLights : Symbol(trafficLights, Decl(quantifiedTypesSelfTypesStateMachine.ts, 3, 3)) +>StateMachine : Symbol(StateMachine, Decl(quantifiedTypesSelfTypesStateMachine.ts, 0, 90)) + + off: { +>off : Symbol(off, Decl(quantifiedTypesSelfTypesStateMachine.ts, 3, 35)) + + ON: "red" +>ON : Symbol(ON, Decl(quantifiedTypesSelfTypesStateMachine.ts, 4, 8)) + + }, + red: { +>red : Symbol(red, Decl(quantifiedTypesSelfTypesStateMachine.ts, 6, 4)) + + TICK: "yellow", +>TICK : Symbol(TICK, Decl(quantifiedTypesSelfTypesStateMachine.ts, 7, 8)) + + OFF: "off" +>OFF : Symbol(OFF, Decl(quantifiedTypesSelfTypesStateMachine.ts, 8, 19)) + + }, + yellow: { +>yellow : Symbol(yellow, Decl(quantifiedTypesSelfTypesStateMachine.ts, 10, 4)) + + TICK: "green", +>TICK : Symbol(TICK, Decl(quantifiedTypesSelfTypesStateMachine.ts, 11, 11)) + + OFF: "off" +>OFF : Symbol(OFF, Decl(quantifiedTypesSelfTypesStateMachine.ts, 12, 18)) + + }, + green: { +>green : Symbol(green, Decl(quantifiedTypesSelfTypesStateMachine.ts, 14, 4)) + + TICK: "red", +>TICK : Symbol(TICK, Decl(quantifiedTypesSelfTypesStateMachine.ts, 15, 10)) + + OFF: "off" +>OFF : Symbol(OFF, Decl(quantifiedTypesSelfTypesStateMachine.ts, 16, 16)) + } +} + +let trafficLightsInvalid: StateMachine = { +>trafficLightsInvalid : Symbol(trafficLightsInvalid, Decl(quantifiedTypesSelfTypesStateMachine.ts, 21, 3)) +>StateMachine : Symbol(StateMachine, Decl(quantifiedTypesSelfTypesStateMachine.ts, 0, 90)) + + off: { +>off : Symbol(off, Decl(quantifiedTypesSelfTypesStateMachine.ts, 21, 42)) + + ON: "red" +>ON : Symbol(ON, Decl(quantifiedTypesSelfTypesStateMachine.ts, 22, 8)) + + }, + red: { +>red : Symbol(red, Decl(quantifiedTypesSelfTypesStateMachine.ts, 24, 4)) + + TICK: "yellow", +>TICK : Symbol(TICK, Decl(quantifiedTypesSelfTypesStateMachine.ts, 25, 8)) + + OFF: "off" +>OFF : Symbol(OFF, Decl(quantifiedTypesSelfTypesStateMachine.ts, 26, 19)) + + }, + yellow: { +>yellow : Symbol(yellow, Decl(quantifiedTypesSelfTypesStateMachine.ts, 28, 4)) + + TICK: "green", +>TICK : Symbol(TICK, Decl(quantifiedTypesSelfTypesStateMachine.ts, 29, 11)) + + OFF: "off" +>OFF : Symbol(OFF, Decl(quantifiedTypesSelfTypesStateMachine.ts, 30, 18)) + + }, + green: { +>green : Symbol(green, Decl(quantifiedTypesSelfTypesStateMachine.ts, 32, 4)) + + TICK: "reddd", +>TICK : Symbol(TICK, Decl(quantifiedTypesSelfTypesStateMachine.ts, 33, 10)) + + OFF: "off" +>OFF : Symbol(OFF, Decl(quantifiedTypesSelfTypesStateMachine.ts, 34, 18)) + } +} diff --git a/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.types b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.types new file mode 100644 index 00000000000..5cab18f8733 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.types @@ -0,0 +1,114 @@ +//// [tests/cases/compiler/quantifiedTypesSelfTypesStateMachine.ts] //// + +=== quantifiedTypesSelfTypesStateMachine.ts === +type ParseStateMachine = { [S in keyof Self]: { [E in keyof Self[S]]: keyof Self } } +>ParseStateMachine : ParseStateMachine + +type StateMachine = > Self +>StateMachine : > Self + +let trafficLights: StateMachine = { +>trafficLights : > Self +>{ off: { ON: "red" }, red: { TICK: "yellow", OFF: "off" }, yellow: { TICK: "green", OFF: "off" }, green: { TICK: "red", OFF: "off" }} : { off: { ON: "red"; }; red: { TICK: "yellow"; OFF: "off"; }; yellow: { TICK: "green"; OFF: "off"; }; green: { TICK: "red"; OFF: "off"; }; } + + off: { +>off : { ON: "red"; } +>{ ON: "red" } : { ON: "red"; } + + ON: "red" +>ON : "red" +>"red" : "red" + + }, + red: { +>red : { TICK: "yellow"; OFF: "off"; } +>{ TICK: "yellow", OFF: "off" } : { TICK: "yellow"; OFF: "off"; } + + TICK: "yellow", +>TICK : "yellow" +>"yellow" : "yellow" + + OFF: "off" +>OFF : "off" +>"off" : "off" + + }, + yellow: { +>yellow : { TICK: "green"; OFF: "off"; } +>{ TICK: "green", OFF: "off" } : { TICK: "green"; OFF: "off"; } + + TICK: "green", +>TICK : "green" +>"green" : "green" + + OFF: "off" +>OFF : "off" +>"off" : "off" + + }, + green: { +>green : { TICK: "red"; OFF: "off"; } +>{ TICK: "red", OFF: "off" } : { TICK: "red"; OFF: "off"; } + + TICK: "red", +>TICK : "red" +>"red" : "red" + + OFF: "off" +>OFF : "off" +>"off" : "off" + } +} + +let trafficLightsInvalid: StateMachine = { +>trafficLightsInvalid : > Self +>{ off: { ON: "red" }, red: { TICK: "yellow", OFF: "off" }, yellow: { TICK: "green", OFF: "off" }, green: { TICK: "reddd", OFF: "off" }} : { off: { ON: "red"; }; red: { TICK: "yellow"; OFF: "off"; }; yellow: { TICK: "green"; OFF: "off"; }; green: { TICK: "reddd"; OFF: "off"; }; } + + off: { +>off : { ON: "red"; } +>{ ON: "red" } : { ON: "red"; } + + ON: "red" +>ON : "red" +>"red" : "red" + + }, + red: { +>red : { TICK: "yellow"; OFF: "off"; } +>{ TICK: "yellow", OFF: "off" } : { TICK: "yellow"; OFF: "off"; } + + TICK: "yellow", +>TICK : "yellow" +>"yellow" : "yellow" + + OFF: "off" +>OFF : "off" +>"off" : "off" + + }, + yellow: { +>yellow : { TICK: "green"; OFF: "off"; } +>{ TICK: "green", OFF: "off" } : { TICK: "green"; OFF: "off"; } + + TICK: "green", +>TICK : "green" +>"green" : "green" + + OFF: "off" +>OFF : "off" +>"off" : "off" + + }, + green: { +>green : { TICK: "reddd"; OFF: "off"; } +>{ TICK: "reddd", OFF: "off" } : { TICK: "reddd"; OFF: "off"; } + + TICK: "reddd", +>TICK : "reddd" +>"reddd" : "reddd" + + OFF: "off" +>OFF : "off" +>"off" : "off" + } +} diff --git a/testdata/tests/cases/compiler/allowQuantifiedTypes.ts b/testdata/tests/cases/compiler/allowQuantifiedTypes.ts new file mode 100644 index 00000000000..2c1b5080f6b --- /dev/null +++ b/testdata/tests/cases/compiler/allowQuantifiedTypes.ts @@ -0,0 +1,3 @@ +type T0 = { values: T[], identifier: (value: T) => string } +type T1 = (t: T) => T +type T2 = (u: U) => U \ No newline at end of file diff --git a/testdata/tests/cases/compiler/playground.ts b/testdata/tests/cases/compiler/playground.ts new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/tests/cases/compiler/quantifiedTypesBasic.ts b/testdata/tests/cases/compiler/quantifiedTypesBasic.ts new file mode 100644 index 00000000000..7abdd40a2a6 --- /dev/null +++ b/testdata/tests/cases/compiler/quantifiedTypesBasic.ts @@ -0,0 +1,11 @@ +let t0: T = "hello" + +let t1: { values: T[], identifier: (value: T) => string } = { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => v.key +} + +let t2: { values: T[], identifier: (value: T) => string } = { + values: [{ key: "a" }, { key: "b" }, { key: 0 }], + identifier: v => v.key +} diff --git a/testdata/tests/cases/compiler/quantifiedTypesBasic2.ts b/testdata/tests/cases/compiler/quantifiedTypesBasic2.ts new file mode 100644 index 00000000000..adb6a4cfdc8 --- /dev/null +++ b/testdata/tests/cases/compiler/quantifiedTypesBasic2.ts @@ -0,0 +1,12 @@ +declare const f1: (t: T) => void +f1("hello") + +declare const f2: (t: { values: T[], identifier: (value: T) => string }) => void +f2({ + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => v.key +}) +f2({ + values: [{ key: "a" }, { key: "b" }, { key: 0 }], + identifier: v => v.key +}) diff --git a/testdata/tests/cases/compiler/quantifiedTypesConstraints.ts b/testdata/tests/cases/compiler/quantifiedTypesConstraints.ts new file mode 100644 index 00000000000..e32b1c9dda5 --- /dev/null +++ b/testdata/tests/cases/compiler/quantifiedTypesConstraints.ts @@ -0,0 +1,7 @@ +type Input = { values: T[], identifier: (value: T) => string } +declare const f: (t: Input) => void + +f({ + values: ["a", "b", "c"], + identifier: v => v +}) \ No newline at end of file diff --git a/testdata/tests/cases/compiler/quantifiedTypesIntermediate.ts b/testdata/tests/cases/compiler/quantifiedTypesIntermediate.ts new file mode 100644 index 00000000000..b1f0876e06f --- /dev/null +++ b/testdata/tests/cases/compiler/quantifiedTypesIntermediate.ts @@ -0,0 +1,40 @@ +type Input = { values: T[], identifier: (value: T) => string } +declare const f: (t: ( Input)[]) => void + +f([ + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => v.key + } +]) + +f([ + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => Number(v.key) + } +]) + + +f([ + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => v.key + }, + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => Number(v.key) + } +]) + + +f([ + { + values: [{ key: "a" }, { key: "b" }, { key: "c" }], + identifier: v => v.key + }, + { + values: [{ id: 1 }, { id: 2 }, { id: 3 }], + identifier: v => v.id.toString() + } +]) diff --git a/testdata/tests/cases/compiler/quantifiedTypesNormalizedShapes.ts b/testdata/tests/cases/compiler/quantifiedTypesNormalizedShapes.ts new file mode 100644 index 00000000000..5a06230a30a --- /dev/null +++ b/testdata/tests/cases/compiler/quantifiedTypesNormalizedShapes.ts @@ -0,0 +1,18 @@ +type NormalizedRecord = + { [K in Id]: Omit & { id: K } } + +interface Layer { + id: string + color: string +} + +let layers: NormalizedRecord = { + a: { + id: "a", + color: "green" + }, + b: { + id: "a", // should have been "b" + color: "blue" + } +} diff --git a/testdata/tests/cases/compiler/quantifiedTypesSelfTypesCaseInsensitve.ts b/testdata/tests/cases/compiler/quantifiedTypesSelfTypesCaseInsensitve.ts new file mode 100644 index 00000000000..324a8920bb0 --- /dev/null +++ b/testdata/tests/cases/compiler/quantifiedTypesSelfTypesCaseInsensitve.ts @@ -0,0 +1,16 @@ +type PasreCaseInsensitive = + Self extends string + ? Lowercase extends Lowercase + ? Self + : `Error: Type '${Self}' is not assignable to type 'CaseInsensitive<${T}>'` + : T + +type CaseInsensitive = PasreCaseInsensitive + +declare const setHeader: + (key: CaseInsensitive<"Set-Cookie" | "Accept">, value: string) => void + +setHeader("Set-Cookie", "test") +setHeader("Accept", "test2") +setHeader("sEt-cOoKiE", "stop writing headers like this but ok") +setHeader("Acept", "nah this has a typo") \ No newline at end of file diff --git a/testdata/tests/cases/compiler/quantifiedTypesSelfTypesStateMachine.ts b/testdata/tests/cases/compiler/quantifiedTypesSelfTypesStateMachine.ts new file mode 100644 index 00000000000..bd9746035bd --- /dev/null +++ b/testdata/tests/cases/compiler/quantifiedTypesSelfTypesStateMachine.ts @@ -0,0 +1,38 @@ +type ParseStateMachine = { [S in keyof Self]: { [E in keyof Self[S]]: keyof Self } } +type StateMachine = > Self + +let trafficLights: StateMachine = { + off: { + ON: "red" + }, + red: { + TICK: "yellow", + OFF: "off" + }, + yellow: { + TICK: "green", + OFF: "off" + }, + green: { + TICK: "red", + OFF: "off" + } +} + +let trafficLightsInvalid: StateMachine = { + off: { + ON: "red" + }, + red: { + TICK: "yellow", + OFF: "off" + }, + yellow: { + TICK: "green", + OFF: "off" + }, + green: { + TICK: "reddd", + OFF: "off" + } +} \ No newline at end of file From 52ac36c971d0fff22532547cc8942b9e9a0d6b1f Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Tue, 30 Dec 2025 22:48:13 +0530 Subject: [PATCH 02/23] delete temp playground.ts --- testdata/tests/cases/compiler/playground.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 testdata/tests/cases/compiler/playground.ts diff --git a/testdata/tests/cases/compiler/playground.ts b/testdata/tests/cases/compiler/playground.ts deleted file mode 100644 index e69de29bb2d..00000000000 From a051f76be96ea80243d0b981760721e6c78900d6 Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Sun, 4 Jan 2026 20:11:02 +0530 Subject: [PATCH 03/23] redo and do only for object literals --- internal/checker/checker.go | 72 ++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 42 deletions(-) diff --git a/internal/checker/checker.go b/internal/checker/checker.go index df49fca0ee6..06bb36aa0e4 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -614,7 +614,6 @@ type Checker struct { reverseMappedCache map[ReverseMappedTypeKey]*Type reverseHomomorphicMappedCache map[ReverseMappedTypeKey]*Type iterationTypesCache map[IterationTypesKey]IterationTypes - contextualTypeStack map[*ast.Node]bool markerTypes collections.Set[*Type] undefinedSymbol *ast.Symbol argumentsSymbol *ast.Symbol @@ -916,7 +915,6 @@ func NewChecker(program Program) (*Checker, *sync.Mutex) { c.reverseMappedCache = make(map[ReverseMappedTypeKey]*Type) c.reverseHomomorphicMappedCache = make(map[ReverseMappedTypeKey]*Type) c.iterationTypesCache = make(map[IterationTypesKey]IterationTypes) - c.contextualTypeStack = make(map[*ast.Node]bool) c.undefinedSymbol = c.newSymbol(ast.SymbolFlagsProperty, "undefined") c.argumentsSymbol = c.newSymbol(ast.SymbolFlagsProperty, "arguments") c.requireSymbol = c.newSymbol(ast.SymbolFlagsProperty, "require") @@ -7248,22 +7246,6 @@ func (c *Checker) reportObjectPossiblyNullOrUndefinedError(node *ast.Node, facts } func (c *Checker) checkExpressionWithContextualType(node *ast.Node, contextualType *Type, inferenceContext *InferenceContext, checkMode CheckMode) *Type { - if contextualType.flags&TypeFlagsQuantified == 0 { - return c.checkExpressionWithContextualTypeWorker(node, contextualType, inferenceContext, checkMode) - } - t0 := c.checkExpressionWithContextualTypeWorker(node, contextualType.AsQuantifiedType().baseType, nil, checkMode|CheckModeSkipContextSensitive|CheckModeSkipGenericFunctions) - ctx := c.newInferenceContext( - core.Map(contextualType.AsQuantifiedType().typeParameters, func(t *TypeParameter) *Type { return t.AsType() }), - nil, - InferenceFlagsNone, - nil, - ) - c.inferTypes(ctx.inferences, t0, contextualType.AsQuantifiedType().baseType, InferencePriorityNoConstraints|InferencePriorityAlwaysStrict, false) - newContextualType := c.instantiateType(contextualType.AsQuantifiedType().baseType, ctx.mapper) - return c.checkExpressionWithContextualTypeWorker(node, newContextualType, inferenceContext, checkMode) -} - -func (c *Checker) checkExpressionWithContextualTypeWorker(node *ast.Node, contextualType *Type, inferenceContext *InferenceContext, checkMode CheckMode) *Type { contextNode := c.getContextNode(node) c.pushContextualType(contextNode, contextualType, false /*isCache*/) c.pushInferenceContext(contextNode, inferenceContext) @@ -7340,30 +7322,8 @@ func (c *Checker) checkExpressionEx(node *ast.Node, checkMode CheckMode) *Type { saveCurrentNode := c.currentNode c.currentNode = node c.instantiationCount = 0 - var t *Type - var contextualType *Type - if !c.contextualTypeStack[node] { - // quickfix to avoid recursion TODO: come up with something better - c.contextualTypeStack[node] = true - contextualType = c.getContextualType(node, ContextFlagsNone) - delete(c.contextualTypeStack, node) - } - isAlreadyContextuallyChecking := core.Some(c.contextualInfos, func(info ContextualInfo) bool { return info.node == node }) - if contextualType != nil && contextualType.flags&TypeFlagsQuantified != 0 && !isAlreadyContextuallyChecking { - t0 := c.checkExpressionWithContextualType(node, contextualType.AsQuantifiedType().baseType, nil, checkMode|CheckModeSkipContextSensitive|CheckModeSkipGenericFunctions) - ctx := c.newInferenceContext( - core.Map(contextualType.AsQuantifiedType().typeParameters, func(t *TypeParameter) *Type { return t.AsType() }), - nil, - InferenceFlagsNone, - nil, - ) - c.inferTypes(ctx.inferences, t0, contextualType.AsQuantifiedType().baseType, InferencePriorityNoConstraints|InferencePriorityAlwaysStrict, false) - newContextualType := c.instantiateType(contextualType.AsQuantifiedType().baseType, ctx.mapper) - t = c.checkExpressionWithContextualType(node, newContextualType, nil, checkMode) - } else { - uninstantiatedType := c.checkExpressionWorker(node, checkMode) - t = c.instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode) - } + uninstantiatedType := c.checkExpressionWorker(node, checkMode) + t := c.instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode) if isConstEnumObjectType(t) { c.checkConstEnumAccess(node, t) } @@ -12780,6 +12740,31 @@ func (c *Checker) checkReferenceExpression(expr *ast.Node, invalidReferenceMessa } func (c *Checker) checkObjectLiteral(node *ast.Node, checkMode CheckMode) *Type { + contextualType := c.getApparentTypeOfContextualType(node, ContextFlagsNone) + isAlreadyContextuallyChecking := c.contextualInfos != nil && core.Some(c.contextualInfos, func(info ContextualInfo) bool { return info.node == node }) + if contextualType == nil || contextualType.flags&TypeFlagsQuantified == 0 || isAlreadyContextuallyChecking { + return c.checkObjectLiteralWorker(node, checkMode) + } + baseType := contextualType.AsQuantifiedType().baseType + typeParameters := core.Map(contextualType.AsQuantifiedType().typeParameters, func(tp *TypeParameter) *Type { return tp.AsType() }) + + // context sensitive + inferenceContext := c.newInferenceContext(typeParameters, nil, InferenceFlagsNone, nil) + t := c.checkExpressionWithContextualType(node, baseType, inferenceContext, checkMode) + c.inferTypes(inferenceContext.inferences, t, baseType, InferencePriorityNone, false) + typeArguments := c.instantiateTypes(typeParameters, inferenceContext.nonFixingMapper) + + // normal + t = c.checkExpressionWithContextualType(node, baseType, inferenceContext, CheckModeNormal) + c.inferTypes(inferenceContext.inferences, t, baseType, InferencePriorityNone, false) + typeArguments = c.instantiateTypes(typeParameters, inferenceContext.mapper) + + // final + t = c.checkExpressionWithContextualType(node, c.instantiateType(baseType, newTypeMapper(typeParameters, typeArguments)), nil, CheckModeNormal) + return t +} + +func (c *Checker) checkObjectLiteralWorker(node *ast.Node, checkMode CheckMode) *Type { inDestructuringPattern := ast.IsAssignmentTarget(node) // Grammar checking c.checkGrammarObjectLiteralExpression(node.AsObjectLiteralExpression(), inDestructuringPattern) @@ -29752,6 +29737,9 @@ func (c *Checker) getApparentTypeOfContextualType(node *ast.Node, contextFlags C instantiatedType := c.instantiateContextualType(contextualType, node, contextFlags) if instantiatedType != nil && !(contextFlags&ContextFlagsNoConstraints != 0 && instantiatedType.flags&TypeFlagsTypeVariable != 0) { apparentType := c.mapTypeEx(instantiatedType, func(t *Type) *Type { + if t.flags&TypeFlagsQuantified != 0 { + return t + } if t.objectFlags&ObjectFlagsMapped != 0 { return t } From 62adca2ec1a8284df2189de813e584cc09ccf8e5 Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Mon, 5 Jan 2026 23:42:02 +0530 Subject: [PATCH 04/23] generalize checking for all expressions not just object literals --- internal/checker/checker.go | 68 +++++--- .../quantifiedTypesAdvanced.errors.txt | 48 ++++++ .../compiler/quantifiedTypesAdvanced.js | 75 +++++++++ .../compiler/quantifiedTypesAdvanced.symbols | 122 ++++++++++++++ .../compiler/quantifiedTypesAdvanced.types | 151 ++++++++++++++++++ .../compiler/quantifiedTypesBasic.errors.txt | 15 +- .../compiler/quantifiedTypesBasic.types | 2 +- .../compiler/quantifiedTypesBasic2.errors.txt | 18 +-- .../compiler/quantifiedTypesBasic2.types | 2 +- .../quantifiedTypesConstraints.errors.txt | 29 ++-- .../compiler/quantifiedTypesConstraints.types | 2 +- .../quantifiedTypesIntermediate.errors.txt | 28 +--- .../quantifiedTypesIntermediate.types | 8 +- ...quantifiedTypesNormalizedShapes.errors.txt | 17 +- .../quantifiedTypesNormalizedShapes.types | 2 +- ...iedTypesSelfTypesCaseInsensitve.errors.txt | 4 +- ...antifiedTypesSelfTypesCaseInsensitve.types | 2 +- ...ifiedTypesSelfTypesStateMachine.errors.txt | 11 +- ...quantifiedTypesSelfTypesStateMachine.types | 62 +++---- .../cases/compiler/quantifiedTypesAdvanced.ts | 24 +++ 20 files changed, 548 insertions(+), 142 deletions(-) create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesAdvanced.errors.txt create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesAdvanced.js create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesAdvanced.symbols create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesAdvanced.types create mode 100644 testdata/tests/cases/compiler/quantifiedTypesAdvanced.ts diff --git a/internal/checker/checker.go b/internal/checker/checker.go index 06bb36aa0e4..48811de6078 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -7246,6 +7246,9 @@ func (c *Checker) reportObjectPossiblyNullOrUndefinedError(node *ast.Node, facts } func (c *Checker) checkExpressionWithContextualType(node *ast.Node, contextualType *Type, inferenceContext *InferenceContext, checkMode CheckMode) *Type { + if contextualType.flags&TypeFlagsQuantified != 0 { + return c.checkExpressionExWithContextualType(node, checkMode, contextualType) + } contextNode := c.getContextNode(node) c.pushContextualType(contextNode, contextualType, false /*isCache*/) c.pushInferenceContext(contextNode, inferenceContext) @@ -7319,6 +7322,46 @@ func (c *Checker) checkExpression(node *ast.Node) *Type { } func (c *Checker) checkExpressionEx(node *ast.Node, checkMode CheckMode) *Type { + return c.checkExpressionExWithContextualType(node, checkMode, nil) +} + +func (c *Checker) checkExpressionExWithContextualType(node *ast.Node, checkMode CheckMode, contextualType *Type) *Type { + if node.Kind == ast.KindIdentifier { // to avoid recursion in some jsx test cases TODO: come up with a better fix + return c.checkExpressionExWorker(node, checkMode) + } + if contextualType == nil { + contextualType = c.getApparentTypeOfContextualType(node, ContextFlagsNone) + } + isAlreadyContextuallyChecking := c.contextualInfos != nil && core.Some(c.contextualInfos, func(info ContextualInfo) bool { return info.node == node }) + if contextualType == nil || contextualType.flags&TypeFlagsQuantified == 0 || isAlreadyContextuallyChecking { + return c.checkExpressionExWorker(node, checkMode) + } + baseType := contextualType.AsQuantifiedType().baseType + typeParameters := core.Map(contextualType.AsQuantifiedType().typeParameters, func(tp *TypeParameter) *Type { return tp.AsType() }) + + // context sensitive + // TODO: this is not needed if the node is not context sensitive + inferenceContext := c.newInferenceContext(typeParameters, nil, InferenceFlagsNone, nil) + t := c.checkExpressionWithContextualType(node, baseType, inferenceContext, checkMode|CheckModeSkipContextSensitive) + c.inferTypes(inferenceContext.inferences, t, baseType, InferencePriorityNone, false) + typeArguments := c.instantiateTypes(typeParameters, inferenceContext.nonFixingMapper) + + // normal + t = c.checkExpressionWithContextualType(node, baseType, inferenceContext, CheckModeNormal) + c.inferTypes(inferenceContext.inferences, t, baseType, InferencePriorityNone, false) + typeArguments = c.instantiateTypes(typeParameters, inferenceContext.mapper) + + // final + baseTypeInferred := c.instantiateType(baseType, newTypeMapper(typeParameters, typeArguments)) + t = c.checkExpressionWithContextualType(node, baseTypeInferred, nil, CheckModeNormal) + + if !c.checkTypeRelatedToAndOptionallyElaborate(t, baseTypeInferred, c.assignableRelation, node, node, nil, nil) { + return c.errorType // to avoid showing errors in parent TODO: maybe there is a better way to do this + } + return t +} + +func (c *Checker) checkExpressionExWorker(node *ast.Node, checkMode CheckMode) *Type { saveCurrentNode := c.currentNode c.currentNode = node c.instantiationCount = 0 @@ -12740,31 +12783,6 @@ func (c *Checker) checkReferenceExpression(expr *ast.Node, invalidReferenceMessa } func (c *Checker) checkObjectLiteral(node *ast.Node, checkMode CheckMode) *Type { - contextualType := c.getApparentTypeOfContextualType(node, ContextFlagsNone) - isAlreadyContextuallyChecking := c.contextualInfos != nil && core.Some(c.contextualInfos, func(info ContextualInfo) bool { return info.node == node }) - if contextualType == nil || contextualType.flags&TypeFlagsQuantified == 0 || isAlreadyContextuallyChecking { - return c.checkObjectLiteralWorker(node, checkMode) - } - baseType := contextualType.AsQuantifiedType().baseType - typeParameters := core.Map(contextualType.AsQuantifiedType().typeParameters, func(tp *TypeParameter) *Type { return tp.AsType() }) - - // context sensitive - inferenceContext := c.newInferenceContext(typeParameters, nil, InferenceFlagsNone, nil) - t := c.checkExpressionWithContextualType(node, baseType, inferenceContext, checkMode) - c.inferTypes(inferenceContext.inferences, t, baseType, InferencePriorityNone, false) - typeArguments := c.instantiateTypes(typeParameters, inferenceContext.nonFixingMapper) - - // normal - t = c.checkExpressionWithContextualType(node, baseType, inferenceContext, CheckModeNormal) - c.inferTypes(inferenceContext.inferences, t, baseType, InferencePriorityNone, false) - typeArguments = c.instantiateTypes(typeParameters, inferenceContext.mapper) - - // final - t = c.checkExpressionWithContextualType(node, c.instantiateType(baseType, newTypeMapper(typeParameters, typeArguments)), nil, CheckModeNormal) - return t -} - -func (c *Checker) checkObjectLiteralWorker(node *ast.Node, checkMode CheckMode) *Type { inDestructuringPattern := ast.IsAssignmentTarget(node) // Grammar checking c.checkGrammarObjectLiteralExpression(node.AsObjectLiteralExpression(), inDestructuringPattern) diff --git a/testdata/baselines/reference/compiler/quantifiedTypesAdvanced.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesAdvanced.errors.txt new file mode 100644 index 00000000000..adeb814c1ce --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesAdvanced.errors.txt @@ -0,0 +1,48 @@ +quantifiedTypesAdvanced.ts(28,5): error TS2322: Type 'boolean' is not assignable to type 'string | number'. +quantifiedTypesAdvanced.ts(36,5): error TS2353: Object literal may only specify known properties, and 'extra' does not exist in type '{ a: "hello"; ab: (a: "hello") => string; bc?: (b: string) => number; }'. + + +==== quantifiedTypesAdvanced.ts (2 errors) ==== + declare const f: + { a: A, ab: (a: A) => B, bc?: (b: B) => C })[]>(a: [...T]) => + { [K in keyof T]: T[K] extends { bc: (...a: never) => infer C } ? C : "lol" } + + let t0 = f([ + { + a: "0", + ab: a => +a, + bc: b => typeof b === "number" + }, + { + a: "hello", + ab: a => a + " world", + bc: b => { + b satisfies string + return +b + } + }, + { + a: 42, + ab: a => a.toString() + } + ]) + + + let t1 = f([ + { + a: true, + ~ +!!! error TS2322: Type 'boolean' is not assignable to type 'string | number'. +!!! related TS6500 quantifiedTypesAdvanced.ts:2:51: The expected type comes from property 'a' which is declared here on type '{ a: string | number; ab: (a: string | number) => number; bc?: (b: number) => boolean; }' + ab: a => +a, + bc: b => typeof b === "number" + }, + { + a: "hello", + ab: a => a + " world", + bc: b => +b, + extra: "foo" // TODO: an extra property should be allowed + ~~~~~ +!!! error TS2353: Object literal may only specify known properties, and 'extra' does not exist in type '{ a: "hello"; ab: (a: "hello") => string; bc?: (b: string) => number; }'. + } + ]) \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesAdvanced.js b/testdata/baselines/reference/compiler/quantifiedTypesAdvanced.js new file mode 100644 index 00000000000..01246608732 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesAdvanced.js @@ -0,0 +1,75 @@ +//// [tests/cases/compiler/quantifiedTypesAdvanced.ts] //// + +//// [quantifiedTypesAdvanced.ts] +declare const f: + { a: A, ab: (a: A) => B, bc?: (b: B) => C })[]>(a: [...T]) => + { [K in keyof T]: T[K] extends { bc: (...a: never) => infer C } ? C : "lol" } + +let t0 = f([ + { + a: "0", + ab: a => +a, + bc: b => typeof b === "number" + }, + { + a: "hello", + ab: a => a + " world", + bc: b => { + b satisfies string + return +b + } + }, + { + a: 42, + ab: a => a.toString() + } +]) + + +let t1 = f([ + { + a: true, + ab: a => +a, + bc: b => typeof b === "number" + }, + { + a: "hello", + ab: a => a + " world", + bc: b => +b, + extra: "foo" // TODO: an extra property should be allowed + } +]) + +//// [quantifiedTypesAdvanced.js] +let t0 = f([ + { + a: "0", + ab: a => +a, + bc: b => typeof b === "number" + }, + { + a: "hello", + ab: a => a + " world", + bc: b => { + b; + return +b; + } + }, + { + a: 42, + ab: a => a.toString() + } +]); +let t1 = f([ + { + a: true, + ab: a => +a, + bc: b => typeof b === "number" + }, + { + a: "hello", + ab: a => a + " world", + bc: b => +b, + extra: "foo" // TODO: an extra property should be allowed + } +]); diff --git a/testdata/baselines/reference/compiler/quantifiedTypesAdvanced.symbols b/testdata/baselines/reference/compiler/quantifiedTypesAdvanced.symbols new file mode 100644 index 00000000000..1fd1571ee0b --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesAdvanced.symbols @@ -0,0 +1,122 @@ +//// [tests/cases/compiler/quantifiedTypesAdvanced.ts] //// + +=== quantifiedTypesAdvanced.ts === +declare const f: +>f : Symbol(f, Decl(quantifiedTypesAdvanced.ts, 0, 13)) + + { a: A, ab: (a: A) => B, bc?: (b: B) => C })[]>(a: [...T]) => +>T : Symbol(T, Decl(quantifiedTypesAdvanced.ts, 1, 3)) +>A : Symbol(A, Decl(quantifiedTypesAdvanced.ts, 1, 15)) +>B : Symbol(B, Decl(quantifiedTypesAdvanced.ts, 1, 41)) +>C : Symbol(C, Decl(quantifiedTypesAdvanced.ts, 1, 44)) +>a : Symbol(a, Decl(quantifiedTypesAdvanced.ts, 1, 49)) +>A : Symbol(A, Decl(quantifiedTypesAdvanced.ts, 1, 15)) +>ab : Symbol(ab, Decl(quantifiedTypesAdvanced.ts, 1, 55)) +>a : Symbol(a, Decl(quantifiedTypesAdvanced.ts, 1, 61)) +>A : Symbol(A, Decl(quantifiedTypesAdvanced.ts, 1, 15)) +>B : Symbol(B, Decl(quantifiedTypesAdvanced.ts, 1, 41)) +>bc : Symbol(bc, Decl(quantifiedTypesAdvanced.ts, 1, 72)) +>b : Symbol(b, Decl(quantifiedTypesAdvanced.ts, 1, 79)) +>B : Symbol(B, Decl(quantifiedTypesAdvanced.ts, 1, 41)) +>C : Symbol(C, Decl(quantifiedTypesAdvanced.ts, 1, 44)) +>a : Symbol(a, Decl(quantifiedTypesAdvanced.ts, 1, 96)) +>T : Symbol(T, Decl(quantifiedTypesAdvanced.ts, 1, 3)) + + { [K in keyof T]: T[K] extends { bc: (...a: never) => infer C } ? C : "lol" } +>K : Symbol(K, Decl(quantifiedTypesAdvanced.ts, 2, 9)) +>T : Symbol(T, Decl(quantifiedTypesAdvanced.ts, 1, 3)) +>T : Symbol(T, Decl(quantifiedTypesAdvanced.ts, 1, 3)) +>K : Symbol(K, Decl(quantifiedTypesAdvanced.ts, 2, 9)) +>bc : Symbol(bc, Decl(quantifiedTypesAdvanced.ts, 2, 38)) +>a : Symbol(a, Decl(quantifiedTypesAdvanced.ts, 2, 44)) +>C : Symbol(C, Decl(quantifiedTypesAdvanced.ts, 2, 65)) +>C : Symbol(C, Decl(quantifiedTypesAdvanced.ts, 2, 65)) + +let t0 = f([ +>t0 : Symbol(t0, Decl(quantifiedTypesAdvanced.ts, 4, 3)) +>f : Symbol(f, Decl(quantifiedTypesAdvanced.ts, 0, 13)) + { + a: "0", +>a : Symbol(a, Decl(quantifiedTypesAdvanced.ts, 5, 3)) + + ab: a => +a, +>ab : Symbol(ab, Decl(quantifiedTypesAdvanced.ts, 6, 11)) +>a : Symbol(a, Decl(quantifiedTypesAdvanced.ts, 7, 7)) +>a : Symbol(a, Decl(quantifiedTypesAdvanced.ts, 7, 7)) + + bc: b => typeof b === "number" +>bc : Symbol(bc, Decl(quantifiedTypesAdvanced.ts, 7, 16)) +>b : Symbol(b, Decl(quantifiedTypesAdvanced.ts, 8, 7)) +>b : Symbol(b, Decl(quantifiedTypesAdvanced.ts, 8, 7)) + + }, + { + a: "hello", +>a : Symbol(a, Decl(quantifiedTypesAdvanced.ts, 10, 3)) + + ab: a => a + " world", +>ab : Symbol(ab, Decl(quantifiedTypesAdvanced.ts, 11, 15)) +>a : Symbol(a, Decl(quantifiedTypesAdvanced.ts, 12, 7)) +>a : Symbol(a, Decl(quantifiedTypesAdvanced.ts, 12, 7)) + + bc: b => { +>bc : Symbol(bc, Decl(quantifiedTypesAdvanced.ts, 12, 26)) +>b : Symbol(b, Decl(quantifiedTypesAdvanced.ts, 13, 7)) + + b satisfies string +>b : Symbol(b, Decl(quantifiedTypesAdvanced.ts, 13, 7)) + + return +b +>b : Symbol(b, Decl(quantifiedTypesAdvanced.ts, 13, 7)) + } + }, + { + a: 42, +>a : Symbol(a, Decl(quantifiedTypesAdvanced.ts, 18, 3)) + + ab: a => a.toString() +>ab : Symbol(ab, Decl(quantifiedTypesAdvanced.ts, 19, 10)) +>a : Symbol(a, Decl(quantifiedTypesAdvanced.ts, 20, 7)) +>a.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(quantifiedTypesAdvanced.ts, 20, 7)) +>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --)) + } +]) + + +let t1 = f([ +>t1 : Symbol(t1, Decl(quantifiedTypesAdvanced.ts, 25, 3)) +>f : Symbol(f, Decl(quantifiedTypesAdvanced.ts, 0, 13)) + { + a: true, +>a : Symbol(a, Decl(quantifiedTypesAdvanced.ts, 26, 3)) + + ab: a => +a, +>ab : Symbol(ab, Decl(quantifiedTypesAdvanced.ts, 27, 12)) +>a : Symbol(a, Decl(quantifiedTypesAdvanced.ts, 28, 7)) +>a : Symbol(a, Decl(quantifiedTypesAdvanced.ts, 28, 7)) + + bc: b => typeof b === "number" +>bc : Symbol(bc, Decl(quantifiedTypesAdvanced.ts, 28, 16)) +>b : Symbol(b, Decl(quantifiedTypesAdvanced.ts, 29, 7)) +>b : Symbol(b, Decl(quantifiedTypesAdvanced.ts, 29, 7)) + + }, + { + a: "hello", +>a : Symbol(a, Decl(quantifiedTypesAdvanced.ts, 31, 3)) + + ab: a => a + " world", +>ab : Symbol(ab, Decl(quantifiedTypesAdvanced.ts, 32, 15)) +>a : Symbol(a, Decl(quantifiedTypesAdvanced.ts, 33, 7)) +>a : Symbol(a, Decl(quantifiedTypesAdvanced.ts, 33, 7)) + + bc: b => +b, +>bc : Symbol(bc, Decl(quantifiedTypesAdvanced.ts, 33, 26)) +>b : Symbol(b, Decl(quantifiedTypesAdvanced.ts, 34, 7)) +>b : Symbol(b, Decl(quantifiedTypesAdvanced.ts, 34, 7)) + + extra: "foo" // TODO: an extra property should be allowed +>extra : Symbol(extra, Decl(quantifiedTypesAdvanced.ts, 34, 16)) + } +]) diff --git a/testdata/baselines/reference/compiler/quantifiedTypesAdvanced.types b/testdata/baselines/reference/compiler/quantifiedTypesAdvanced.types new file mode 100644 index 00000000000..4eb2f83c337 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesAdvanced.types @@ -0,0 +1,151 @@ +//// [tests/cases/compiler/quantifiedTypesAdvanced.ts] //// + +=== quantifiedTypesAdvanced.ts === +declare const f: +>f : { a: A; ab: (a: A) => B; bc?: (b: B) => C; })[]>(a: [...T]) => { [K in keyof T]: T[K] extends { bc: (...a: never) => infer C_1; } ? C_1 : "lol"; } + + { a: A, ab: (a: A) => B, bc?: (b: B) => C })[]>(a: [...T]) => +>a : A +>ab : (a: A) => B +>a : A +>bc : (b: B) => C +>b : B +>a : [...T] + + { [K in keyof T]: T[K] extends { bc: (...a: never) => infer C } ? C : "lol" } +>bc : (...a: never) => C +>a : never + +let t0 = f([ +>t0 : [boolean, number, "lol"] +>f([ { a: "0", ab: a => +a, bc: b => typeof b === "number" }, { a: "hello", ab: a => a + " world", bc: b => { b satisfies string return +b } }, { a: 42, ab: a => a.toString() }]) : [boolean, number, "lol"] +>f : { a: A; ab: (a: A) => B; bc?: (b: B) => C; })[]>(a: [...T]) => { [K in keyof T]: T[K] extends { bc: (...a: never) => infer C_1; } ? C_1 : "lol"; } +>[ { a: "0", ab: a => +a, bc: b => typeof b === "number" }, { a: "hello", ab: a => a + " world", bc: b => { b satisfies string return +b } }, { a: 42, ab: a => a.toString() }] : [{ a: "0"; ab: (a: "0") => number; bc: (b: number) => boolean; }, { a: "hello"; ab: (a: "hello") => string; bc: (b: string) => number; }, { a: 42; ab: (a: 42) => string; }] + { +>{ a: "0", ab: a => +a, bc: b => typeof b === "number" } : { a: "0"; ab: (a: "0") => number; bc: (b: number) => boolean; } + + a: "0", +>a : "0" +>"0" : "0" + + ab: a => +a, +>ab : (a: "0") => number +>a => +a : (a: "0") => number +>a : "0" +>+a : number +>a : "0" + + bc: b => typeof b === "number" +>bc : (b: number) => boolean +>b => typeof b === "number" : (b: number) => boolean +>b : number +>typeof b === "number" : boolean +>typeof b : "bigint" | "boolean" | "function" | "number" | "object" | "string" | "symbol" | "undefined" +>b : number +>"number" : "number" + + }, + { +>{ a: "hello", ab: a => a + " world", bc: b => { b satisfies string return +b } } : { a: "hello"; ab: (a: "hello") => string; bc: (b: string) => number; } + + a: "hello", +>a : "hello" +>"hello" : "hello" + + ab: a => a + " world", +>ab : (a: "hello") => string +>a => a + " world" : (a: "hello") => string +>a : "hello" +>a + " world" : string +>a : "hello" +>" world" : " world" + + bc: b => { +>bc : (b: string) => number +>b => { b satisfies string return +b } : (b: string) => number +>b : string + + b satisfies string +>b satisfies string : string +>b : string + + return +b +>+b : number +>b : string + } + }, + { +>{ a: 42, ab: a => a.toString() } : { a: 42; ab: (a: 42) => string; } + + a: 42, +>a : 42 +>42 : 42 + + ab: a => a.toString() +>ab : (a: 42) => string +>a => a.toString() : (a: 42) => string +>a : 42 +>a.toString() : string +>a.toString : (radix?: number) => string +>a : 42 +>toString : (radix?: number) => string + } +]) + + +let t1 = f([ +>t1 : any +>f([ { a: true, ab: a => +a, bc: b => typeof b === "number" }, { a: "hello", ab: a => a + " world", bc: b => +b, extra: "foo" // TODO: an extra property should be allowed }]) : any +>f : { a: A; ab: (a: A) => B; bc?: (b: B) => C; })[]>(a: [...T]) => { [K in keyof T]: T[K] extends { bc: (...a: never) => infer C_1; } ? C_1 : "lol"; } +>[ { a: true, ab: a => +a, bc: b => typeof b === "number" }, { a: "hello", ab: a => a + " world", bc: b => +b, extra: "foo" // TODO: an extra property should be allowed }] : [{ a: boolean; ab: (a: string | number) => number; bc: (b: number) => boolean; }, { a: string; ab: (a: "hello") => string; bc: (b: string) => number; extra: string; }] + { +>{ a: true, ab: a => +a, bc: b => typeof b === "number" } : { a: boolean; ab: (a: string | number) => number; bc: (b: number) => boolean; } + + a: true, +>a : boolean +>true : true + + ab: a => +a, +>ab : (a: string | number) => number +>a => +a : (a: string | number) => number +>a : string | number +>+a : number +>a : string | number + + bc: b => typeof b === "number" +>bc : (b: number) => boolean +>b => typeof b === "number" : (b: number) => boolean +>b : number +>typeof b === "number" : boolean +>typeof b : "bigint" | "boolean" | "function" | "number" | "object" | "string" | "symbol" | "undefined" +>b : number +>"number" : "number" + + }, + { +>{ a: "hello", ab: a => a + " world", bc: b => +b, extra: "foo" // TODO: an extra property should be allowed } : { a: string; ab: (a: "hello") => string; bc: (b: string) => number; extra: string; } + + a: "hello", +>a : string +>"hello" : "hello" + + ab: a => a + " world", +>ab : (a: "hello") => string +>a => a + " world" : (a: "hello") => string +>a : "hello" +>a + " world" : string +>a : "hello" +>" world" : " world" + + bc: b => +b, +>bc : (b: string) => number +>b => +b : (b: string) => number +>b : string +>+b : number +>b : string + + extra: "foo" // TODO: an extra property should be allowed +>extra : string +>"foo" : "foo" + } +]) diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBasic.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesBasic.errors.txt index 8b17ec27ca0..38148ca7e81 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesBasic.errors.txt +++ b/testdata/baselines/reference/compiler/quantifiedTypesBasic.errors.txt @@ -1,7 +1,5 @@ -quantifiedTypesBasic.ts(8,5): error TS2322: Type '{ values: ({ key: string; } | { key: number; })[]; identifier: (v: { key: string; } | { key: number; }) => string | number; }' is not assignable to type '{ values: ({ key: string; } | { key: number; })[]; identifier: (value: { key: string; } | { key: number; }) => string; }'. - The types returned by 'identifier(...)' are incompatible between these types. - Type 'string | number' is not assignable to type 'string'. - Type 'number' is not assignable to type 'string'. +quantifiedTypesBasic.ts(10,20): error TS2322: Type 'string | number' is not assignable to type 'string'. + Type 'number' is not assignable to type 'string'. ==== quantifiedTypesBasic.ts (1 errors) ==== @@ -13,12 +11,11 @@ quantifiedTypesBasic.ts(8,5): error TS2322: Type '{ values: ({ key: string; } | } let t2: { values: T[], identifier: (value: T) => string } = { - ~~ -!!! error TS2322: Type '{ values: ({ key: string; } | { key: number; })[]; identifier: (v: { key: string; } | { key: number; }) => string | number; }' is not assignable to type '{ values: ({ key: string; } | { key: number; })[]; identifier: (value: { key: string; } | { key: number; }) => string; }'. -!!! error TS2322: The types returned by 'identifier(...)' are incompatible between these types. -!!! error TS2322: Type 'string | number' is not assignable to type 'string'. -!!! error TS2322: Type 'number' is not assignable to type 'string'. values: [{ key: "a" }, { key: "b" }, { key: 0 }], identifier: v => v.key + ~~~~~ +!!! error TS2322: Type 'string | number' is not assignable to type 'string'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. +!!! related TS6502 quantifiedTypesBasic.ts:8:40: The expected type comes from the return type of this signature. } \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBasic.types b/testdata/baselines/reference/compiler/quantifiedTypesBasic.types index 0ee31693457..1908d24f2ac 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesBasic.types +++ b/testdata/baselines/reference/compiler/quantifiedTypesBasic.types @@ -39,7 +39,7 @@ let t2: { values: T[], identifier: (value: T) => string } = { >values : T[] >identifier : (value: T) => string >value : T ->{ values: [{ key: "a" }, { key: "b" }, { key: 0 }], identifier: v => v.key} : { values: ({ key: string; } | { key: number; })[]; identifier: (v: { key: string; } | { key: number; }) => string | number; } +>{ values: [{ key: "a" }, { key: "b" }, { key: 0 }], identifier: v => v.key} : any values: [{ key: "a" }, { key: "b" }, { key: 0 }], >values : ({ key: string; } | { key: number; })[] diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBasic2.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesBasic2.errors.txt index c3f9c3a878f..3e04efef513 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesBasic2.errors.txt +++ b/testdata/baselines/reference/compiler/quantifiedTypesBasic2.errors.txt @@ -1,7 +1,5 @@ -quantifiedTypesBasic2.ts(9,4): error TS2345: Argument of type '{ values: ({ key: string; } | { key: number; })[]; identifier: (v: { key: string; } | { key: number; }) => string | number; }' is not assignable to parameter of type '{ values: ({ key: string; } | { key: number; })[]; identifier: (value: { key: string; } | { key: number; }) => string; }'. - The types returned by 'identifier(...)' are incompatible between these types. - Type 'string | number' is not assignable to type 'string'. - Type 'number' is not assignable to type 'string'. +quantifiedTypesBasic2.ts(11,20): error TS2322: Type 'string | number' is not assignable to type 'string'. + Type 'number' is not assignable to type 'string'. ==== quantifiedTypesBasic2.ts (1 errors) ==== @@ -14,15 +12,11 @@ quantifiedTypesBasic2.ts(9,4): error TS2345: Argument of type '{ values: ({ key: identifier: v => v.key }) f2({ - ~ values: [{ key: "a" }, { key: "b" }, { key: 0 }], - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ identifier: v => v.key - ~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~~ +!!! error TS2322: Type 'string | number' is not assignable to type 'string'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. +!!! related TS6502 quantifiedTypesBasic2.ts:4:54: The expected type comes from the return type of this signature. }) - ~ -!!! error TS2345: Argument of type '{ values: ({ key: string; } | { key: number; })[]; identifier: (v: { key: string; } | { key: number; }) => string | number; }' is not assignable to parameter of type '{ values: ({ key: string; } | { key: number; })[]; identifier: (value: { key: string; } | { key: number; }) => string; }'. -!!! error TS2345: The types returned by 'identifier(...)' are incompatible between these types. -!!! error TS2345: Type 'string | number' is not assignable to type 'string'. -!!! error TS2345: Type 'number' is not assignable to type 'string'. \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBasic2.types b/testdata/baselines/reference/compiler/quantifiedTypesBasic2.types index 62c7cbe1e5b..a5f6f0f448d 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesBasic2.types +++ b/testdata/baselines/reference/compiler/quantifiedTypesBasic2.types @@ -47,7 +47,7 @@ f2({ f2({ >f2({ values: [{ key: "a" }, { key: "b" }, { key: 0 }], identifier: v => v.key}) : void >f2 : (t: { values: T[]; identifier: (value: T) => string; }) => void ->{ values: [{ key: "a" }, { key: "b" }, { key: 0 }], identifier: v => v.key} : { values: ({ key: string; } | { key: number; })[]; identifier: (v: { key: string; } | { key: number; }) => string | number; } +>{ values: [{ key: "a" }, { key: "b" }, { key: 0 }], identifier: v => v.key} : any values: [{ key: "a" }, { key: "b" }, { key: 0 }], >values : ({ key: string; } | { key: number; })[] diff --git a/testdata/baselines/reference/compiler/quantifiedTypesConstraints.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesConstraints.errors.txt index 14214eb5c20..709c2fa0a56 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesConstraints.errors.txt +++ b/testdata/baselines/reference/compiler/quantifiedTypesConstraints.errors.txt @@ -1,22 +1,23 @@ -quantifiedTypesConstraints.ts(4,3): error TS2345: Argument of type '{ values: string[]; identifier: (v: object) => object; }' is not assignable to parameter of type 'Input'. - Types of property 'values' are incompatible. - Type 'string[]' is not assignable to type 'object[]'. - Type 'string' is not assignable to type 'object'. +quantifiedTypesConstraints.ts(5,12): error TS2322: Type 'string' is not assignable to type 'object'. +quantifiedTypesConstraints.ts(5,17): error TS2322: Type 'string' is not assignable to type 'object'. +quantifiedTypesConstraints.ts(5,22): error TS2322: Type 'string' is not assignable to type 'object'. +quantifiedTypesConstraints.ts(6,20): error TS2322: Type 'object' is not assignable to type 'string'. -==== quantifiedTypesConstraints.ts (1 errors) ==== +==== quantifiedTypesConstraints.ts (4 errors) ==== type Input = { values: T[], identifier: (value: T) => string } declare const f: (t: Input) => void f({ - ~ values: ["a", "b", "c"], - ~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~ +!!! error TS2322: Type 'string' is not assignable to type 'object'. + ~~~ +!!! error TS2322: Type 'string' is not assignable to type 'object'. + ~~~ +!!! error TS2322: Type 'string' is not assignable to type 'object'. identifier: v => v - ~~~~~~~~~~~~~~~~~~~~ - }) - ~ -!!! error TS2345: Argument of type '{ values: string[]; identifier: (v: object) => object; }' is not assignable to parameter of type 'Input'. -!!! error TS2345: Types of property 'values' are incompatible. -!!! error TS2345: Type 'string[]' is not assignable to type 'object[]'. -!!! error TS2345: Type 'string' is not assignable to type 'object'. \ No newline at end of file + ~ +!!! error TS2322: Type 'object' is not assignable to type 'string'. +!!! related TS6502 quantifiedTypesConstraints.ts:1:44: The expected type comes from the return type of this signature. + }) \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesConstraints.types b/testdata/baselines/reference/compiler/quantifiedTypesConstraints.types index c3021a7a172..82d96e3f353 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesConstraints.types +++ b/testdata/baselines/reference/compiler/quantifiedTypesConstraints.types @@ -14,7 +14,7 @@ declare const f: (t: Input) => void f({ >f({ values: ["a", "b", "c"], identifier: v => v}) : void >f : (t: Input) => void ->{ values: ["a", "b", "c"], identifier: v => v} : { values: string[]; identifier: (v: object) => object; } +>{ values: ["a", "b", "c"], identifier: v => v} : any values: ["a", "b", "c"], >values : string[] diff --git a/testdata/baselines/reference/compiler/quantifiedTypesIntermediate.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesIntermediate.errors.txt index be578a75d10..7a19c688849 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesIntermediate.errors.txt +++ b/testdata/baselines/reference/compiler/quantifiedTypesIntermediate.errors.txt @@ -1,9 +1,5 @@ -quantifiedTypesIntermediate.ts(12,3): error TS2322: Type '{ values: [{ key: string; }, { key: string; }, { key: string; }]; identifier: (v: { key: string; }) => number; }' is not assignable to type 'Input<{ key: string; } | { key: string; } | { key: string; }>'. - The types returned by 'identifier(...)' are incompatible between these types. - Type 'number' is not assignable to type 'string'. -quantifiedTypesIntermediate.ts(24,3): error TS2322: Type '{ values: [{ key: string; }, { key: string; }, { key: string; }]; identifier: (v: { key: string; }) => number; }' is not assignable to type 'Input<{ key: string; } | { key: string; } | { key: string; }>'. - The types returned by 'identifier(...)' are incompatible between these types. - Type 'number' is not assignable to type 'string'. +quantifiedTypesIntermediate.ts(14,22): error TS2322: Type 'number' is not assignable to type 'string'. +quantifiedTypesIntermediate.ts(26,22): error TS2322: Type 'number' is not assignable to type 'string'. ==== quantifiedTypesIntermediate.ts (2 errors) ==== @@ -19,16 +15,12 @@ quantifiedTypesIntermediate.ts(24,3): error TS2322: Type '{ values: [{ key: stri f([ { - ~ values: [{ key: "a" }, { key: "b" }, { key: "c" }], - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ identifier: v => Number(v.key) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. +!!! related TS6502 quantifiedTypesIntermediate.ts:1:44: The expected type comes from the return type of this signature. } - ~~~ -!!! error TS2322: Type '{ values: [{ key: string; }, { key: string; }, { key: string; }]; identifier: (v: { key: string; }) => number; }' is not assignable to type 'Input<{ key: string; } | { key: string; } | { key: string; }>'. -!!! error TS2322: The types returned by 'identifier(...)' are incompatible between these types. -!!! error TS2322: Type 'number' is not assignable to type 'string'. ]) @@ -38,16 +30,12 @@ quantifiedTypesIntermediate.ts(24,3): error TS2322: Type '{ values: [{ key: stri identifier: v => v.key }, { - ~ values: [{ key: "a" }, { key: "b" }, { key: "c" }], - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ identifier: v => Number(v.key) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. +!!! related TS6502 quantifiedTypesIntermediate.ts:1:44: The expected type comes from the return type of this signature. } - ~~~ -!!! error TS2322: Type '{ values: [{ key: string; }, { key: string; }, { key: string; }]; identifier: (v: { key: string; }) => number; }' is not assignable to type 'Input<{ key: string; } | { key: string; } | { key: string; }>'. -!!! error TS2322: The types returned by 'identifier(...)' are incompatible between these types. -!!! error TS2322: Type 'number' is not assignable to type 'string'. ]) diff --git a/testdata/baselines/reference/compiler/quantifiedTypesIntermediate.types b/testdata/baselines/reference/compiler/quantifiedTypesIntermediate.types index df6663b3dd4..3adbdf63e71 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesIntermediate.types +++ b/testdata/baselines/reference/compiler/quantifiedTypesIntermediate.types @@ -44,9 +44,9 @@ f([ f([ >f([ { values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => Number(v.key) }]) : void >f : (t: ( Input)[]) => void ->[ { values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => Number(v.key) }] : { values: { key: string; }[]; identifier: (v: { key: string; }) => number; }[] +>[ { values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => Number(v.key) }] : any[] { ->{ values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => Number(v.key) } : { values: { key: string; }[]; identifier: (v: { key: string; }) => number; } +>{ values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => Number(v.key) } : any values: [{ key: "a" }, { key: "b" }, { key: "c" }], >values : { key: string; }[] @@ -77,7 +77,7 @@ f([ f([ >f([ { values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => v.key }, { values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => Number(v.key) }]) : void >f : (t: ( Input)[]) => void ->[ { values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => v.key }, { values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => Number(v.key) }] : ({ values: { key: string; }[]; identifier: (v: { key: string; }) => string; } | { values: { key: string; }[]; identifier: (v: { key: string; }) => number; })[] +>[ { values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => v.key }, { values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => Number(v.key) }] : any[] { >{ values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => v.key } : { values: { key: string; }[]; identifier: (v: { key: string; }) => string; } @@ -104,7 +104,7 @@ f([ }, { ->{ values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => Number(v.key) } : { values: { key: string; }[]; identifier: (v: { key: string; }) => number; } +>{ values: [{ key: "a" }, { key: "b" }, { key: "c" }], identifier: v => Number(v.key) } : any values: [{ key: "a" }, { key: "b" }, { key: "c" }], >values : { key: string; }[] diff --git a/testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.errors.txt index 9f7e3c33325..49820d3d452 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.errors.txt +++ b/testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.errors.txt @@ -1,9 +1,4 @@ -quantifiedTypesNormalizedShapes.ts(9,5): error TS2322: Type '{ a: { id: "a"; color: string; }; b: { id: "a"; color: string; }; }' is not assignable to type '{ a: Omit & { id: "a"; }; b: Omit & { id: "b"; }; }'. - Types of property 'b' are incompatible. - Type '{ id: "a"; color: string; }' is not assignable to type 'Omit & { id: "b"; }'. - Type '{ id: "a"; color: string; }' is not assignable to type '{ id: "b"; }'. - Types of property 'id' are incompatible. - Type '"a"' is not assignable to type '"b"'. +quantifiedTypesNormalizedShapes.ts(15,5): error TS2322: Type '"a"' is not assignable to type '"b"'. ==== quantifiedTypesNormalizedShapes.ts (1 errors) ==== @@ -16,19 +11,15 @@ quantifiedTypesNormalizedShapes.ts(9,5): error TS2322: Type '{ a: { id: "a"; col } let layers: NormalizedRecord = { - ~~~~~~ -!!! error TS2322: Type '{ a: { id: "a"; color: string; }; b: { id: "a"; color: string; }; }' is not assignable to type '{ a: Omit & { id: "a"; }; b: Omit & { id: "b"; }; }'. -!!! error TS2322: Types of property 'b' are incompatible. -!!! error TS2322: Type '{ id: "a"; color: string; }' is not assignable to type 'Omit & { id: "b"; }'. -!!! error TS2322: Type '{ id: "a"; color: string; }' is not assignable to type '{ id: "b"; }'. -!!! error TS2322: Types of property 'id' are incompatible. -!!! error TS2322: Type '"a"' is not assignable to type '"b"'. a: { id: "a", color: "green" }, b: { id: "a", // should have been "b" + ~~ +!!! error TS2322: Type '"a"' is not assignable to type '"b"'. +!!! related TS6500 quantifiedTypesNormalizedShapes.ts:2:54: The expected type comes from property 'id' which is declared here on type 'Omit & { id: "b"; }' color: "blue" } } diff --git a/testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.types b/testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.types index 7e2c259a0ec..a056d39039d 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.types +++ b/testdata/baselines/reference/compiler/quantifiedTypesNormalizedShapes.types @@ -18,7 +18,7 @@ interface Layer { let layers: NormalizedRecord = { >layers : { [K in Id]: Omit & { id: K; }; } ->{ a: { id: "a", color: "green" }, b: { id: "a", // should have been "b" color: "blue" }} : { a: { id: "a"; color: string; }; b: { id: "a"; color: string; }; } +>{ a: { id: "a", color: "green" }, b: { id: "a", // should have been "b" color: "blue" }} : any a: { >a : { id: string; color: string; } diff --git a/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.errors.txt index 6dfb104ba1f..7eb9c7328aa 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.errors.txt +++ b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.errors.txt @@ -1,4 +1,4 @@ -quantifiedTypesSelfTypesCaseInsensitve.ts(16,11): error TS2345: Argument of type '"Acept"' is not assignable to parameter of type '"Error: Type 'Acept' is not assignable to type 'CaseInsensitive'" | "Error: Type 'Acept' is not assignable to type 'CaseInsensitive'"'. +quantifiedTypesSelfTypesCaseInsensitve.ts(16,11): error TS2322: Type '"Acept"' is not assignable to type '"Error: Type 'Acept' is not assignable to type 'CaseInsensitive'" | "Error: Type 'Acept' is not assignable to type 'CaseInsensitive'"'. ==== quantifiedTypesSelfTypesCaseInsensitve.ts (1 errors) ==== @@ -19,4 +19,4 @@ quantifiedTypesSelfTypesCaseInsensitve.ts(16,11): error TS2345: Argument of type setHeader("sEt-cOoKiE", "stop writing headers like this but ok") setHeader("Acept", "nah this has a typo") ~~~~~~~ -!!! error TS2345: Argument of type '"Acept"' is not assignable to parameter of type '"Error: Type 'Acept' is not assignable to type 'CaseInsensitive'" | "Error: Type 'Acept' is not assignable to type 'CaseInsensitive'"'. \ No newline at end of file +!!! error TS2322: Type '"Acept"' is not assignable to type '"Error: Type 'Acept' is not assignable to type 'CaseInsensitive'" | "Error: Type 'Acept' is not assignable to type 'CaseInsensitive'"'. \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.types b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.types index 393ffb003cc..81fd7caee91 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.types +++ b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesCaseInsensitve.types @@ -41,6 +41,6 @@ setHeader("sEt-cOoKiE", "stop writing headers like this but ok") setHeader("Acept", "nah this has a typo") >setHeader("Acept", "nah this has a typo") : void >setHeader : (key: PasreCaseInsensitive, value: string) => void ->"Acept" : "Acept" +>"Acept" : any >"nah this has a typo" : "nah this has a typo" diff --git a/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.errors.txt index 71ba0c99c88..6332d611080 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.errors.txt +++ b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.errors.txt @@ -1,6 +1,4 @@ -quantifiedTypesSelfTypesStateMachine.ts(22,5): error TS2322: Type '{ off: { ON: "red"; }; red: { TICK: "yellow"; OFF: "off"; }; yellow: { TICK: "green"; OFF: "off"; }; green: { TICK: "reddd"; OFF: "off"; }; }' is not assignable to type 'ParseStateMachine<{ off: { ON: "red"; }; red: { TICK: "yellow"; OFF: "off"; }; yellow: { TICK: "green"; OFF: "off"; }; green: { TICK: "reddd"; OFF: "off"; }; }>'. - The types of 'green.TICK' are incompatible between these types. - Type '"reddd"' is not assignable to type '"green" | "off" | "red" | "yellow"'. Did you mean '"red"'? +quantifiedTypesSelfTypesStateMachine.ts(35,5): error TS2820: Type '"reddd"' is not assignable to type '"green" | "off" | "red" | "yellow"'. Did you mean '"red"'? ==== quantifiedTypesSelfTypesStateMachine.ts (1 errors) ==== @@ -26,10 +24,6 @@ quantifiedTypesSelfTypesStateMachine.ts(22,5): error TS2322: Type '{ off: { ON: } let trafficLightsInvalid: StateMachine = { - ~~~~~~~~~~~~~~~~~~~~ -!!! error TS2322: Type '{ off: { ON: "red"; }; red: { TICK: "yellow"; OFF: "off"; }; yellow: { TICK: "green"; OFF: "off"; }; green: { TICK: "reddd"; OFF: "off"; }; }' is not assignable to type 'ParseStateMachine<{ off: { ON: "red"; }; red: { TICK: "yellow"; OFF: "off"; }; yellow: { TICK: "green"; OFF: "off"; }; green: { TICK: "reddd"; OFF: "off"; }; }>'. -!!! error TS2322: The types of 'green.TICK' are incompatible between these types. -!!! error TS2322: Type '"reddd"' is not assignable to type '"green" | "off" | "red" | "yellow"'. Did you mean '"red"'? off: { ON: "red" }, @@ -43,6 +37,9 @@ quantifiedTypesSelfTypesStateMachine.ts(22,5): error TS2322: Type '{ off: { ON: }, green: { TICK: "reddd", + ~~~~ +!!! error TS2820: Type '"reddd"' is not assignable to type '"green" | "off" | "red" | "yellow"'. Did you mean '"red"'? +!!! related TS6500 quantifiedTypesSelfTypesStateMachine.ts:35:5: The expected type comes from property 'TICK' which is declared here on type '{ TICK: "green" | "off" | "red" | "yellow"; OFF: "green" | "off" | "red" | "yellow"; }' OFF: "off" } } \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.types b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.types index 5cab18f8733..59bd1d8cb9b 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.types +++ b/testdata/baselines/reference/compiler/quantifiedTypesSelfTypesStateMachine.types @@ -12,103 +12,103 @@ let trafficLights: StateMachine = { >{ off: { ON: "red" }, red: { TICK: "yellow", OFF: "off" }, yellow: { TICK: "green", OFF: "off" }, green: { TICK: "red", OFF: "off" }} : { off: { ON: "red"; }; red: { TICK: "yellow"; OFF: "off"; }; yellow: { TICK: "green"; OFF: "off"; }; green: { TICK: "red"; OFF: "off"; }; } off: { ->off : { ON: "red"; } ->{ ON: "red" } : { ON: "red"; } +>off : { ON: string; } +>{ ON: "red" } : { ON: string; } ON: "red" ->ON : "red" +>ON : string >"red" : "red" }, red: { ->red : { TICK: "yellow"; OFF: "off"; } ->{ TICK: "yellow", OFF: "off" } : { TICK: "yellow"; OFF: "off"; } +>red : { TICK: string; OFF: string; } +>{ TICK: "yellow", OFF: "off" } : { TICK: string; OFF: string; } TICK: "yellow", ->TICK : "yellow" +>TICK : string >"yellow" : "yellow" OFF: "off" ->OFF : "off" +>OFF : string >"off" : "off" }, yellow: { ->yellow : { TICK: "green"; OFF: "off"; } ->{ TICK: "green", OFF: "off" } : { TICK: "green"; OFF: "off"; } +>yellow : { TICK: string; OFF: string; } +>{ TICK: "green", OFF: "off" } : { TICK: string; OFF: string; } TICK: "green", ->TICK : "green" +>TICK : string >"green" : "green" OFF: "off" ->OFF : "off" +>OFF : string >"off" : "off" }, green: { ->green : { TICK: "red"; OFF: "off"; } ->{ TICK: "red", OFF: "off" } : { TICK: "red"; OFF: "off"; } +>green : { TICK: string; OFF: string; } +>{ TICK: "red", OFF: "off" } : { TICK: string; OFF: string; } TICK: "red", ->TICK : "red" +>TICK : string >"red" : "red" OFF: "off" ->OFF : "off" +>OFF : string >"off" : "off" } } let trafficLightsInvalid: StateMachine = { >trafficLightsInvalid : > Self ->{ off: { ON: "red" }, red: { TICK: "yellow", OFF: "off" }, yellow: { TICK: "green", OFF: "off" }, green: { TICK: "reddd", OFF: "off" }} : { off: { ON: "red"; }; red: { TICK: "yellow"; OFF: "off"; }; yellow: { TICK: "green"; OFF: "off"; }; green: { TICK: "reddd"; OFF: "off"; }; } +>{ off: { ON: "red" }, red: { TICK: "yellow", OFF: "off" }, yellow: { TICK: "green", OFF: "off" }, green: { TICK: "reddd", OFF: "off" }} : any off: { ->off : { ON: "red"; } ->{ ON: "red" } : { ON: "red"; } +>off : { ON: string; } +>{ ON: "red" } : { ON: string; } ON: "red" ->ON : "red" +>ON : string >"red" : "red" }, red: { ->red : { TICK: "yellow"; OFF: "off"; } ->{ TICK: "yellow", OFF: "off" } : { TICK: "yellow"; OFF: "off"; } +>red : { TICK: string; OFF: string; } +>{ TICK: "yellow", OFF: "off" } : { TICK: string; OFF: string; } TICK: "yellow", ->TICK : "yellow" +>TICK : string >"yellow" : "yellow" OFF: "off" ->OFF : "off" +>OFF : string >"off" : "off" }, yellow: { ->yellow : { TICK: "green"; OFF: "off"; } ->{ TICK: "green", OFF: "off" } : { TICK: "green"; OFF: "off"; } +>yellow : { TICK: string; OFF: string; } +>{ TICK: "green", OFF: "off" } : { TICK: string; OFF: string; } TICK: "green", ->TICK : "green" +>TICK : string >"green" : "green" OFF: "off" ->OFF : "off" +>OFF : string >"off" : "off" }, green: { ->green : { TICK: "reddd"; OFF: "off"; } ->{ TICK: "reddd", OFF: "off" } : { TICK: "reddd"; OFF: "off"; } +>green : { TICK: string; OFF: string; } +>{ TICK: "reddd", OFF: "off" } : { TICK: string; OFF: string; } TICK: "reddd", ->TICK : "reddd" +>TICK : string >"reddd" : "reddd" OFF: "off" ->OFF : "off" +>OFF : string >"off" : "off" } } diff --git a/testdata/tests/cases/compiler/quantifiedTypesAdvanced.ts b/testdata/tests/cases/compiler/quantifiedTypesAdvanced.ts new file mode 100644 index 00000000000..56c71fd147b --- /dev/null +++ b/testdata/tests/cases/compiler/quantifiedTypesAdvanced.ts @@ -0,0 +1,24 @@ +declare const f: + { a: A, ab: (a: A) => B, bc?: (b: B) => C })[]>(a: [...T]) => + { [K in keyof T]: T[K] extends { bc: (...a: never) => infer C } ? C : "lol" } + +let t0 = f([ + { + a: "0", + ab: a => +a, + bc: b => typeof b === "number" + }, + { + a: "hello", + ab: a => a + " world", + bc: b => { + b satisfies string + return +b + } + }, + { + a: 42, + ab: a => a.toString() + } +]) + From 6318b2f1b3e4dbabeb9ff9a1aa98d7fb8b82561c Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Tue, 6 Jan 2026 21:05:50 +0530 Subject: [PATCH 05/23] tweak relater to handle unions --- internal/checker/relater.go | 56 ++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/internal/checker/relater.go b/internal/checker/relater.go index 28d74c049ce..d75c13cdf26 100644 --- a/internal/checker/relater.go +++ b/internal/checker/relater.go @@ -172,14 +172,26 @@ func (c *Checker) isTypeRelatedTo(source *Type, target *Type, relation *Relation if source.flags&TypeFlagsQuantified != 0 { return source == target } - ctx := c.newInferenceContext( - core.Map(target.AsQuantifiedType().typeParameters, func(t *TypeParameter) *Type { return t.AsType() }), - nil, - InferenceFlagsNone, - nil, - ) - c.inferTypes(ctx.inferences, source, target.AsQuantifiedType().baseType, InferencePriorityNoConstraints|InferencePriorityAlwaysStrict, false) - return c.isTypeRelatedTo(source, c.instantiateType(target.AsQuantifiedType().baseType, ctx.mapper), relation) + baseType := target.AsQuantifiedType().baseType + typeParameters := core.Map(target.AsQuantifiedType().typeParameters, func(t *TypeParameter) *Type { return t.AsType() }) + + if source.flags&TypeFlagsUnion == 0 { + inferenceContext := c.newInferenceContext(typeParameters, nil, InferenceFlagsNone, nil) + c.inferTypes(inferenceContext.inferences, source, baseType, InferencePriorityNone, false) + return c.isTypeRelatedTo(source, c.instantiateType(baseType, inferenceContext.mapper), relation) + } + + for _, sourceMember := range source.AsUnionType().types { + inferenceContext := c.newInferenceContext(typeParameters, nil, InferenceFlagsNone, nil) + c.inferTypes(inferenceContext.inferences, sourceMember, baseType, InferencePriorityNone, false) + result := c.isTypeRelatedTo(sourceMember, c.instantiateType(baseType, inferenceContext.mapper), relation) + if result { + continue + } + return result + } + + return true } if isFreshLiteralType(source) { source = source.AsLiteralType().regularType @@ -2570,14 +2582,26 @@ func (r *Relater) isRelatedToEx(originalSource *Type, originalTarget *Type, recu if originalSource.flags&TypeFlagsQuantified != 0 && originalSource == originalTarget { return TernaryTrue } - ctx := r.c.newInferenceContext( - core.Map(originalTarget.AsQuantifiedType().typeParameters, func(t *TypeParameter) *Type { return t.AsType() }), - nil, - InferenceFlagsNone, - nil, - ) - r.c.inferTypes(ctx.inferences, originalSource, originalTarget.AsQuantifiedType().baseType, InferencePriorityNoConstraints|InferencePriorityAlwaysStrict, false) - return r.isRelatedToEx(originalSource, r.c.instantiateType(originalTarget.AsQuantifiedType().baseType, ctx.mapper), recursionFlags, reportErrors, headMessage, intersectionState) + baseType := originalTarget.AsQuantifiedType().baseType + typeParameters := core.Map(originalTarget.AsQuantifiedType().typeParameters, func(t *TypeParameter) *Type { return t.AsType() }) + + if originalSource.flags&TypeFlagsUnion == 0 { + inferenceContext := r.c.newInferenceContext(typeParameters, nil, InferenceFlagsNone, nil) + r.c.inferTypes(inferenceContext.inferences, originalSource, baseType, InferencePriorityNone, false) + return r.isRelatedToEx(originalSource, r.c.instantiateType(baseType, inferenceContext.mapper), recursionFlags, reportErrors, headMessage, intersectionState) + } + + for _, originalSourceMember := range originalSource.AsUnionType().types { + inferenceContext := r.c.newInferenceContext(typeParameters, nil, InferenceFlagsNone, nil) + r.c.inferTypes(inferenceContext.inferences, originalSourceMember, baseType, InferencePriorityNone, false) + result := r.isRelatedToEx(originalSourceMember, r.c.instantiateType(baseType, inferenceContext.mapper), recursionFlags, reportErrors, headMessage, intersectionState) + if result == TernaryTrue { + continue + } + return result + } + + return TernaryTrue } if originalSource == originalTarget { From ecb3fe3a834d3b775b8a155d917bc73715065b7a Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Tue, 6 Jan 2026 23:38:18 +0530 Subject: [PATCH 06/23] fix bad test commit --- .../cases/compiler/quantifiedTypesAdvanced.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/testdata/tests/cases/compiler/quantifiedTypesAdvanced.ts b/testdata/tests/cases/compiler/quantifiedTypesAdvanced.ts index 56c71fd147b..d3ecd39e6d2 100644 --- a/testdata/tests/cases/compiler/quantifiedTypesAdvanced.ts +++ b/testdata/tests/cases/compiler/quantifiedTypesAdvanced.ts @@ -22,3 +22,17 @@ let t0 = f([ } ]) + +let t1 = f([ + { + a: true, + ab: a => +a, + bc: b => typeof b === "number" + }, + { + a: "hello", + ab: a => a + " world", + bc: b => +b, + extra: "foo" // TODO: an extra property should be allowed + } +]) \ No newline at end of file From 13eaee4aacad16926ca892734ed3c9c8ddeee9f8 Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Sat, 10 Jan 2026 15:19:11 +0530 Subject: [PATCH 07/23] preserve parent inference context --- internal/checker/checker.go | 35 +++++++++++++------ internal/printer/printer.go | 1 + .../quantifiedTypesParentInferenceContext.js | 9 +++++ ...ntifiedTypesParentInferenceContext.symbols | 17 +++++++++ ...uantifiedTypesParentInferenceContext.types | 17 +++++++++ .../quantifiedTypesParentInferenceContext2.js | 8 +++++ ...tifiedTypesParentInferenceContext2.symbols | 17 +++++++++ ...antifiedTypesParentInferenceContext2.types | 17 +++++++++ .../quantifiedTypesParentInferenceContext.ts | 2 ++ .../quantifiedTypesParentInferenceContext2.ts | 2 ++ 10 files changed, 115 insertions(+), 10 deletions(-) create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext.js create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext.symbols create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext.types create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext2.js create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext2.symbols create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext2.types create mode 100644 testdata/tests/cases/compiler/quantifiedTypesParentInferenceContext.ts create mode 100644 testdata/tests/cases/compiler/quantifiedTypesParentInferenceContext2.ts diff --git a/internal/checker/checker.go b/internal/checker/checker.go index 48811de6078..8893eb11635 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -44,8 +44,9 @@ const ( CheckModeRestBindingElement CheckMode = 1 << 5 // Checking a type that is going to be used to determine the type of a rest binding element // e.g. in `const { a, ...rest } = foo`, when checking the type of `foo` to determine the type of `rest`, // we need to preserve generic types instead of substituting them for constraints - CheckModeTypeOnly CheckMode = 1 << 6 // Called from getTypeOfExpression, diagnostics may be omitted - CheckModeForceTuple CheckMode = 1 << 7 + CheckModeTypeOnly CheckMode = 1 << 6 // Called from getTypeOfExpression, diagnostics may be omitted + CheckModeForceTuple CheckMode = 1 << 7 + CheckModeQuantifiedContextual CheckMode = 1 << 8 ) type TypeSystemEntity any @@ -7247,7 +7248,7 @@ func (c *Checker) reportObjectPossiblyNullOrUndefinedError(node *ast.Node, facts func (c *Checker) checkExpressionWithContextualType(node *ast.Node, contextualType *Type, inferenceContext *InferenceContext, checkMode CheckMode) *Type { if contextualType.flags&TypeFlagsQuantified != 0 { - return c.checkExpressionExWithContextualType(node, checkMode, contextualType) + return c.checkExpressionExWithContextualType(node, checkMode, contextualType, inferenceContext) } contextNode := c.getContextNode(node) c.pushContextualType(contextNode, contextualType, false /*isCache*/) @@ -7322,42 +7323,56 @@ func (c *Checker) checkExpression(node *ast.Node) *Type { } func (c *Checker) checkExpressionEx(node *ast.Node, checkMode CheckMode) *Type { - return c.checkExpressionExWithContextualType(node, checkMode, nil) + return c.checkExpressionExWithContextualType(node, checkMode, nil, nil) } -func (c *Checker) checkExpressionExWithContextualType(node *ast.Node, checkMode CheckMode, contextualType *Type) *Type { +// we now have too many checkExpression* functions and it's a bit of a spagetti so maybe there is a better way to do this +// but it's done this way to reduce the number of locations where a change has to be made for quantified types +func (c *Checker) checkExpressionExWithContextualType(node *ast.Node, checkMode CheckMode, contextualType *Type, parentInferenceContext *InferenceContext) *Type { if node.Kind == ast.KindIdentifier { // to avoid recursion in some jsx test cases TODO: come up with a better fix return c.checkExpressionExWorker(node, checkMode) } if contextualType == nil { contextualType = c.getApparentTypeOfContextualType(node, ContextFlagsNone) } + if parentInferenceContext == nil { + parentInferenceContext = c.getInferenceContext(node) + } isAlreadyContextuallyChecking := c.contextualInfos != nil && core.Some(c.contextualInfos, func(info ContextualInfo) bool { return info.node == node }) if contextualType == nil || contextualType.flags&TypeFlagsQuantified == 0 || isAlreadyContextuallyChecking { return c.checkExpressionExWorker(node, checkMode) } baseType := contextualType.AsQuantifiedType().baseType + if parentInferenceContext != nil { + baseType = c.instantiateType(baseType, parentInferenceContext.mapper) + } typeParameters := core.Map(contextualType.AsQuantifiedType().typeParameters, func(tp *TypeParameter) *Type { return tp.AsType() }) // context sensitive // TODO: this is not needed if the node is not context sensitive inferenceContext := c.newInferenceContext(typeParameters, nil, InferenceFlagsNone, nil) - t := c.checkExpressionWithContextualType(node, baseType, inferenceContext, checkMode|CheckModeSkipContextSensitive) + if parentInferenceContext != nil { + // probably a bad way to comvine inference contexts but works + inferenceContext.nonFixingMapper = c.combineTypeMappers(inferenceContext.nonFixingMapper, parentInferenceContext.nonFixingMapper) + inferenceContext.mapper = c.combineTypeMappers(inferenceContext.mapper, parentInferenceContext.mapper) + } + t := c.checkExpressionWithContextualType(node, baseType, inferenceContext, checkMode|CheckModeSkipContextSensitive|CheckModeQuantifiedContextual) c.inferTypes(inferenceContext.inferences, t, baseType, InferencePriorityNone, false) typeArguments := c.instantiateTypes(typeParameters, inferenceContext.nonFixingMapper) // normal - t = c.checkExpressionWithContextualType(node, baseType, inferenceContext, CheckModeNormal) + t = c.checkExpressionWithContextualType(node, baseType, inferenceContext, CheckModeNormal|CheckModeQuantifiedContextual) c.inferTypes(inferenceContext.inferences, t, baseType, InferencePriorityNone, false) typeArguments = c.instantiateTypes(typeParameters, inferenceContext.mapper) // final baseTypeInferred := c.instantiateType(baseType, newTypeMapper(typeParameters, typeArguments)) - t = c.checkExpressionWithContextualType(node, baseTypeInferred, nil, CheckModeNormal) + t = c.checkExpressionWithContextualType(node, baseTypeInferred, core.IfElse(parentInferenceContext != nil, parentInferenceContext, nil), CheckModeNormal|CheckModeQuantifiedContextual) if !c.checkTypeRelatedToAndOptionallyElaborate(t, baseTypeInferred, c.assignableRelation, node, node, nil, nil) { return c.errorType // to avoid showing errors in parent TODO: maybe there is a better way to do this } + return t } @@ -9980,12 +9995,12 @@ func (c *Checker) checkFunctionExpressionOrObjectLiteralMethod(node *ast.Node, c func (c *Checker) contextuallyCheckFunctionExpressionOrObjectLiteralMethod(node *ast.Node, checkMode CheckMode) { links := c.nodeLinks.Get(node) // Check if function expression is contextually typed and assign parameter types if so. - if links.flags&NodeCheckFlagsContextChecked == 0 { + if links.flags&NodeCheckFlagsContextChecked == 0 || checkMode&CheckModeQuantifiedContextual != 0 { contextualSignature := c.getContextualSignature(node) // If a type check is started at a function expression that is an argument of a function call, obtaining the // contextual type may recursively get back to here during overload resolution of the call. If so, we will have // already assigned contextual types. - if links.flags&NodeCheckFlagsContextChecked == 0 { + if links.flags&NodeCheckFlagsContextChecked == 0 || checkMode&CheckModeQuantifiedContextual != 0 { links.flags |= NodeCheckFlagsContextChecked signature := core.FirstOrNil(c.getSignaturesOfType(c.getTypeOfSymbol(c.getSymbolOfDeclaration(node)), SignatureKindCall)) if signature == nil { diff --git a/internal/printer/printer.go b/internal/printer/printer.go index 8b37ec0d9b5..b21646cfc46 100644 --- a/internal/printer/printer.go +++ b/internal/printer/printer.go @@ -2186,6 +2186,7 @@ func (p *Printer) emitQuantifiedTypeNpde(node *ast.QuantifiedTypeNode) { state := p.enterNode(node.AsNode()) p.emitTypeParameters(node.AsNode(), node.TypeParameters) p.writeSpace() + // TODO: print parenthesis if BaseType is a function p.emitTypeNode(node.BaseType, ast.TypePrecedenceConditional) p.exitNode(node.AsNode(), state) } diff --git a/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext.js b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext.js new file mode 100644 index 00000000000..3a786df7987 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext.js @@ -0,0 +1,9 @@ +//// [tests/cases/compiler/quantifiedTypesParentInferenceContext.ts] //// + +//// [quantifiedTypesParentInferenceContext.ts] +declare const f: (a: A, f: [(a: A) => void]) => void +f(0, [a => {}]) + + +//// [quantifiedTypesParentInferenceContext.js] +f(0, [a => { }]); diff --git a/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext.symbols b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext.symbols new file mode 100644 index 00000000000..0a7a9c737a7 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext.symbols @@ -0,0 +1,17 @@ +//// [tests/cases/compiler/quantifiedTypesParentInferenceContext.ts] //// + +=== quantifiedTypesParentInferenceContext.ts === +declare const f: (a: A, f: [(a: A) => void]) => void +>f : Symbol(f, Decl(quantifiedTypesParentInferenceContext.ts, 0, 13)) +>A : Symbol(A, Decl(quantifiedTypesParentInferenceContext.ts, 0, 18)) +>a : Symbol(a, Decl(quantifiedTypesParentInferenceContext.ts, 0, 21)) +>A : Symbol(A, Decl(quantifiedTypesParentInferenceContext.ts, 0, 18)) +>f : Symbol(f, Decl(quantifiedTypesParentInferenceContext.ts, 0, 26)) +>T : Symbol(T, Decl(quantifiedTypesParentInferenceContext.ts, 0, 31)) +>a : Symbol(a, Decl(quantifiedTypesParentInferenceContext.ts, 0, 36)) +>A : Symbol(A, Decl(quantifiedTypesParentInferenceContext.ts, 0, 18)) + +f(0, [a => {}]) +>f : Symbol(f, Decl(quantifiedTypesParentInferenceContext.ts, 0, 13)) +>a : Symbol(a, Decl(quantifiedTypesParentInferenceContext.ts, 1, 6)) + diff --git a/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext.types b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext.types new file mode 100644 index 00000000000..4dd5c97fed2 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext.types @@ -0,0 +1,17 @@ +//// [tests/cases/compiler/quantifiedTypesParentInferenceContext.ts] //// + +=== quantifiedTypesParentInferenceContext.ts === +declare const f: (a: A, f: [(a: A) => void]) => void +>f : (a: A, f: [(a: A) => void]) => void +>a : A +>f : [(a: A) => void] +>a : A + +f(0, [a => {}]) +>f(0, [a => {}]) : void +>f : (a: A, f: [(a: A) => void]) => void +>0 : 0 +>[a => {}] : [(a: number) => void] +>a => {} : (a: number) => void +>a : number + diff --git a/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext2.js b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext2.js new file mode 100644 index 00000000000..298ef126339 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext2.js @@ -0,0 +1,8 @@ +//// [tests/cases/compiler/quantifiedTypesParentInferenceContext2.ts] //// + +//// [quantifiedTypesParentInferenceContext2.ts] +declare const f: (a: A, f: [ ((a: A) => void)]) => void +f(0, [a => {}]) + +//// [quantifiedTypesParentInferenceContext2.js] +f(0, [a => { }]); diff --git a/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext2.symbols b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext2.symbols new file mode 100644 index 00000000000..b65ea49e8bf --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext2.symbols @@ -0,0 +1,17 @@ +//// [tests/cases/compiler/quantifiedTypesParentInferenceContext2.ts] //// + +=== quantifiedTypesParentInferenceContext2.ts === +declare const f: (a: A, f: [ ((a: A) => void)]) => void +>f : Symbol(f, Decl(quantifiedTypesParentInferenceContext2.ts, 0, 13)) +>A : Symbol(A, Decl(quantifiedTypesParentInferenceContext2.ts, 0, 18)) +>a : Symbol(a, Decl(quantifiedTypesParentInferenceContext2.ts, 0, 21)) +>A : Symbol(A, Decl(quantifiedTypesParentInferenceContext2.ts, 0, 18)) +>f : Symbol(f, Decl(quantifiedTypesParentInferenceContext2.ts, 0, 26)) +>T : Symbol(T, Decl(quantifiedTypesParentInferenceContext2.ts, 0, 32)) +>a : Symbol(a, Decl(quantifiedTypesParentInferenceContext2.ts, 0, 37)) +>A : Symbol(A, Decl(quantifiedTypesParentInferenceContext2.ts, 0, 18)) + +f(0, [a => {}]) +>f : Symbol(f, Decl(quantifiedTypesParentInferenceContext2.ts, 0, 13)) +>a : Symbol(a, Decl(quantifiedTypesParentInferenceContext2.ts, 1, 6)) + diff --git a/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext2.types b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext2.types new file mode 100644 index 00000000000..2ce8c87df19 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext2.types @@ -0,0 +1,17 @@ +//// [tests/cases/compiler/quantifiedTypesParentInferenceContext2.ts] //// + +=== quantifiedTypesParentInferenceContext2.ts === +declare const f: (a: A, f: [ ((a: A) => void)]) => void +>f : (a: A, f: [ (a: A) => void]) => void +>a : A +>f : [ (a: A) => void] +>a : A + +f(0, [a => {}]) +>f(0, [a => {}]) : void +>f : (a: A, f: [ (a: A) => void]) => void +>0 : 0 +>[a => {}] : [(a: number) => void] +>a => {} : (a: number) => void +>a : number + diff --git a/testdata/tests/cases/compiler/quantifiedTypesParentInferenceContext.ts b/testdata/tests/cases/compiler/quantifiedTypesParentInferenceContext.ts new file mode 100644 index 00000000000..3fba34c1f1a --- /dev/null +++ b/testdata/tests/cases/compiler/quantifiedTypesParentInferenceContext.ts @@ -0,0 +1,2 @@ +declare const f: (a: A, f: [(a: A) => void]) => void +f(0, [a => {}]) diff --git a/testdata/tests/cases/compiler/quantifiedTypesParentInferenceContext2.ts b/testdata/tests/cases/compiler/quantifiedTypesParentInferenceContext2.ts new file mode 100644 index 00000000000..ec538b5d506 --- /dev/null +++ b/testdata/tests/cases/compiler/quantifiedTypesParentInferenceContext2.ts @@ -0,0 +1,2 @@ +declare const f: (a: A, f: [ ((a: A) => void)]) => void +f(0, [a => {}]) \ No newline at end of file From 63729c4aae1807fe7665b26d4084743ec4801e05 Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Sat, 10 Jan 2026 21:04:34 +0530 Subject: [PATCH 08/23] more parent contextual inference --- internal/checker/checker.go | 19 ++++++++------- .../compiler/quantifiedTypesAdvanced.types | 10 ++++---- .../quantifiedTypesParentInferenceContext3.js | 9 ++++++++ ...tifiedTypesParentInferenceContext3.symbols | 21 +++++++++++++++++ ...antifiedTypesParentInferenceContext3.types | 23 +++++++++++++++++++ .../quantifiedTypesParentInferenceContext3.ts | 2 ++ 6 files changed, 71 insertions(+), 13 deletions(-) create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext3.js create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext3.symbols create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext3.types create mode 100644 testdata/tests/cases/compiler/quantifiedTypesParentInferenceContext3.ts diff --git a/internal/checker/checker.go b/internal/checker/checker.go index 8893eb11635..fc0b358c6b9 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -7328,9 +7328,9 @@ func (c *Checker) checkExpressionEx(node *ast.Node, checkMode CheckMode) *Type { // we now have too many checkExpression* functions and it's a bit of a spagetti so maybe there is a better way to do this // but it's done this way to reduce the number of locations where a change has to be made for quantified types -func (c *Checker) checkExpressionExWithContextualType(node *ast.Node, checkMode CheckMode, contextualType *Type, parentInferenceContext *InferenceContext) *Type { +func (c *Checker) checkExpressionExWithContextualType(node *ast.Node, parentCheckMode CheckMode, contextualType *Type, parentInferenceContext *InferenceContext) *Type { if node.Kind == ast.KindIdentifier { // to avoid recursion in some jsx test cases TODO: come up with a better fix - return c.checkExpressionExWorker(node, checkMode) + return c.checkExpressionExWorker(node, parentCheckMode) } if contextualType == nil { contextualType = c.getApparentTypeOfContextualType(node, ContextFlagsNone) @@ -7340,11 +7340,11 @@ func (c *Checker) checkExpressionExWithContextualType(node *ast.Node, checkMode } isAlreadyContextuallyChecking := c.contextualInfos != nil && core.Some(c.contextualInfos, func(info ContextualInfo) bool { return info.node == node }) if contextualType == nil || contextualType.flags&TypeFlagsQuantified == 0 || isAlreadyContextuallyChecking { - return c.checkExpressionExWorker(node, checkMode) + return c.checkExpressionExWorker(node, parentCheckMode) } baseType := contextualType.AsQuantifiedType().baseType if parentInferenceContext != nil { - baseType = c.instantiateType(baseType, parentInferenceContext.mapper) + baseType = c.instantiateType(baseType, parentInferenceContext.nonFixingMapper) } typeParameters := core.Map(contextualType.AsQuantifiedType().typeParameters, func(tp *TypeParameter) *Type { return tp.AsType() }) @@ -7356,7 +7356,10 @@ func (c *Checker) checkExpressionExWithContextualType(node *ast.Node, checkMode inferenceContext.nonFixingMapper = c.combineTypeMappers(inferenceContext.nonFixingMapper, parentInferenceContext.nonFixingMapper) inferenceContext.mapper = c.combineTypeMappers(inferenceContext.mapper, parentInferenceContext.mapper) } - t := c.checkExpressionWithContextualType(node, baseType, inferenceContext, checkMode|CheckModeSkipContextSensitive|CheckModeQuantifiedContextual) + t := c.checkExpressionWithContextualType(node, baseType, inferenceContext, parentCheckMode|CheckModeSkipContextSensitive|CheckModeQuantifiedContextual) + if t.objectFlags&ObjectFlagsNonInferrableType != 0 && parentCheckMode&CheckModeSkipContextSensitive != 0 { + return t + } c.inferTypes(inferenceContext.inferences, t, baseType, InferencePriorityNone, false) typeArguments := c.instantiateTypes(typeParameters, inferenceContext.nonFixingMapper) @@ -7366,10 +7369,10 @@ func (c *Checker) checkExpressionExWithContextualType(node *ast.Node, checkMode typeArguments = c.instantiateTypes(typeParameters, inferenceContext.mapper) // final - baseTypeInferred := c.instantiateType(baseType, newTypeMapper(typeParameters, typeArguments)) - t = c.checkExpressionWithContextualType(node, baseTypeInferred, core.IfElse(parentInferenceContext != nil, parentInferenceContext, nil), CheckModeNormal|CheckModeQuantifiedContextual) + baseType = c.instantiateType(baseType, newTypeMapper(typeParameters, typeArguments)) + t = c.checkExpressionWithContextualType(node, baseType, core.IfElse(parentInferenceContext != nil, parentInferenceContext, nil), CheckModeNormal|CheckModeQuantifiedContextual) - if !c.checkTypeRelatedToAndOptionallyElaborate(t, baseTypeInferred, c.assignableRelation, node, node, nil, nil) { + if !c.checkTypeRelatedToAndOptionallyElaborate(t, baseType, c.assignableRelation, node, node, nil, nil) { return c.errorType // to avoid showing errors in parent TODO: maybe there is a better way to do this } diff --git a/testdata/baselines/reference/compiler/quantifiedTypesAdvanced.types b/testdata/baselines/reference/compiler/quantifiedTypesAdvanced.types index 4eb2f83c337..b7d1ffad49d 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesAdvanced.types +++ b/testdata/baselines/reference/compiler/quantifiedTypesAdvanced.types @@ -94,12 +94,12 @@ let t0 = f([ let t1 = f([ ->t1 : any ->f([ { a: true, ab: a => +a, bc: b => typeof b === "number" }, { a: "hello", ab: a => a + " world", bc: b => +b, extra: "foo" // TODO: an extra property should be allowed }]) : any +>t1 : (( { a: A; ab: (a: A) => B; bc?: (b: B) => C; }) extends { bc: (...a: never) => infer C_1; } ? C_1 : "lol")[] +>f([ { a: true, ab: a => +a, bc: b => typeof b === "number" }, { a: "hello", ab: a => a + " world", bc: b => +b, extra: "foo" // TODO: an extra property should be allowed }]) : (( { a: A; ab: (a: A) => B; bc?: (b: B) => C; }) extends { bc: (...a: never) => infer C_1; } ? C_1 : "lol")[] >f : { a: A; ab: (a: A) => B; bc?: (b: B) => C; })[]>(a: [...T]) => { [K in keyof T]: T[K] extends { bc: (...a: never) => infer C_1; } ? C_1 : "lol"; } ->[ { a: true, ab: a => +a, bc: b => typeof b === "number" }, { a: "hello", ab: a => a + " world", bc: b => +b, extra: "foo" // TODO: an extra property should be allowed }] : [{ a: boolean; ab: (a: string | number) => number; bc: (b: number) => boolean; }, { a: string; ab: (a: "hello") => string; bc: (b: string) => number; extra: string; }] +>[ { a: true, ab: a => +a, bc: b => typeof b === "number" }, { a: "hello", ab: a => a + " world", bc: b => +b, extra: "foo" // TODO: an extra property should be allowed }] : any[] { ->{ a: true, ab: a => +a, bc: b => typeof b === "number" } : { a: boolean; ab: (a: string | number) => number; bc: (b: number) => boolean; } +>{ a: true, ab: a => +a, bc: b => typeof b === "number" } : any a: true, >a : boolean @@ -123,7 +123,7 @@ let t1 = f([ }, { ->{ a: "hello", ab: a => a + " world", bc: b => +b, extra: "foo" // TODO: an extra property should be allowed } : { a: string; ab: (a: "hello") => string; bc: (b: string) => number; extra: string; } +>{ a: "hello", ab: a => a + " world", bc: b => +b, extra: "foo" // TODO: an extra property should be allowed } : any a: "hello", >a : string diff --git a/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext3.js b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext3.js new file mode 100644 index 00000000000..bf2cb764c76 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext3.js @@ -0,0 +1,9 @@ +//// [tests/cases/compiler/quantifiedTypesParentInferenceContext3.ts] //// + +//// [quantifiedTypesParentInferenceContext3.ts] +declare const f: (x: { a: A, f: [ ((a: A) => void)] }) => void +f({ a: 0, f: [a => { a satisfies number; }] }) + + +//// [quantifiedTypesParentInferenceContext3.js] +f({ a: 0, f: [a => { a; }] }); diff --git a/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext3.symbols b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext3.symbols new file mode 100644 index 00000000000..ab66b8caf47 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext3.symbols @@ -0,0 +1,21 @@ +//// [tests/cases/compiler/quantifiedTypesParentInferenceContext3.ts] //// + +=== quantifiedTypesParentInferenceContext3.ts === +declare const f: (x: { a: A, f: [ ((a: A) => void)] }) => void +>f : Symbol(f, Decl(quantifiedTypesParentInferenceContext3.ts, 0, 13)) +>A : Symbol(A, Decl(quantifiedTypesParentInferenceContext3.ts, 0, 18)) +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext3.ts, 0, 21)) +>a : Symbol(a, Decl(quantifiedTypesParentInferenceContext3.ts, 0, 25)) +>A : Symbol(A, Decl(quantifiedTypesParentInferenceContext3.ts, 0, 18)) +>f : Symbol(f, Decl(quantifiedTypesParentInferenceContext3.ts, 0, 31)) +>T : Symbol(T, Decl(quantifiedTypesParentInferenceContext3.ts, 0, 37)) +>a : Symbol(a, Decl(quantifiedTypesParentInferenceContext3.ts, 0, 42)) +>A : Symbol(A, Decl(quantifiedTypesParentInferenceContext3.ts, 0, 18)) + +f({ a: 0, f: [a => { a satisfies number; }] }) +>f : Symbol(f, Decl(quantifiedTypesParentInferenceContext3.ts, 0, 13)) +>a : Symbol(a, Decl(quantifiedTypesParentInferenceContext3.ts, 1, 3)) +>f : Symbol(f, Decl(quantifiedTypesParentInferenceContext3.ts, 1, 9)) +>a : Symbol(a, Decl(quantifiedTypesParentInferenceContext3.ts, 1, 14)) +>a : Symbol(a, Decl(quantifiedTypesParentInferenceContext3.ts, 1, 14)) + diff --git a/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext3.types b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext3.types new file mode 100644 index 00000000000..e9cc9744c50 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext3.types @@ -0,0 +1,23 @@ +//// [tests/cases/compiler/quantifiedTypesParentInferenceContext3.ts] //// + +=== quantifiedTypesParentInferenceContext3.ts === +declare const f: (x: { a: A, f: [ ((a: A) => void)] }) => void +>f : (x: { a: A; f: [ (a: A) => void]; }) => void +>x : { a: A; f: [ (a: A) => void]; } +>a : A +>f : [ (a: A) => void] +>a : A + +f({ a: 0, f: [a => { a satisfies number; }] }) +>f({ a: 0, f: [a => { a satisfies number; }] }) : void +>f : (x: { a: A; f: [ (a: A) => void]; }) => void +>{ a: 0, f: [a => { a satisfies number; }] } : { a: number; f: [(a: number) => void]; } +>a : number +>0 : 0 +>f : [(a: number) => void] +>[a => { a satisfies number; }] : [(a: number) => void] +>a => { a satisfies number; } : (a: number) => void +>a : number +>a satisfies number : number +>a : number + diff --git a/testdata/tests/cases/compiler/quantifiedTypesParentInferenceContext3.ts b/testdata/tests/cases/compiler/quantifiedTypesParentInferenceContext3.ts new file mode 100644 index 00000000000..168335e035a --- /dev/null +++ b/testdata/tests/cases/compiler/quantifiedTypesParentInferenceContext3.ts @@ -0,0 +1,2 @@ +declare const f: (x: { a: A, f: [ ((a: A) => void)] }) => void +f({ a: 0, f: [a => { a satisfies number; }] }) From 499b4ebc16ee97334d49f0abeacbb7b0b9fc1525 Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Sat, 10 Jan 2026 21:12:20 +0530 Subject: [PATCH 09/23] add redux toolkit usecase --- .../quantifiedTypesReduxToolkit.errors.txt | 93 ++++++ .../compiler/quantifiedTypesReduxToolkit.js | 129 ++++++++ .../quantifiedTypesReduxToolkit.symbols | 297 ++++++++++++++++++ .../quantifiedTypesReduxToolkit.types | 273 ++++++++++++++++ .../compiler/quantifiedTypesReduxToolkit.ts | 79 +++++ 5 files changed, 871 insertions(+) create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesReduxToolkit.errors.txt create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesReduxToolkit.js create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesReduxToolkit.symbols create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesReduxToolkit.types create mode 100644 testdata/tests/cases/compiler/quantifiedTypesReduxToolkit.ts diff --git a/testdata/baselines/reference/compiler/quantifiedTypesReduxToolkit.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesReduxToolkit.errors.txt new file mode 100644 index 00000000000..ddc1590c26b --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesReduxToolkit.errors.txt @@ -0,0 +1,93 @@ +quantifiedTypesReduxToolkit.ts(63,7): error TS2322: Type '(state: { foo: string; }, action: PayloadAction) => void' is not assignable to type '(state: { foo: string; }, action: { payload: number; } & { type: "invalidReducerWithPrepareNotation"; }) => void'. + Types of parameters 'action' and 'action' are incompatible. + Type '{ payload: number; } & { type: "invalidReducerWithPrepareNotation"; }' is not assignable to type 'PayloadAction'. + Types of property 'payload' are incompatible. + Type 'number' is not assignable to type 'string'. + + +==== quantifiedTypesReduxToolkit.ts (1 errors) ==== + // https://github.com/microsoft/TypeScript/issues/51612#issuecomment-1375431039 + + declare const createSlice: + < S extends object + , Rs extends { [T1 in T]:

Reducer } + > + (slice: { + name: string, + initialState: S, + reducers: Rs + }) => + Slice + + type Reducer = + | ((state: S, action: P & { type: T }) => void) + | { reducer: (state: S, action: P & { type: T }) => void + , prepare: (...a: never) => P + } + + type Slice = + { actions: + { [K in keyof Rs]: + Rs[K] extends { prepare: (...a: infer A) => infer R } ? (...a: A) => { type: K } & R : + Rs[K] extends (state: never, action: PayloadAction) => unknown ? (payload: P) => { type: K, payload: P } : + never + } + } + + type PayloadAction

= + { type: string + , payload: P + } + + const slice = createSlice({ + name: "someSlice", + initialState: { + foo: "bar" + }, + reducers: { + simpleReducer: (state, action: PayloadAction) => { + state.foo = action.payload + }, + reducerWithPrepareNotation: { + prepare: (char: string, repeats: number) => { + return { payload: char.repeat(repeats), extraStuff: true } + }, + reducer: (state, action) => { + state.foo = action.payload + } + }, + reducerWithAnotherPrepareNotation: { + prepare: (char: string, repeats: number) => { + return { payload: repeats * char.length } + }, + reducer: (state, action) => { + state.foo = state.foo.slice(0, action.payload) + }, + }, + invalidReducerWithPrepareNotation: { + prepare: (char: string, repeats: number) => { + return { payload: repeats * char.length } + }, + reducer: (state, action: PayloadAction) => { + ~~~~~~~ +!!! error TS2322: Type '(state: { foo: string; }, action: PayloadAction) => void' is not assignable to type '(state: { foo: string; }, action: { payload: number; } & { type: "invalidReducerWithPrepareNotation"; }) => void'. +!!! error TS2322: Types of parameters 'action' and 'action' are incompatible. +!!! error TS2322: Type '{ payload: number; } & { type: "invalidReducerWithPrepareNotation"; }' is not assignable to type 'PayloadAction'. +!!! error TS2322: Types of property 'payload' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + state.foo = action.payload + }, + }, + } + }) + + { + const _expectType: (payload: string) => PayloadAction = slice.actions.simpleReducer + } + { + const _expectType: (char: string, repeats: number) => PayloadAction = slice.actions.reducerWithPrepareNotation + } + { + const _expectType: (char: string, repeats: number) => PayloadAction = slice.actions.reducerWithAnotherPrepareNotation + } + \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesReduxToolkit.js b/testdata/baselines/reference/compiler/quantifiedTypesReduxToolkit.js new file mode 100644 index 00000000000..0f1d6da7946 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesReduxToolkit.js @@ -0,0 +1,129 @@ +//// [tests/cases/compiler/quantifiedTypesReduxToolkit.ts] //// + +//// [quantifiedTypesReduxToolkit.ts] +// https://github.com/microsoft/TypeScript/issues/51612#issuecomment-1375431039 + +declare const createSlice: + < S extends object + , Rs extends { [T1 in T]:

Reducer } + > + (slice: { + name: string, + initialState: S, + reducers: Rs + }) => + Slice + +type Reducer = + | ((state: S, action: P & { type: T }) => void) + | { reducer: (state: S, action: P & { type: T }) => void + , prepare: (...a: never) => P + } + +type Slice = + { actions: + { [K in keyof Rs]: + Rs[K] extends { prepare: (...a: infer A) => infer R } ? (...a: A) => { type: K } & R : + Rs[K] extends (state: never, action: PayloadAction) => unknown ? (payload: P) => { type: K, payload: P } : + never + } + } + +type PayloadAction

= + { type: string + , payload: P + } + +const slice = createSlice({ + name: "someSlice", + initialState: { + foo: "bar" + }, + reducers: { + simpleReducer: (state, action: PayloadAction) => { + state.foo = action.payload + }, + reducerWithPrepareNotation: { + prepare: (char: string, repeats: number) => { + return { payload: char.repeat(repeats), extraStuff: true } + }, + reducer: (state, action) => { + state.foo = action.payload + } + }, + reducerWithAnotherPrepareNotation: { + prepare: (char: string, repeats: number) => { + return { payload: repeats * char.length } + }, + reducer: (state, action) => { + state.foo = state.foo.slice(0, action.payload) + }, + }, + invalidReducerWithPrepareNotation: { + prepare: (char: string, repeats: number) => { + return { payload: repeats * char.length } + }, + reducer: (state, action: PayloadAction) => { + state.foo = action.payload + }, + }, + } +}) + +{ + const _expectType: (payload: string) => PayloadAction = slice.actions.simpleReducer +} +{ + const _expectType: (char: string, repeats: number) => PayloadAction = slice.actions.reducerWithPrepareNotation +} +{ + const _expectType: (char: string, repeats: number) => PayloadAction = slice.actions.reducerWithAnotherPrepareNotation +} + + +//// [quantifiedTypesReduxToolkit.js] +// https://github.com/microsoft/TypeScript/issues/51612#issuecomment-1375431039 +const slice = createSlice({ + name: "someSlice", + initialState: { + foo: "bar" + }, + reducers: { + simpleReducer: (state, action) => { + state.foo = action.payload; + }, + reducerWithPrepareNotation: { + prepare: (char, repeats) => { + return { payload: char.repeat(repeats), extraStuff: true }; + }, + reducer: (state, action) => { + state.foo = action.payload; + } + }, + reducerWithAnotherPrepareNotation: { + prepare: (char, repeats) => { + return { payload: repeats * char.length }; + }, + reducer: (state, action) => { + state.foo = state.foo.slice(0, action.payload); + }, + }, + invalidReducerWithPrepareNotation: { + prepare: (char, repeats) => { + return { payload: repeats * char.length }; + }, + reducer: (state, action) => { + state.foo = action.payload; + }, + }, + } +}); +{ + const _expectType = slice.actions.simpleReducer; +} +{ + const _expectType = slice.actions.reducerWithPrepareNotation; +} +{ + const _expectType = slice.actions.reducerWithAnotherPrepareNotation; +} diff --git a/testdata/baselines/reference/compiler/quantifiedTypesReduxToolkit.symbols b/testdata/baselines/reference/compiler/quantifiedTypesReduxToolkit.symbols new file mode 100644 index 00000000000..66f3d99d611 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesReduxToolkit.symbols @@ -0,0 +1,297 @@ +//// [tests/cases/compiler/quantifiedTypesReduxToolkit.ts] //// + +=== quantifiedTypesReduxToolkit.ts === +// https://github.com/microsoft/TypeScript/issues/51612#issuecomment-1375431039 + +declare const createSlice: +>createSlice : Symbol(createSlice, Decl(quantifiedTypesReduxToolkit.ts, 2, 13)) + + < S extends object +>S : Symbol(S, Decl(quantifiedTypesReduxToolkit.ts, 3, 3)) + + , Rs extends { [T1 in T]:

Reducer } +>Rs : Symbol(Rs, Decl(quantifiedTypesReduxToolkit.ts, 4, 3)) +>T : Symbol(T, Decl(quantifiedTypesReduxToolkit.ts, 4, 16)) +>T1 : Symbol(T1, Decl(quantifiedTypesReduxToolkit.ts, 4, 37)) +>T : Symbol(T, Decl(quantifiedTypesReduxToolkit.ts, 4, 16)) +>P : Symbol(P, Decl(quantifiedTypesReduxToolkit.ts, 4, 48)) +>Reducer : Symbol(Reducer, Decl(quantifiedTypesReduxToolkit.ts, 11, 18)) +>S : Symbol(S, Decl(quantifiedTypesReduxToolkit.ts, 3, 3)) +>T1 : Symbol(T1, Decl(quantifiedTypesReduxToolkit.ts, 4, 37)) +>P : Symbol(P, Decl(quantifiedTypesReduxToolkit.ts, 4, 48)) + + > + (slice: { +>slice : Symbol(slice, Decl(quantifiedTypesReduxToolkit.ts, 6, 5)) + + name: string, +>name : Symbol(name, Decl(quantifiedTypesReduxToolkit.ts, 6, 13)) + + initialState: S, +>initialState : Symbol(initialState, Decl(quantifiedTypesReduxToolkit.ts, 7, 19)) +>S : Symbol(S, Decl(quantifiedTypesReduxToolkit.ts, 3, 3)) + + reducers: Rs +>reducers : Symbol(reducers, Decl(quantifiedTypesReduxToolkit.ts, 8, 22)) +>Rs : Symbol(Rs, Decl(quantifiedTypesReduxToolkit.ts, 4, 3)) + + }) => + Slice +>Slice : Symbol(Slice, Decl(quantifiedTypesReduxToolkit.ts, 17, 5)) +>S : Symbol(S, Decl(quantifiedTypesReduxToolkit.ts, 3, 3)) +>Rs : Symbol(Rs, Decl(quantifiedTypesReduxToolkit.ts, 4, 3)) + +type Reducer = +>Reducer : Symbol(Reducer, Decl(quantifiedTypesReduxToolkit.ts, 11, 18)) +>S : Symbol(S, Decl(quantifiedTypesReduxToolkit.ts, 13, 13)) +>T : Symbol(T, Decl(quantifiedTypesReduxToolkit.ts, 13, 15)) +>P : Symbol(P, Decl(quantifiedTypesReduxToolkit.ts, 13, 18)) + + | ((state: S, action: P & { type: T }) => void) +>state : Symbol(state, Decl(quantifiedTypesReduxToolkit.ts, 14, 6)) +>S : Symbol(S, Decl(quantifiedTypesReduxToolkit.ts, 13, 13)) +>action : Symbol(action, Decl(quantifiedTypesReduxToolkit.ts, 14, 15)) +>P : Symbol(P, Decl(quantifiedTypesReduxToolkit.ts, 13, 18)) +>type : Symbol(type, Decl(quantifiedTypesReduxToolkit.ts, 14, 29)) +>T : Symbol(T, Decl(quantifiedTypesReduxToolkit.ts, 13, 15)) + + | { reducer: (state: S, action: P & { type: T }) => void +>reducer : Symbol(reducer, Decl(quantifiedTypesReduxToolkit.ts, 15, 5)) +>state : Symbol(state, Decl(quantifiedTypesReduxToolkit.ts, 15, 16)) +>S : Symbol(S, Decl(quantifiedTypesReduxToolkit.ts, 13, 13)) +>action : Symbol(action, Decl(quantifiedTypesReduxToolkit.ts, 15, 25)) +>P : Symbol(P, Decl(quantifiedTypesReduxToolkit.ts, 13, 18)) +>type : Symbol(type, Decl(quantifiedTypesReduxToolkit.ts, 15, 39)) +>T : Symbol(T, Decl(quantifiedTypesReduxToolkit.ts, 13, 15)) + + , prepare: (...a: never) => P +>prepare : Symbol(prepare, Decl(quantifiedTypesReduxToolkit.ts, 16, 5)) +>a : Symbol(a, Decl(quantifiedTypesReduxToolkit.ts, 16, 16)) +>P : Symbol(P, Decl(quantifiedTypesReduxToolkit.ts, 13, 18)) + } + +type Slice = +>Slice : Symbol(Slice, Decl(quantifiedTypesReduxToolkit.ts, 17, 5)) +>S : Symbol(S, Decl(quantifiedTypesReduxToolkit.ts, 19, 11)) +>Rs : Symbol(Rs, Decl(quantifiedTypesReduxToolkit.ts, 19, 13)) + + { actions: +>actions : Symbol(actions, Decl(quantifiedTypesReduxToolkit.ts, 20, 3)) + + { [K in keyof Rs]: +>K : Symbol(K, Decl(quantifiedTypesReduxToolkit.ts, 21, 9)) +>Rs : Symbol(Rs, Decl(quantifiedTypesReduxToolkit.ts, 19, 13)) + + Rs[K] extends { prepare: (...a: infer A) => infer R } ? (...a: A) => { type: K } & R : +>Rs : Symbol(Rs, Decl(quantifiedTypesReduxToolkit.ts, 19, 13)) +>K : Symbol(K, Decl(quantifiedTypesReduxToolkit.ts, 21, 9)) +>prepare : Symbol(prepare, Decl(quantifiedTypesReduxToolkit.ts, 22, 25)) +>a : Symbol(a, Decl(quantifiedTypesReduxToolkit.ts, 22, 36)) +>A : Symbol(A, Decl(quantifiedTypesReduxToolkit.ts, 22, 47)) +>R : Symbol(R, Decl(quantifiedTypesReduxToolkit.ts, 22, 59)) +>a : Symbol(a, Decl(quantifiedTypesReduxToolkit.ts, 22, 67)) +>A : Symbol(A, Decl(quantifiedTypesReduxToolkit.ts, 22, 47)) +>type : Symbol(type, Decl(quantifiedTypesReduxToolkit.ts, 22, 80)) +>K : Symbol(K, Decl(quantifiedTypesReduxToolkit.ts, 21, 9)) +>R : Symbol(R, Decl(quantifiedTypesReduxToolkit.ts, 22, 59)) + + Rs[K] extends (state: never, action: PayloadAction) => unknown ? (payload: P) => { type: K, payload: P } : +>Rs : Symbol(Rs, Decl(quantifiedTypesReduxToolkit.ts, 19, 13)) +>K : Symbol(K, Decl(quantifiedTypesReduxToolkit.ts, 21, 9)) +>state : Symbol(state, Decl(quantifiedTypesReduxToolkit.ts, 23, 25)) +>action : Symbol(action, Decl(quantifiedTypesReduxToolkit.ts, 23, 38)) +>PayloadAction : Symbol(PayloadAction, Decl(quantifiedTypesReduxToolkit.ts, 26, 3)) +>P : Symbol(P, Decl(quantifiedTypesReduxToolkit.ts, 23, 66)) +>payload : Symbol(payload, Decl(quantifiedTypesReduxToolkit.ts, 23, 85)) +>P : Symbol(P, Decl(quantifiedTypesReduxToolkit.ts, 23, 66)) +>type : Symbol(type, Decl(quantifiedTypesReduxToolkit.ts, 23, 101)) +>K : Symbol(K, Decl(quantifiedTypesReduxToolkit.ts, 21, 9)) +>payload : Symbol(payload, Decl(quantifiedTypesReduxToolkit.ts, 23, 110)) +>P : Symbol(P, Decl(quantifiedTypesReduxToolkit.ts, 23, 66)) + + never + } + } + +type PayloadAction

= +>PayloadAction : Symbol(PayloadAction, Decl(quantifiedTypesReduxToolkit.ts, 26, 3)) +>P : Symbol(P, Decl(quantifiedTypesReduxToolkit.ts, 28, 19)) + + { type: string +>type : Symbol(type, Decl(quantifiedTypesReduxToolkit.ts, 29, 3)) + + , payload: P +>payload : Symbol(payload, Decl(quantifiedTypesReduxToolkit.ts, 30, 3)) +>P : Symbol(P, Decl(quantifiedTypesReduxToolkit.ts, 28, 19)) + } + +const slice = createSlice({ +>slice : Symbol(slice, Decl(quantifiedTypesReduxToolkit.ts, 33, 5)) +>createSlice : Symbol(createSlice, Decl(quantifiedTypesReduxToolkit.ts, 2, 13)) + + name: "someSlice", +>name : Symbol(name, Decl(quantifiedTypesReduxToolkit.ts, 33, 27)) + + initialState: { +>initialState : Symbol(initialState, Decl(quantifiedTypesReduxToolkit.ts, 34, 20)) + + foo: "bar" +>foo : Symbol(foo, Decl(quantifiedTypesReduxToolkit.ts, 35, 17)) + + }, + reducers: { +>reducers : Symbol(reducers, Decl(quantifiedTypesReduxToolkit.ts, 37, 4)) + + simpleReducer: (state, action: PayloadAction) => { +>simpleReducer : Symbol(simpleReducer, Decl(quantifiedTypesReduxToolkit.ts, 38, 13)) +>state : Symbol(state, Decl(quantifiedTypesReduxToolkit.ts, 39, 20)) +>action : Symbol(action, Decl(quantifiedTypesReduxToolkit.ts, 39, 26)) +>PayloadAction : Symbol(PayloadAction, Decl(quantifiedTypesReduxToolkit.ts, 26, 3)) + + state.foo = action.payload +>state.foo : Symbol(foo, Decl(quantifiedTypesReduxToolkit.ts, 35, 17)) +>state : Symbol(state, Decl(quantifiedTypesReduxToolkit.ts, 39, 20)) +>foo : Symbol(foo, Decl(quantifiedTypesReduxToolkit.ts, 35, 17)) +>action.payload : Symbol(payload, Decl(quantifiedTypesReduxToolkit.ts, 30, 3)) +>action : Symbol(action, Decl(quantifiedTypesReduxToolkit.ts, 39, 26)) +>payload : Symbol(payload, Decl(quantifiedTypesReduxToolkit.ts, 30, 3)) + + }, + reducerWithPrepareNotation: { +>reducerWithPrepareNotation : Symbol(reducerWithPrepareNotation, Decl(quantifiedTypesReduxToolkit.ts, 41, 6)) + + prepare: (char: string, repeats: number) => { +>prepare : Symbol(prepare, Decl(quantifiedTypesReduxToolkit.ts, 42, 33)) +>char : Symbol(char, Decl(quantifiedTypesReduxToolkit.ts, 43, 16)) +>repeats : Symbol(repeats, Decl(quantifiedTypesReduxToolkit.ts, 43, 29)) + + return { payload: char.repeat(repeats), extraStuff: true } +>payload : Symbol(payload, Decl(quantifiedTypesReduxToolkit.ts, 44, 16)) +>char.repeat : Symbol(String.repeat, Decl(lib.es2015.core.d.ts, --, --)) +>char : Symbol(char, Decl(quantifiedTypesReduxToolkit.ts, 43, 16)) +>repeat : Symbol(String.repeat, Decl(lib.es2015.core.d.ts, --, --)) +>repeats : Symbol(repeats, Decl(quantifiedTypesReduxToolkit.ts, 43, 29)) +>extraStuff : Symbol(extraStuff, Decl(quantifiedTypesReduxToolkit.ts, 44, 47)) + + }, + reducer: (state, action) => { +>reducer : Symbol(reducer, Decl(quantifiedTypesReduxToolkit.ts, 45, 8)) +>state : Symbol(state, Decl(quantifiedTypesReduxToolkit.ts, 46, 16)) +>action : Symbol(action, Decl(quantifiedTypesReduxToolkit.ts, 46, 22)) + + state.foo = action.payload +>state.foo : Symbol(foo, Decl(quantifiedTypesReduxToolkit.ts, 35, 17)) +>state : Symbol(state, Decl(quantifiedTypesReduxToolkit.ts, 46, 16)) +>foo : Symbol(foo, Decl(quantifiedTypesReduxToolkit.ts, 35, 17)) +>action.payload : Symbol(payload, Decl(quantifiedTypesReduxToolkit.ts, 44, 16)) +>action : Symbol(action, Decl(quantifiedTypesReduxToolkit.ts, 46, 22)) +>payload : Symbol(payload, Decl(quantifiedTypesReduxToolkit.ts, 44, 16)) + } + }, + reducerWithAnotherPrepareNotation: { +>reducerWithAnotherPrepareNotation : Symbol(reducerWithAnotherPrepareNotation, Decl(quantifiedTypesReduxToolkit.ts, 49, 6)) + + prepare: (char: string, repeats: number) => { +>prepare : Symbol(prepare, Decl(quantifiedTypesReduxToolkit.ts, 50, 40)) +>char : Symbol(char, Decl(quantifiedTypesReduxToolkit.ts, 51, 16)) +>repeats : Symbol(repeats, Decl(quantifiedTypesReduxToolkit.ts, 51, 29)) + + return { payload: repeats * char.length } +>payload : Symbol(payload, Decl(quantifiedTypesReduxToolkit.ts, 52, 16)) +>repeats : Symbol(repeats, Decl(quantifiedTypesReduxToolkit.ts, 51, 29)) +>char.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) +>char : Symbol(char, Decl(quantifiedTypesReduxToolkit.ts, 51, 16)) +>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) + + }, + reducer: (state, action) => { +>reducer : Symbol(reducer, Decl(quantifiedTypesReduxToolkit.ts, 53, 8)) +>state : Symbol(state, Decl(quantifiedTypesReduxToolkit.ts, 54, 16)) +>action : Symbol(action, Decl(quantifiedTypesReduxToolkit.ts, 54, 22)) + + state.foo = state.foo.slice(0, action.payload) +>state.foo : Symbol(foo, Decl(quantifiedTypesReduxToolkit.ts, 35, 17)) +>state : Symbol(state, Decl(quantifiedTypesReduxToolkit.ts, 54, 16)) +>foo : Symbol(foo, Decl(quantifiedTypesReduxToolkit.ts, 35, 17)) +>state.foo.slice : Symbol(String.slice, Decl(lib.es5.d.ts, --, --)) +>state.foo : Symbol(foo, Decl(quantifiedTypesReduxToolkit.ts, 35, 17)) +>state : Symbol(state, Decl(quantifiedTypesReduxToolkit.ts, 54, 16)) +>foo : Symbol(foo, Decl(quantifiedTypesReduxToolkit.ts, 35, 17)) +>slice : Symbol(String.slice, Decl(lib.es5.d.ts, --, --)) +>action.payload : Symbol(payload, Decl(quantifiedTypesReduxToolkit.ts, 52, 16)) +>action : Symbol(action, Decl(quantifiedTypesReduxToolkit.ts, 54, 22)) +>payload : Symbol(payload, Decl(quantifiedTypesReduxToolkit.ts, 52, 16)) + + }, + }, + invalidReducerWithPrepareNotation: { +>invalidReducerWithPrepareNotation : Symbol(invalidReducerWithPrepareNotation, Decl(quantifiedTypesReduxToolkit.ts, 57, 6)) + + prepare: (char: string, repeats: number) => { +>prepare : Symbol(prepare, Decl(quantifiedTypesReduxToolkit.ts, 58, 40)) +>char : Symbol(char, Decl(quantifiedTypesReduxToolkit.ts, 59, 16)) +>repeats : Symbol(repeats, Decl(quantifiedTypesReduxToolkit.ts, 59, 29)) + + return { payload: repeats * char.length } +>payload : Symbol(payload, Decl(quantifiedTypesReduxToolkit.ts, 60, 16)) +>repeats : Symbol(repeats, Decl(quantifiedTypesReduxToolkit.ts, 59, 29)) +>char.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) +>char : Symbol(char, Decl(quantifiedTypesReduxToolkit.ts, 59, 16)) +>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) + + }, + reducer: (state, action: PayloadAction) => { +>reducer : Symbol(reducer, Decl(quantifiedTypesReduxToolkit.ts, 61, 8)) +>state : Symbol(state, Decl(quantifiedTypesReduxToolkit.ts, 62, 16)) +>action : Symbol(action, Decl(quantifiedTypesReduxToolkit.ts, 62, 22)) +>PayloadAction : Symbol(PayloadAction, Decl(quantifiedTypesReduxToolkit.ts, 26, 3)) + + state.foo = action.payload +>state.foo : Symbol(foo, Decl(quantifiedTypesReduxToolkit.ts, 35, 17)) +>state : Symbol(state, Decl(quantifiedTypesReduxToolkit.ts, 62, 16)) +>foo : Symbol(foo, Decl(quantifiedTypesReduxToolkit.ts, 35, 17)) +>action.payload : Symbol(payload, Decl(quantifiedTypesReduxToolkit.ts, 30, 3)) +>action : Symbol(action, Decl(quantifiedTypesReduxToolkit.ts, 62, 22)) +>payload : Symbol(payload, Decl(quantifiedTypesReduxToolkit.ts, 30, 3)) + + }, + }, + } +}) + +{ + const _expectType: (payload: string) => PayloadAction = slice.actions.simpleReducer +>_expectType : Symbol(_expectType, Decl(quantifiedTypesReduxToolkit.ts, 70, 7)) +>payload : Symbol(payload, Decl(quantifiedTypesReduxToolkit.ts, 70, 22)) +>PayloadAction : Symbol(PayloadAction, Decl(quantifiedTypesReduxToolkit.ts, 26, 3)) +>slice.actions.simpleReducer : Symbol(simpleReducer, Decl(quantifiedTypesReduxToolkit.ts, 38, 13)) +>slice.actions : Symbol(actions, Decl(quantifiedTypesReduxToolkit.ts, 20, 3)) +>slice : Symbol(slice, Decl(quantifiedTypesReduxToolkit.ts, 33, 5)) +>actions : Symbol(actions, Decl(quantifiedTypesReduxToolkit.ts, 20, 3)) +>simpleReducer : Symbol(simpleReducer, Decl(quantifiedTypesReduxToolkit.ts, 38, 13)) +} +{ + const _expectType: (char: string, repeats: number) => PayloadAction = slice.actions.reducerWithPrepareNotation +>_expectType : Symbol(_expectType, Decl(quantifiedTypesReduxToolkit.ts, 73, 7)) +>char : Symbol(char, Decl(quantifiedTypesReduxToolkit.ts, 73, 22)) +>repeats : Symbol(repeats, Decl(quantifiedTypesReduxToolkit.ts, 73, 35)) +>PayloadAction : Symbol(PayloadAction, Decl(quantifiedTypesReduxToolkit.ts, 26, 3)) +>slice.actions.reducerWithPrepareNotation : Symbol(reducerWithPrepareNotation, Decl(quantifiedTypesReduxToolkit.ts, 41, 6)) +>slice.actions : Symbol(actions, Decl(quantifiedTypesReduxToolkit.ts, 20, 3)) +>slice : Symbol(slice, Decl(quantifiedTypesReduxToolkit.ts, 33, 5)) +>actions : Symbol(actions, Decl(quantifiedTypesReduxToolkit.ts, 20, 3)) +>reducerWithPrepareNotation : Symbol(reducerWithPrepareNotation, Decl(quantifiedTypesReduxToolkit.ts, 41, 6)) +} +{ + const _expectType: (char: string, repeats: number) => PayloadAction = slice.actions.reducerWithAnotherPrepareNotation +>_expectType : Symbol(_expectType, Decl(quantifiedTypesReduxToolkit.ts, 76, 7)) +>char : Symbol(char, Decl(quantifiedTypesReduxToolkit.ts, 76, 22)) +>repeats : Symbol(repeats, Decl(quantifiedTypesReduxToolkit.ts, 76, 35)) +>PayloadAction : Symbol(PayloadAction, Decl(quantifiedTypesReduxToolkit.ts, 26, 3)) +>slice.actions.reducerWithAnotherPrepareNotation : Symbol(reducerWithAnotherPrepareNotation, Decl(quantifiedTypesReduxToolkit.ts, 49, 6)) +>slice.actions : Symbol(actions, Decl(quantifiedTypesReduxToolkit.ts, 20, 3)) +>slice : Symbol(slice, Decl(quantifiedTypesReduxToolkit.ts, 33, 5)) +>actions : Symbol(actions, Decl(quantifiedTypesReduxToolkit.ts, 20, 3)) +>reducerWithAnotherPrepareNotation : Symbol(reducerWithAnotherPrepareNotation, Decl(quantifiedTypesReduxToolkit.ts, 49, 6)) +} + diff --git a/testdata/baselines/reference/compiler/quantifiedTypesReduxToolkit.types b/testdata/baselines/reference/compiler/quantifiedTypesReduxToolkit.types new file mode 100644 index 00000000000..357dd94445b --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesReduxToolkit.types @@ -0,0 +1,273 @@ +//// [tests/cases/compiler/quantifiedTypesReduxToolkit.ts] //// + +=== quantifiedTypesReduxToolkit.ts === +// https://github.com/microsoft/TypeScript/issues/51612#issuecomment-1375431039 + +declare const createSlice: +>createSlice : { [T1 in T]:

Reducer; }>(slice: { name: string; initialState: S; reducers: Rs; }) => Slice + + < S extends object + , Rs extends { [T1 in T]:

Reducer } + > + (slice: { +>slice : { name: string; initialState: S; reducers: Rs; } + + name: string, +>name : string + + initialState: S, +>initialState : S + + reducers: Rs +>reducers : Rs + + }) => + Slice + +type Reducer = +>Reducer : Reducer + + | ((state: S, action: P & { type: T }) => void) +>state : S +>action : P & { type: T; } +>type : T + + | { reducer: (state: S, action: P & { type: T }) => void +>reducer : (state: S, action: P & { type: T; }) => void +>state : S +>action : P & { type: T; } +>type : T + + , prepare: (...a: never) => P +>prepare : (...a: never) => P +>a : never + } + +type Slice = +>Slice : Slice + + { actions: +>actions : { [K in keyof Rs]: Rs[K] extends { prepare: (...a: infer A) => infer R; } ? (...a: A) => { type: K; } & R : Rs[K] extends (state: never, action: PayloadAction) => unknown ? (payload: P) => { type: K; payload: P; } : never; } + + { [K in keyof Rs]: + Rs[K] extends { prepare: (...a: infer A) => infer R } ? (...a: A) => { type: K } & R : +>prepare : (...a: A) => R +>a : A +>a : A +>type : K + + Rs[K] extends (state: never, action: PayloadAction) => unknown ? (payload: P) => { type: K, payload: P } : +>state : never +>action : PayloadAction

+>payload : P +>type : K +>payload : P + + never + } + } + +type PayloadAction

= +>PayloadAction : PayloadAction

+ + { type: string +>type : string + + , payload: P +>payload : P + } + +const slice = createSlice({ +>slice : Slice<{ foo: string; }, { simpleReducer: (state: { foo: string; }, action: PayloadAction) => void; reducerWithPrepareNotation: { prepare: (char: string, repeats: number) => { payload: string; extraStuff: boolean; }; reducer: (state: { foo: string; }, action: { payload: string; extraStuff: boolean; } & { type: "reducerWithPrepareNotation"; }) => void; }; reducerWithAnotherPrepareNotation: { prepare: (char: string, repeats: number) => { payload: number; }; reducer: (state: { foo: string; }, action: { payload: number; } & { type: "reducerWithAnotherPrepareNotation"; }) => void; }; invalidReducerWithPrepareNotation: any; }> +>createSlice({ name: "someSlice", initialState: { foo: "bar" }, reducers: { simpleReducer: (state, action: PayloadAction) => { state.foo = action.payload }, reducerWithPrepareNotation: { prepare: (char: string, repeats: number) => { return { payload: char.repeat(repeats), extraStuff: true } }, reducer: (state, action) => { state.foo = action.payload } }, reducerWithAnotherPrepareNotation: { prepare: (char: string, repeats: number) => { return { payload: repeats * char.length } }, reducer: (state, action) => { state.foo = state.foo.slice(0, action.payload) }, }, invalidReducerWithPrepareNotation: { prepare: (char: string, repeats: number) => { return { payload: repeats * char.length } }, reducer: (state, action: PayloadAction) => { state.foo = action.payload }, }, }}) : Slice<{ foo: string; }, { simpleReducer: (state: { foo: string; }, action: PayloadAction) => void; reducerWithPrepareNotation: { prepare: (char: string, repeats: number) => { payload: string; extraStuff: boolean; }; reducer: (state: { foo: string; }, action: { payload: string; extraStuff: boolean; } & { type: "reducerWithPrepareNotation"; }) => void; }; reducerWithAnotherPrepareNotation: { prepare: (char: string, repeats: number) => { payload: number; }; reducer: (state: { foo: string; }, action: { payload: number; } & { type: "reducerWithAnotherPrepareNotation"; }) => void; }; invalidReducerWithPrepareNotation: any; }> +>createSlice : { [T1 in T]:

Reducer; }>(slice: { name: string; initialState: S; reducers: Rs; }) => Slice +>{ name: "someSlice", initialState: { foo: "bar" }, reducers: { simpleReducer: (state, action: PayloadAction) => { state.foo = action.payload }, reducerWithPrepareNotation: { prepare: (char: string, repeats: number) => { return { payload: char.repeat(repeats), extraStuff: true } }, reducer: (state, action) => { state.foo = action.payload } }, reducerWithAnotherPrepareNotation: { prepare: (char: string, repeats: number) => { return { payload: repeats * char.length } }, reducer: (state, action) => { state.foo = state.foo.slice(0, action.payload) }, }, invalidReducerWithPrepareNotation: { prepare: (char: string, repeats: number) => { return { payload: repeats * char.length } }, reducer: (state, action: PayloadAction) => { state.foo = action.payload }, }, }} : { name: string; initialState: { foo: string; }; reducers: { simpleReducer: (state: { foo: string; }, action: PayloadAction) => void; reducerWithPrepareNotation: { prepare: (char: string, repeats: number) => { payload: string; extraStuff: boolean; }; reducer: (state: { foo: string; }, action: { payload: string; extraStuff: boolean; } & { type: "reducerWithPrepareNotation"; }) => void; }; reducerWithAnotherPrepareNotation: { prepare: (char: string, repeats: number) => { payload: number; }; reducer: (state: { foo: string; }, action: { payload: number; } & { type: "reducerWithAnotherPrepareNotation"; }) => void; }; invalidReducerWithPrepareNotation: { prepare: (char: string, repeats: number) => { payload: number; }; reducer: (state: { foo: string; }, action: PayloadAction) => void; }; }; } + + name: "someSlice", +>name : string +>"someSlice" : "someSlice" + + initialState: { +>initialState : { foo: string; } +>{ foo: "bar" } : { foo: string; } + + foo: "bar" +>foo : string +>"bar" : "bar" + + }, + reducers: { +>reducers : { simpleReducer: (state: { foo: string; }, action: PayloadAction) => void; reducerWithPrepareNotation: { prepare: (char: string, repeats: number) => { payload: string; extraStuff: boolean; }; reducer: (state: { foo: string; }, action: { payload: string; extraStuff: boolean; } & { type: "reducerWithPrepareNotation"; }) => void; }; reducerWithAnotherPrepareNotation: { prepare: (char: string, repeats: number) => { payload: number; }; reducer: (state: { foo: string; }, action: { payload: number; } & { type: "reducerWithAnotherPrepareNotation"; }) => void; }; invalidReducerWithPrepareNotation: { prepare: (char: string, repeats: number) => { payload: number; }; reducer: (state: { foo: string; }, action: PayloadAction) => void; }; } +>{ simpleReducer: (state, action: PayloadAction) => { state.foo = action.payload }, reducerWithPrepareNotation: { prepare: (char: string, repeats: number) => { return { payload: char.repeat(repeats), extraStuff: true } }, reducer: (state, action) => { state.foo = action.payload } }, reducerWithAnotherPrepareNotation: { prepare: (char: string, repeats: number) => { return { payload: repeats * char.length } }, reducer: (state, action) => { state.foo = state.foo.slice(0, action.payload) }, }, invalidReducerWithPrepareNotation: { prepare: (char: string, repeats: number) => { return { payload: repeats * char.length } }, reducer: (state, action: PayloadAction) => { state.foo = action.payload }, }, } : { simpleReducer: (state: { foo: string; }, action: PayloadAction) => void; reducerWithPrepareNotation: { prepare: (char: string, repeats: number) => { payload: string; extraStuff: boolean; }; reducer: (state: { foo: string; }, action: { payload: string; extraStuff: boolean; } & { type: "reducerWithPrepareNotation"; }) => void; }; reducerWithAnotherPrepareNotation: { prepare: (char: string, repeats: number) => { payload: number; }; reducer: (state: { foo: string; }, action: { payload: number; } & { type: "reducerWithAnotherPrepareNotation"; }) => void; }; invalidReducerWithPrepareNotation: { prepare: (char: string, repeats: number) => { payload: number; }; reducer: (state: { foo: string; }, action: PayloadAction) => void; }; } + + simpleReducer: (state, action: PayloadAction) => { +>simpleReducer : (state: { foo: string; }, action: PayloadAction) => void +>(state, action: PayloadAction) => { state.foo = action.payload } : (state: { foo: string; }, action: PayloadAction) => void +>state : { foo: string; } +>action : PayloadAction + + state.foo = action.payload +>state.foo = action.payload : string +>state.foo : string +>state : { foo: string; } +>foo : string +>action.payload : string +>action : PayloadAction +>payload : string + + }, + reducerWithPrepareNotation: { +>reducerWithPrepareNotation : { prepare: (char: string, repeats: number) => { payload: string; extraStuff: boolean; }; reducer: (state: { foo: string; }, action: { payload: string; extraStuff: boolean; } & { type: "reducerWithPrepareNotation"; }) => void; } +>{ prepare: (char: string, repeats: number) => { return { payload: char.repeat(repeats), extraStuff: true } }, reducer: (state, action) => { state.foo = action.payload } } : { prepare: (char: string, repeats: number) => { payload: string; extraStuff: boolean; }; reducer: (state: { foo: string; }, action: { payload: string; extraStuff: boolean; } & { type: "reducerWithPrepareNotation"; }) => void; } + + prepare: (char: string, repeats: number) => { +>prepare : (char: string, repeats: number) => { payload: string; extraStuff: boolean; } +>(char: string, repeats: number) => { return { payload: char.repeat(repeats), extraStuff: true } } : (char: string, repeats: number) => { payload: string; extraStuff: boolean; } +>char : string +>repeats : number + + return { payload: char.repeat(repeats), extraStuff: true } +>{ payload: char.repeat(repeats), extraStuff: true } : { payload: string; extraStuff: true; } +>payload : string +>char.repeat(repeats) : string +>char.repeat : (count: number) => string +>char : string +>repeat : (count: number) => string +>repeats : number +>extraStuff : true +>true : true + + }, + reducer: (state, action) => { +>reducer : (state: { foo: string; }, action: { payload: string; extraStuff: boolean; } & { type: "reducerWithPrepareNotation"; }) => void +>(state, action) => { state.foo = action.payload } : (state: { foo: string; }, action: { payload: string; extraStuff: boolean; } & { type: "reducerWithPrepareNotation"; }) => void +>state : { foo: string; } +>action : { payload: string; extraStuff: boolean; } & { type: "reducerWithPrepareNotation"; } + + state.foo = action.payload +>state.foo = action.payload : string +>state.foo : string +>state : { foo: string; } +>foo : string +>action.payload : string +>action : { payload: string; extraStuff: boolean; } & { type: "reducerWithPrepareNotation"; } +>payload : string + } + }, + reducerWithAnotherPrepareNotation: { +>reducerWithAnotherPrepareNotation : { prepare: (char: string, repeats: number) => { payload: number; }; reducer: (state: { foo: string; }, action: { payload: number; } & { type: "reducerWithAnotherPrepareNotation"; }) => void; } +>{ prepare: (char: string, repeats: number) => { return { payload: repeats * char.length } }, reducer: (state, action) => { state.foo = state.foo.slice(0, action.payload) }, } : { prepare: (char: string, repeats: number) => { payload: number; }; reducer: (state: { foo: string; }, action: { payload: number; } & { type: "reducerWithAnotherPrepareNotation"; }) => void; } + + prepare: (char: string, repeats: number) => { +>prepare : (char: string, repeats: number) => { payload: number; } +>(char: string, repeats: number) => { return { payload: repeats * char.length } } : (char: string, repeats: number) => { payload: number; } +>char : string +>repeats : number + + return { payload: repeats * char.length } +>{ payload: repeats * char.length } : { payload: number; } +>payload : number +>repeats * char.length : number +>repeats : number +>char.length : number +>char : string +>length : number + + }, + reducer: (state, action) => { +>reducer : (state: { foo: string; }, action: { payload: number; } & { type: "reducerWithAnotherPrepareNotation"; }) => void +>(state, action) => { state.foo = state.foo.slice(0, action.payload) } : (state: { foo: string; }, action: { payload: number; } & { type: "reducerWithAnotherPrepareNotation"; }) => void +>state : { foo: string; } +>action : { payload: number; } & { type: "reducerWithAnotherPrepareNotation"; } + + state.foo = state.foo.slice(0, action.payload) +>state.foo = state.foo.slice(0, action.payload) : string +>state.foo : string +>state : { foo: string; } +>foo : string +>state.foo.slice(0, action.payload) : string +>state.foo.slice : (start?: number, end?: number) => string +>state.foo : string +>state : { foo: string; } +>foo : string +>slice : (start?: number, end?: number) => string +>0 : 0 +>action.payload : number +>action : { payload: number; } & { type: "reducerWithAnotherPrepareNotation"; } +>payload : number + + }, + }, + invalidReducerWithPrepareNotation: { +>invalidReducerWithPrepareNotation : { prepare: (char: string, repeats: number) => { payload: number; }; reducer: (state: { foo: string; }, action: PayloadAction) => void; } +>{ prepare: (char: string, repeats: number) => { return { payload: repeats * char.length } }, reducer: (state, action: PayloadAction) => { state.foo = action.payload }, } : { prepare: (char: string, repeats: number) => { payload: number; }; reducer: (state: { foo: string; }, action: PayloadAction) => void; } + + prepare: (char: string, repeats: number) => { +>prepare : (char: string, repeats: number) => { payload: number; } +>(char: string, repeats: number) => { return { payload: repeats * char.length } } : (char: string, repeats: number) => { payload: number; } +>char : string +>repeats : number + + return { payload: repeats * char.length } +>{ payload: repeats * char.length } : { payload: number; } +>payload : number +>repeats * char.length : number +>repeats : number +>char.length : number +>char : string +>length : number + + }, + reducer: (state, action: PayloadAction) => { +>reducer : (state: { foo: string; }, action: PayloadAction) => void +>(state, action: PayloadAction) => { state.foo = action.payload } : (state: { foo: string; }, action: PayloadAction) => void +>state : { foo: string; } +>action : PayloadAction + + state.foo = action.payload +>state.foo = action.payload : string +>state.foo : string +>state : { foo: string; } +>foo : string +>action.payload : string +>action : PayloadAction +>payload : string + + }, + }, + } +}) + +{ + const _expectType: (payload: string) => PayloadAction = slice.actions.simpleReducer +>_expectType : (payload: string) => PayloadAction +>payload : string +>slice.actions.simpleReducer : (payload: string) => { type: "simpleReducer"; payload: string; } +>slice.actions : { simpleReducer: (payload: string) => { type: "simpleReducer"; payload: string; }; reducerWithPrepareNotation: (char: string, repeats: number) => { type: "reducerWithPrepareNotation"; } & { payload: string; extraStuff: boolean; }; reducerWithAnotherPrepareNotation: (char: string, repeats: number) => { type: "reducerWithAnotherPrepareNotation"; } & { payload: number; }; invalidReducerWithPrepareNotation: any; } +>slice : Slice<{ foo: string; }, { simpleReducer: (state: { foo: string; }, action: PayloadAction) => void; reducerWithPrepareNotation: { prepare: (char: string, repeats: number) => { payload: string; extraStuff: boolean; }; reducer: (state: { foo: string; }, action: { payload: string; extraStuff: boolean; } & { type: "reducerWithPrepareNotation"; }) => void; }; reducerWithAnotherPrepareNotation: { prepare: (char: string, repeats: number) => { payload: number; }; reducer: (state: { foo: string; }, action: { payload: number; } & { type: "reducerWithAnotherPrepareNotation"; }) => void; }; invalidReducerWithPrepareNotation: any; }> +>actions : { simpleReducer: (payload: string) => { type: "simpleReducer"; payload: string; }; reducerWithPrepareNotation: (char: string, repeats: number) => { type: "reducerWithPrepareNotation"; } & { payload: string; extraStuff: boolean; }; reducerWithAnotherPrepareNotation: (char: string, repeats: number) => { type: "reducerWithAnotherPrepareNotation"; } & { payload: number; }; invalidReducerWithPrepareNotation: any; } +>simpleReducer : (payload: string) => { type: "simpleReducer"; payload: string; } +} +{ + const _expectType: (char: string, repeats: number) => PayloadAction = slice.actions.reducerWithPrepareNotation +>_expectType : (char: string, repeats: number) => PayloadAction +>char : string +>repeats : number +>slice.actions.reducerWithPrepareNotation : (char: string, repeats: number) => { type: "reducerWithPrepareNotation"; } & { payload: string; extraStuff: boolean; } +>slice.actions : { simpleReducer: (payload: string) => { type: "simpleReducer"; payload: string; }; reducerWithPrepareNotation: (char: string, repeats: number) => { type: "reducerWithPrepareNotation"; } & { payload: string; extraStuff: boolean; }; reducerWithAnotherPrepareNotation: (char: string, repeats: number) => { type: "reducerWithAnotherPrepareNotation"; } & { payload: number; }; invalidReducerWithPrepareNotation: any; } +>slice : Slice<{ foo: string; }, { simpleReducer: (state: { foo: string; }, action: PayloadAction) => void; reducerWithPrepareNotation: { prepare: (char: string, repeats: number) => { payload: string; extraStuff: boolean; }; reducer: (state: { foo: string; }, action: { payload: string; extraStuff: boolean; } & { type: "reducerWithPrepareNotation"; }) => void; }; reducerWithAnotherPrepareNotation: { prepare: (char: string, repeats: number) => { payload: number; }; reducer: (state: { foo: string; }, action: { payload: number; } & { type: "reducerWithAnotherPrepareNotation"; }) => void; }; invalidReducerWithPrepareNotation: any; }> +>actions : { simpleReducer: (payload: string) => { type: "simpleReducer"; payload: string; }; reducerWithPrepareNotation: (char: string, repeats: number) => { type: "reducerWithPrepareNotation"; } & { payload: string; extraStuff: boolean; }; reducerWithAnotherPrepareNotation: (char: string, repeats: number) => { type: "reducerWithAnotherPrepareNotation"; } & { payload: number; }; invalidReducerWithPrepareNotation: any; } +>reducerWithPrepareNotation : (char: string, repeats: number) => { type: "reducerWithPrepareNotation"; } & { payload: string; extraStuff: boolean; } +} +{ + const _expectType: (char: string, repeats: number) => PayloadAction = slice.actions.reducerWithAnotherPrepareNotation +>_expectType : (char: string, repeats: number) => PayloadAction +>char : string +>repeats : number +>slice.actions.reducerWithAnotherPrepareNotation : (char: string, repeats: number) => { type: "reducerWithAnotherPrepareNotation"; } & { payload: number; } +>slice.actions : { simpleReducer: (payload: string) => { type: "simpleReducer"; payload: string; }; reducerWithPrepareNotation: (char: string, repeats: number) => { type: "reducerWithPrepareNotation"; } & { payload: string; extraStuff: boolean; }; reducerWithAnotherPrepareNotation: (char: string, repeats: number) => { type: "reducerWithAnotherPrepareNotation"; } & { payload: number; }; invalidReducerWithPrepareNotation: any; } +>slice : Slice<{ foo: string; }, { simpleReducer: (state: { foo: string; }, action: PayloadAction) => void; reducerWithPrepareNotation: { prepare: (char: string, repeats: number) => { payload: string; extraStuff: boolean; }; reducer: (state: { foo: string; }, action: { payload: string; extraStuff: boolean; } & { type: "reducerWithPrepareNotation"; }) => void; }; reducerWithAnotherPrepareNotation: { prepare: (char: string, repeats: number) => { payload: number; }; reducer: (state: { foo: string; }, action: { payload: number; } & { type: "reducerWithAnotherPrepareNotation"; }) => void; }; invalidReducerWithPrepareNotation: any; }> +>actions : { simpleReducer: (payload: string) => { type: "simpleReducer"; payload: string; }; reducerWithPrepareNotation: (char: string, repeats: number) => { type: "reducerWithPrepareNotation"; } & { payload: string; extraStuff: boolean; }; reducerWithAnotherPrepareNotation: (char: string, repeats: number) => { type: "reducerWithAnotherPrepareNotation"; } & { payload: number; }; invalidReducerWithPrepareNotation: any; } +>reducerWithAnotherPrepareNotation : (char: string, repeats: number) => { type: "reducerWithAnotherPrepareNotation"; } & { payload: number; } +} + diff --git a/testdata/tests/cases/compiler/quantifiedTypesReduxToolkit.ts b/testdata/tests/cases/compiler/quantifiedTypesReduxToolkit.ts new file mode 100644 index 00000000000..522a3f52c79 --- /dev/null +++ b/testdata/tests/cases/compiler/quantifiedTypesReduxToolkit.ts @@ -0,0 +1,79 @@ +// @lib: esnext +// https://github.com/microsoft/TypeScript/issues/51612#issuecomment-1375431039 + +declare const createSlice: + < S extends object + , Rs extends { [T1 in T]:

Reducer } + > + (slice: { + name: string, + initialState: S, + reducers: Rs + }) => + Slice + +type Reducer = + | ((state: S, action: P & { type: T }) => void) + | { reducer: (state: S, action: P & { type: T }) => void + , prepare: (...a: never) => P + } + +type Slice = + { actions: + { [K in keyof Rs]: + Rs[K] extends { prepare: (...a: infer A) => infer R } ? (...a: A) => { type: K } & R : + Rs[K] extends (state: never, action: PayloadAction) => unknown ? (payload: P) => { type: K, payload: P } : + never + } + } + +type PayloadAction

= + { type: string + , payload: P + } + +const slice = createSlice({ + name: "someSlice", + initialState: { + foo: "bar" + }, + reducers: { + simpleReducer: (state, action: PayloadAction) => { + state.foo = action.payload + }, + reducerWithPrepareNotation: { + prepare: (char: string, repeats: number) => { + return { payload: char.repeat(repeats), extraStuff: true } + }, + reducer: (state, action) => { + state.foo = action.payload + } + }, + reducerWithAnotherPrepareNotation: { + prepare: (char: string, repeats: number) => { + return { payload: repeats * char.length } + }, + reducer: (state, action) => { + state.foo = state.foo.slice(0, action.payload) + }, + }, + invalidReducerWithPrepareNotation: { + prepare: (char: string, repeats: number) => { + return { payload: repeats * char.length } + }, + reducer: (state, action: PayloadAction) => { + state.foo = action.payload + }, + }, + } +}) + +{ + const _expectType: (payload: string) => PayloadAction = slice.actions.simpleReducer +} +{ + const _expectType: (char: string, repeats: number) => PayloadAction = slice.actions.reducerWithPrepareNotation +} +{ + const _expectType: (char: string, repeats: number) => PayloadAction = slice.actions.reducerWithAnotherPrepareNotation +} From bbe80a654df6f4e4c37f6ff8b0c55cb1d29cd923 Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Sun, 11 Jan 2026 14:19:38 +0530 Subject: [PATCH 10/23] add #25051 usecase --- internal/checker/checker.go | 7 ++ .../compiler/quantifiedTypesIssue25051.js | 27 +++++++ .../quantifiedTypesIssue25051.symbols | 67 ++++++++++++++++++ .../compiler/quantifiedTypesIssue25051.types | 70 +++++++++++++++++++ .../compiler/quantifiedTypesIssue25051.ts | 14 ++++ 5 files changed, 185 insertions(+) create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesIssue25051.js create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesIssue25051.symbols create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesIssue25051.types create mode 100644 testdata/tests/cases/compiler/quantifiedTypesIssue25051.ts diff --git a/internal/checker/checker.go b/internal/checker/checker.go index fc0b358c6b9..2e2532fa19d 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -7372,6 +7372,10 @@ func (c *Checker) checkExpressionExWithContextualType(node *ast.Node, parentChec baseType = c.instantiateType(baseType, newTypeMapper(typeParameters, typeArguments)) t = c.checkExpressionWithContextualType(node, baseType, core.IfElse(parentInferenceContext != nil, parentInferenceContext, nil), CheckModeNormal|CheckModeQuantifiedContextual) + if t.flags&TypeFlagsUnion != 0 { + return t // if it's a union then the subtype relation checking is non-trivial and we'll let the relater handle it + } + if !c.checkTypeRelatedToAndOptionallyElaborate(t, baseType, c.assignableRelation, node, node, nil, nil) { return c.errorType // to avoid showing errors in parent TODO: maybe there is a better way to do this } @@ -10979,6 +10983,9 @@ func (c *Checker) checkPropertyAccessChain(node *ast.Node, checkMode CheckMode) } func (c *Checker) checkPropertyAccessExpressionOrQualifiedName(node *ast.Node, left *ast.Node, leftType *Type, right *ast.Node, checkMode CheckMode, writeOnly bool) *Type { + if leftType.flags&TypeFlagsQuantified != 0 { + return c.checkPropertyAccessExpressionOrQualifiedName(node, left, leftType.AsQuantifiedType().baseType, right, checkMode, writeOnly) + } parentSymbol := c.getResolvedSymbolOrNil(left) assignmentKind := getAssignmentTargetKind(node) widenedType := leftType diff --git a/testdata/baselines/reference/compiler/quantifiedTypesIssue25051.js b/testdata/baselines/reference/compiler/quantifiedTypesIssue25051.js new file mode 100644 index 00000000000..e9237b28999 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesIssue25051.js @@ -0,0 +1,27 @@ +//// [tests/cases/compiler/quantifiedTypesIssue25051.ts] //// + +//// [quantifiedTypesIssue25051.ts] +// https://github.com/microsoft/TypeScript/issues/25051 + +type NumberRecord = { kind: "n", v: number, f: (v: number) => void }; +type StringRecord = { kind: "s", v: string, f: (v: string) => void }; +type BooleanRecord = { kind: "b", v: boolean, f: (v: boolean) => void }; +type GenericRecord = { kind: string, v: T, f: (v: T) => void }; + +function processRecord(record: GenericRecord) { + record.f(record.v); +} +processRecord({} as NumberRecord) +processRecord({} as StringRecord) +processRecord({} as BooleanRecord) +processRecord({} as NumberRecord | StringRecord | BooleanRecord) + +//// [quantifiedTypesIssue25051.js] +// https://github.com/microsoft/TypeScript/issues/25051 +function processRecord(record) { + record.f(record.v); +} +processRecord({}); +processRecord({}); +processRecord({}); +processRecord({}); diff --git a/testdata/baselines/reference/compiler/quantifiedTypesIssue25051.symbols b/testdata/baselines/reference/compiler/quantifiedTypesIssue25051.symbols new file mode 100644 index 00000000000..11964624527 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesIssue25051.symbols @@ -0,0 +1,67 @@ +//// [tests/cases/compiler/quantifiedTypesIssue25051.ts] //// + +=== quantifiedTypesIssue25051.ts === +// https://github.com/microsoft/TypeScript/issues/25051 + +type NumberRecord = { kind: "n", v: number, f: (v: number) => void }; +>NumberRecord : Symbol(NumberRecord, Decl(quantifiedTypesIssue25051.ts, 0, 0)) +>kind : Symbol(kind, Decl(quantifiedTypesIssue25051.ts, 2, 21)) +>v : Symbol(v, Decl(quantifiedTypesIssue25051.ts, 2, 32)) +>f : Symbol(f, Decl(quantifiedTypesIssue25051.ts, 2, 43)) +>v : Symbol(v, Decl(quantifiedTypesIssue25051.ts, 2, 48)) + +type StringRecord = { kind: "s", v: string, f: (v: string) => void }; +>StringRecord : Symbol(StringRecord, Decl(quantifiedTypesIssue25051.ts, 2, 69)) +>kind : Symbol(kind, Decl(quantifiedTypesIssue25051.ts, 3, 21)) +>v : Symbol(v, Decl(quantifiedTypesIssue25051.ts, 3, 32)) +>f : Symbol(f, Decl(quantifiedTypesIssue25051.ts, 3, 43)) +>v : Symbol(v, Decl(quantifiedTypesIssue25051.ts, 3, 48)) + +type BooleanRecord = { kind: "b", v: boolean, f: (v: boolean) => void }; +>BooleanRecord : Symbol(BooleanRecord, Decl(quantifiedTypesIssue25051.ts, 3, 69)) +>kind : Symbol(kind, Decl(quantifiedTypesIssue25051.ts, 4, 22)) +>v : Symbol(v, Decl(quantifiedTypesIssue25051.ts, 4, 33)) +>f : Symbol(f, Decl(quantifiedTypesIssue25051.ts, 4, 45)) +>v : Symbol(v, Decl(quantifiedTypesIssue25051.ts, 4, 50)) + +type GenericRecord = { kind: string, v: T, f: (v: T) => void }; +>GenericRecord : Symbol(GenericRecord, Decl(quantifiedTypesIssue25051.ts, 4, 72)) +>T : Symbol(T, Decl(quantifiedTypesIssue25051.ts, 5, 22)) +>kind : Symbol(kind, Decl(quantifiedTypesIssue25051.ts, 5, 26)) +>v : Symbol(v, Decl(quantifiedTypesIssue25051.ts, 5, 40)) +>T : Symbol(T, Decl(quantifiedTypesIssue25051.ts, 5, 22)) +>f : Symbol(f, Decl(quantifiedTypesIssue25051.ts, 5, 46)) +>v : Symbol(v, Decl(quantifiedTypesIssue25051.ts, 5, 51)) +>T : Symbol(T, Decl(quantifiedTypesIssue25051.ts, 5, 22)) + +function processRecord(record: GenericRecord) { +>processRecord : Symbol(processRecord, Decl(quantifiedTypesIssue25051.ts, 5, 67)) +>record : Symbol(record, Decl(quantifiedTypesIssue25051.ts, 7, 23)) +>GenericRecord : Symbol(GenericRecord, Decl(quantifiedTypesIssue25051.ts, 4, 72)) + + record.f(record.v); +>record.f : Symbol(f, Decl(quantifiedTypesIssue25051.ts, 5, 46)) +>record : Symbol(record, Decl(quantifiedTypesIssue25051.ts, 7, 23)) +>f : Symbol(f, Decl(quantifiedTypesIssue25051.ts, 5, 46)) +>record.v : Symbol(v, Decl(quantifiedTypesIssue25051.ts, 5, 40)) +>record : Symbol(record, Decl(quantifiedTypesIssue25051.ts, 7, 23)) +>v : Symbol(v, Decl(quantifiedTypesIssue25051.ts, 5, 40)) +} +processRecord({} as NumberRecord) +>processRecord : Symbol(processRecord, Decl(quantifiedTypesIssue25051.ts, 5, 67)) +>NumberRecord : Symbol(NumberRecord, Decl(quantifiedTypesIssue25051.ts, 0, 0)) + +processRecord({} as StringRecord) +>processRecord : Symbol(processRecord, Decl(quantifiedTypesIssue25051.ts, 5, 67)) +>StringRecord : Symbol(StringRecord, Decl(quantifiedTypesIssue25051.ts, 2, 69)) + +processRecord({} as BooleanRecord) +>processRecord : Symbol(processRecord, Decl(quantifiedTypesIssue25051.ts, 5, 67)) +>BooleanRecord : Symbol(BooleanRecord, Decl(quantifiedTypesIssue25051.ts, 3, 69)) + +processRecord({} as NumberRecord | StringRecord | BooleanRecord) +>processRecord : Symbol(processRecord, Decl(quantifiedTypesIssue25051.ts, 5, 67)) +>NumberRecord : Symbol(NumberRecord, Decl(quantifiedTypesIssue25051.ts, 0, 0)) +>StringRecord : Symbol(StringRecord, Decl(quantifiedTypesIssue25051.ts, 2, 69)) +>BooleanRecord : Symbol(BooleanRecord, Decl(quantifiedTypesIssue25051.ts, 3, 69)) + diff --git a/testdata/baselines/reference/compiler/quantifiedTypesIssue25051.types b/testdata/baselines/reference/compiler/quantifiedTypesIssue25051.types new file mode 100644 index 00000000000..45dc1814390 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesIssue25051.types @@ -0,0 +1,70 @@ +//// [tests/cases/compiler/quantifiedTypesIssue25051.ts] //// + +=== quantifiedTypesIssue25051.ts === +// https://github.com/microsoft/TypeScript/issues/25051 + +type NumberRecord = { kind: "n", v: number, f: (v: number) => void }; +>NumberRecord : NumberRecord +>kind : "n" +>v : number +>f : (v: number) => void +>v : number + +type StringRecord = { kind: "s", v: string, f: (v: string) => void }; +>StringRecord : StringRecord +>kind : "s" +>v : string +>f : (v: string) => void +>v : string + +type BooleanRecord = { kind: "b", v: boolean, f: (v: boolean) => void }; +>BooleanRecord : BooleanRecord +>kind : "b" +>v : boolean +>f : (v: boolean) => void +>v : boolean + +type GenericRecord = { kind: string, v: T, f: (v: T) => void }; +>GenericRecord : { kind: string; v: T; f: (v: T) => void; } +>kind : string +>v : T +>f : (v: T) => void +>v : T + +function processRecord(record: GenericRecord) { +>processRecord : (record: { kind: string; v: T; f: (v: T) => void; }) => void +>record : { kind: string; v: T; f: (v: T) => void; } + + record.f(record.v); +>record.f(record.v) : void +>record.f : (v: T) => void +>record : { kind: string; v: T; f: (v: T) => void; } +>f : (v: T) => void +>record.v : T +>record : { kind: string; v: T; f: (v: T) => void; } +>v : T +} +processRecord({} as NumberRecord) +>processRecord({} as NumberRecord) : void +>processRecord : (record: { kind: string; v: T; f: (v: T) => void; }) => void +>{} as NumberRecord : NumberRecord +>{} : {} + +processRecord({} as StringRecord) +>processRecord({} as StringRecord) : void +>processRecord : (record: { kind: string; v: T; f: (v: T) => void; }) => void +>{} as StringRecord : StringRecord +>{} : {} + +processRecord({} as BooleanRecord) +>processRecord({} as BooleanRecord) : void +>processRecord : (record: { kind: string; v: T; f: (v: T) => void; }) => void +>{} as BooleanRecord : BooleanRecord +>{} : {} + +processRecord({} as NumberRecord | StringRecord | BooleanRecord) +>processRecord({} as NumberRecord | StringRecord | BooleanRecord) : void +>processRecord : (record: { kind: string; v: T; f: (v: T) => void; }) => void +>{} as NumberRecord | StringRecord | BooleanRecord : BooleanRecord | NumberRecord | StringRecord +>{} : {} + diff --git a/testdata/tests/cases/compiler/quantifiedTypesIssue25051.ts b/testdata/tests/cases/compiler/quantifiedTypesIssue25051.ts new file mode 100644 index 00000000000..f7d75c268f0 --- /dev/null +++ b/testdata/tests/cases/compiler/quantifiedTypesIssue25051.ts @@ -0,0 +1,14 @@ +// https://github.com/microsoft/TypeScript/issues/25051 + +type NumberRecord = { kind: "n", v: number, f: (v: number) => void }; +type StringRecord = { kind: "s", v: string, f: (v: string) => void }; +type BooleanRecord = { kind: "b", v: boolean, f: (v: boolean) => void }; +type GenericRecord = { kind: string, v: T, f: (v: T) => void }; + +function processRecord(record: GenericRecord) { + record.f(record.v); +} +processRecord({} as NumberRecord) +processRecord({} as StringRecord) +processRecord({} as BooleanRecord) +processRecord({} as NumberRecord | StringRecord | BooleanRecord) \ No newline at end of file From d84379f84a5b9adf07485d794b1b5a9ff86fa700 Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Sun, 11 Jan 2026 14:21:15 +0530 Subject: [PATCH 11/23] will fix infinite recursions in some jsx cases later --- internal/checker/checker.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/internal/checker/checker.go b/internal/checker/checker.go index 2e2532fa19d..7f0853aff48 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -7329,9 +7329,6 @@ func (c *Checker) checkExpressionEx(node *ast.Node, checkMode CheckMode) *Type { // we now have too many checkExpression* functions and it's a bit of a spagetti so maybe there is a better way to do this // but it's done this way to reduce the number of locations where a change has to be made for quantified types func (c *Checker) checkExpressionExWithContextualType(node *ast.Node, parentCheckMode CheckMode, contextualType *Type, parentInferenceContext *InferenceContext) *Type { - if node.Kind == ast.KindIdentifier { // to avoid recursion in some jsx test cases TODO: come up with a better fix - return c.checkExpressionExWorker(node, parentCheckMode) - } if contextualType == nil { contextualType = c.getApparentTypeOfContextualType(node, ContextFlagsNone) } From 9ce47b8f7a99f7706d59ca2a4ebfdeb47b05b9f7 Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Fri, 16 Jan 2026 22:51:29 +0530 Subject: [PATCH 12/23] rename test and add todo --- .../quantifiedTypesIssue25051.symbols | 67 --------------- ...e25051.js => quantifiedTypesIssue30581.js} | 19 +++-- .../quantifiedTypesIssue30581.symbols | 82 +++++++++++++++++++ ....types => quantifiedTypesIssue30581.types} | 20 ++++- ...e25051.ts => quantifiedTypesIssue30581.ts} | 8 +- 5 files changed, 118 insertions(+), 78 deletions(-) delete mode 100644 testdata/baselines/reference/compiler/quantifiedTypesIssue25051.symbols rename testdata/baselines/reference/compiler/{quantifiedTypesIssue25051.js => quantifiedTypesIssue30581.js} (57%) create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesIssue30581.symbols rename testdata/baselines/reference/compiler/{quantifiedTypesIssue25051.types => quantifiedTypesIssue30581.types} (70%) rename testdata/tests/cases/compiler/{quantifiedTypesIssue25051.ts => quantifiedTypesIssue30581.ts} (73%) diff --git a/testdata/baselines/reference/compiler/quantifiedTypesIssue25051.symbols b/testdata/baselines/reference/compiler/quantifiedTypesIssue25051.symbols deleted file mode 100644 index 11964624527..00000000000 --- a/testdata/baselines/reference/compiler/quantifiedTypesIssue25051.symbols +++ /dev/null @@ -1,67 +0,0 @@ -//// [tests/cases/compiler/quantifiedTypesIssue25051.ts] //// - -=== quantifiedTypesIssue25051.ts === -// https://github.com/microsoft/TypeScript/issues/25051 - -type NumberRecord = { kind: "n", v: number, f: (v: number) => void }; ->NumberRecord : Symbol(NumberRecord, Decl(quantifiedTypesIssue25051.ts, 0, 0)) ->kind : Symbol(kind, Decl(quantifiedTypesIssue25051.ts, 2, 21)) ->v : Symbol(v, Decl(quantifiedTypesIssue25051.ts, 2, 32)) ->f : Symbol(f, Decl(quantifiedTypesIssue25051.ts, 2, 43)) ->v : Symbol(v, Decl(quantifiedTypesIssue25051.ts, 2, 48)) - -type StringRecord = { kind: "s", v: string, f: (v: string) => void }; ->StringRecord : Symbol(StringRecord, Decl(quantifiedTypesIssue25051.ts, 2, 69)) ->kind : Symbol(kind, Decl(quantifiedTypesIssue25051.ts, 3, 21)) ->v : Symbol(v, Decl(quantifiedTypesIssue25051.ts, 3, 32)) ->f : Symbol(f, Decl(quantifiedTypesIssue25051.ts, 3, 43)) ->v : Symbol(v, Decl(quantifiedTypesIssue25051.ts, 3, 48)) - -type BooleanRecord = { kind: "b", v: boolean, f: (v: boolean) => void }; ->BooleanRecord : Symbol(BooleanRecord, Decl(quantifiedTypesIssue25051.ts, 3, 69)) ->kind : Symbol(kind, Decl(quantifiedTypesIssue25051.ts, 4, 22)) ->v : Symbol(v, Decl(quantifiedTypesIssue25051.ts, 4, 33)) ->f : Symbol(f, Decl(quantifiedTypesIssue25051.ts, 4, 45)) ->v : Symbol(v, Decl(quantifiedTypesIssue25051.ts, 4, 50)) - -type GenericRecord = { kind: string, v: T, f: (v: T) => void }; ->GenericRecord : Symbol(GenericRecord, Decl(quantifiedTypesIssue25051.ts, 4, 72)) ->T : Symbol(T, Decl(quantifiedTypesIssue25051.ts, 5, 22)) ->kind : Symbol(kind, Decl(quantifiedTypesIssue25051.ts, 5, 26)) ->v : Symbol(v, Decl(quantifiedTypesIssue25051.ts, 5, 40)) ->T : Symbol(T, Decl(quantifiedTypesIssue25051.ts, 5, 22)) ->f : Symbol(f, Decl(quantifiedTypesIssue25051.ts, 5, 46)) ->v : Symbol(v, Decl(quantifiedTypesIssue25051.ts, 5, 51)) ->T : Symbol(T, Decl(quantifiedTypesIssue25051.ts, 5, 22)) - -function processRecord(record: GenericRecord) { ->processRecord : Symbol(processRecord, Decl(quantifiedTypesIssue25051.ts, 5, 67)) ->record : Symbol(record, Decl(quantifiedTypesIssue25051.ts, 7, 23)) ->GenericRecord : Symbol(GenericRecord, Decl(quantifiedTypesIssue25051.ts, 4, 72)) - - record.f(record.v); ->record.f : Symbol(f, Decl(quantifiedTypesIssue25051.ts, 5, 46)) ->record : Symbol(record, Decl(quantifiedTypesIssue25051.ts, 7, 23)) ->f : Symbol(f, Decl(quantifiedTypesIssue25051.ts, 5, 46)) ->record.v : Symbol(v, Decl(quantifiedTypesIssue25051.ts, 5, 40)) ->record : Symbol(record, Decl(quantifiedTypesIssue25051.ts, 7, 23)) ->v : Symbol(v, Decl(quantifiedTypesIssue25051.ts, 5, 40)) -} -processRecord({} as NumberRecord) ->processRecord : Symbol(processRecord, Decl(quantifiedTypesIssue25051.ts, 5, 67)) ->NumberRecord : Symbol(NumberRecord, Decl(quantifiedTypesIssue25051.ts, 0, 0)) - -processRecord({} as StringRecord) ->processRecord : Symbol(processRecord, Decl(quantifiedTypesIssue25051.ts, 5, 67)) ->StringRecord : Symbol(StringRecord, Decl(quantifiedTypesIssue25051.ts, 2, 69)) - -processRecord({} as BooleanRecord) ->processRecord : Symbol(processRecord, Decl(quantifiedTypesIssue25051.ts, 5, 67)) ->BooleanRecord : Symbol(BooleanRecord, Decl(quantifiedTypesIssue25051.ts, 3, 69)) - -processRecord({} as NumberRecord | StringRecord | BooleanRecord) ->processRecord : Symbol(processRecord, Decl(quantifiedTypesIssue25051.ts, 5, 67)) ->NumberRecord : Symbol(NumberRecord, Decl(quantifiedTypesIssue25051.ts, 0, 0)) ->StringRecord : Symbol(StringRecord, Decl(quantifiedTypesIssue25051.ts, 2, 69)) ->BooleanRecord : Symbol(BooleanRecord, Decl(quantifiedTypesIssue25051.ts, 3, 69)) - diff --git a/testdata/baselines/reference/compiler/quantifiedTypesIssue25051.js b/testdata/baselines/reference/compiler/quantifiedTypesIssue30581.js similarity index 57% rename from testdata/baselines/reference/compiler/quantifiedTypesIssue25051.js rename to testdata/baselines/reference/compiler/quantifiedTypesIssue30581.js index e9237b28999..ac5056f2b6f 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesIssue25051.js +++ b/testdata/baselines/reference/compiler/quantifiedTypesIssue30581.js @@ -1,7 +1,7 @@ -//// [tests/cases/compiler/quantifiedTypesIssue25051.ts] //// +//// [tests/cases/compiler/quantifiedTypesIssue30581.ts] //// -//// [quantifiedTypesIssue25051.ts] -// https://github.com/microsoft/TypeScript/issues/25051 +//// [quantifiedTypesIssue30581.ts] +// https://github.com/microsoft/TypeScript/issues/30581 type NumberRecord = { kind: "n", v: number, f: (v: number) => void }; type StringRecord = { kind: "s", v: string, f: (v: string) => void }; @@ -14,10 +14,14 @@ function processRecord(record: GenericRecord) { processRecord({} as NumberRecord) processRecord({} as StringRecord) processRecord({} as BooleanRecord) -processRecord({} as NumberRecord | StringRecord | BooleanRecord) +processRecord({} as NumberRecord | StringRecord | BooleanRecord) + +function processRecord2(record1: GenericRecord, record2: GenericRecord) { + record1.f(record2.v); // TODO: should not compile +} -//// [quantifiedTypesIssue25051.js] -// https://github.com/microsoft/TypeScript/issues/25051 +//// [quantifiedTypesIssue30581.js] +// https://github.com/microsoft/TypeScript/issues/30581 function processRecord(record) { record.f(record.v); } @@ -25,3 +29,6 @@ processRecord({}); processRecord({}); processRecord({}); processRecord({}); +function processRecord2(record1, record2) { + record1.f(record2.v); // TODO: should not compile +} diff --git a/testdata/baselines/reference/compiler/quantifiedTypesIssue30581.symbols b/testdata/baselines/reference/compiler/quantifiedTypesIssue30581.symbols new file mode 100644 index 00000000000..6db3a8051e3 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesIssue30581.symbols @@ -0,0 +1,82 @@ +//// [tests/cases/compiler/quantifiedTypesIssue30581.ts] //// + +=== quantifiedTypesIssue30581.ts === +// https://github.com/microsoft/TypeScript/issues/30581 + +type NumberRecord = { kind: "n", v: number, f: (v: number) => void }; +>NumberRecord : Symbol(NumberRecord, Decl(quantifiedTypesIssue30581.ts, 0, 0)) +>kind : Symbol(kind, Decl(quantifiedTypesIssue30581.ts, 2, 21)) +>v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 2, 32)) +>f : Symbol(f, Decl(quantifiedTypesIssue30581.ts, 2, 43)) +>v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 2, 48)) + +type StringRecord = { kind: "s", v: string, f: (v: string) => void }; +>StringRecord : Symbol(StringRecord, Decl(quantifiedTypesIssue30581.ts, 2, 69)) +>kind : Symbol(kind, Decl(quantifiedTypesIssue30581.ts, 3, 21)) +>v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 3, 32)) +>f : Symbol(f, Decl(quantifiedTypesIssue30581.ts, 3, 43)) +>v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 3, 48)) + +type BooleanRecord = { kind: "b", v: boolean, f: (v: boolean) => void }; +>BooleanRecord : Symbol(BooleanRecord, Decl(quantifiedTypesIssue30581.ts, 3, 69)) +>kind : Symbol(kind, Decl(quantifiedTypesIssue30581.ts, 4, 22)) +>v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 4, 33)) +>f : Symbol(f, Decl(quantifiedTypesIssue30581.ts, 4, 45)) +>v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 4, 50)) + +type GenericRecord = { kind: string, v: T, f: (v: T) => void }; +>GenericRecord : Symbol(GenericRecord, Decl(quantifiedTypesIssue30581.ts, 4, 72)) +>T : Symbol(T, Decl(quantifiedTypesIssue30581.ts, 5, 22)) +>kind : Symbol(kind, Decl(quantifiedTypesIssue30581.ts, 5, 26)) +>v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 5, 40)) +>T : Symbol(T, Decl(quantifiedTypesIssue30581.ts, 5, 22)) +>f : Symbol(f, Decl(quantifiedTypesIssue30581.ts, 5, 46)) +>v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 5, 51)) +>T : Symbol(T, Decl(quantifiedTypesIssue30581.ts, 5, 22)) + +function processRecord(record: GenericRecord) { +>processRecord : Symbol(processRecord, Decl(quantifiedTypesIssue30581.ts, 5, 67)) +>record : Symbol(record, Decl(quantifiedTypesIssue30581.ts, 7, 23)) +>GenericRecord : Symbol(GenericRecord, Decl(quantifiedTypesIssue30581.ts, 4, 72)) + + record.f(record.v); +>record.f : Symbol(f, Decl(quantifiedTypesIssue30581.ts, 5, 46)) +>record : Symbol(record, Decl(quantifiedTypesIssue30581.ts, 7, 23)) +>f : Symbol(f, Decl(quantifiedTypesIssue30581.ts, 5, 46)) +>record.v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 5, 40)) +>record : Symbol(record, Decl(quantifiedTypesIssue30581.ts, 7, 23)) +>v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 5, 40)) +} +processRecord({} as NumberRecord) +>processRecord : Symbol(processRecord, Decl(quantifiedTypesIssue30581.ts, 5, 67)) +>NumberRecord : Symbol(NumberRecord, Decl(quantifiedTypesIssue30581.ts, 0, 0)) + +processRecord({} as StringRecord) +>processRecord : Symbol(processRecord, Decl(quantifiedTypesIssue30581.ts, 5, 67)) +>StringRecord : Symbol(StringRecord, Decl(quantifiedTypesIssue30581.ts, 2, 69)) + +processRecord({} as BooleanRecord) +>processRecord : Symbol(processRecord, Decl(quantifiedTypesIssue30581.ts, 5, 67)) +>BooleanRecord : Symbol(BooleanRecord, Decl(quantifiedTypesIssue30581.ts, 3, 69)) + +processRecord({} as NumberRecord | StringRecord | BooleanRecord) +>processRecord : Symbol(processRecord, Decl(quantifiedTypesIssue30581.ts, 5, 67)) +>NumberRecord : Symbol(NumberRecord, Decl(quantifiedTypesIssue30581.ts, 0, 0)) +>StringRecord : Symbol(StringRecord, Decl(quantifiedTypesIssue30581.ts, 2, 69)) +>BooleanRecord : Symbol(BooleanRecord, Decl(quantifiedTypesIssue30581.ts, 3, 69)) + +function processRecord2(record1: GenericRecord, record2: GenericRecord) { +>processRecord2 : Symbol(processRecord2, Decl(quantifiedTypesIssue30581.ts, 13, 64)) +>record1 : Symbol(record1, Decl(quantifiedTypesIssue30581.ts, 15, 24)) +>GenericRecord : Symbol(GenericRecord, Decl(quantifiedTypesIssue30581.ts, 4, 72)) +>record2 : Symbol(record2, Decl(quantifiedTypesIssue30581.ts, 15, 47)) +>GenericRecord : Symbol(GenericRecord, Decl(quantifiedTypesIssue30581.ts, 4, 72)) + + record1.f(record2.v); // TODO: should not compile +>record1.f : Symbol(f, Decl(quantifiedTypesIssue30581.ts, 5, 46)) +>record1 : Symbol(record1, Decl(quantifiedTypesIssue30581.ts, 15, 24)) +>f : Symbol(f, Decl(quantifiedTypesIssue30581.ts, 5, 46)) +>record2.v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 5, 40)) +>record2 : Symbol(record2, Decl(quantifiedTypesIssue30581.ts, 15, 47)) +>v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 5, 40)) +} diff --git a/testdata/baselines/reference/compiler/quantifiedTypesIssue25051.types b/testdata/baselines/reference/compiler/quantifiedTypesIssue30581.types similarity index 70% rename from testdata/baselines/reference/compiler/quantifiedTypesIssue25051.types rename to testdata/baselines/reference/compiler/quantifiedTypesIssue30581.types index 45dc1814390..9044a0366f7 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesIssue25051.types +++ b/testdata/baselines/reference/compiler/quantifiedTypesIssue30581.types @@ -1,7 +1,7 @@ -//// [tests/cases/compiler/quantifiedTypesIssue25051.ts] //// +//// [tests/cases/compiler/quantifiedTypesIssue30581.ts] //// -=== quantifiedTypesIssue25051.ts === -// https://github.com/microsoft/TypeScript/issues/25051 +=== quantifiedTypesIssue30581.ts === +// https://github.com/microsoft/TypeScript/issues/30581 type NumberRecord = { kind: "n", v: number, f: (v: number) => void }; >NumberRecord : NumberRecord @@ -68,3 +68,17 @@ processRecord({} as NumberRecord | StringRecord | BooleanRecord) >{} as NumberRecord | StringRecord | BooleanRecord : BooleanRecord | NumberRecord | StringRecord >{} : {} +function processRecord2(record1: GenericRecord, record2: GenericRecord) { +>processRecord2 : (record1: { kind: string; v: T; f: (v: T) => void; }, record2: { kind: string; v: T; f: (v: T) => void; }) => void +>record1 : { kind: string; v: T; f: (v: T) => void; } +>record2 : { kind: string; v: T; f: (v: T) => void; } + + record1.f(record2.v); // TODO: should not compile +>record1.f(record2.v) : void +>record1.f : (v: T) => void +>record1 : { kind: string; v: T; f: (v: T) => void; } +>f : (v: T) => void +>record2.v : T +>record2 : { kind: string; v: T; f: (v: T) => void; } +>v : T +} diff --git a/testdata/tests/cases/compiler/quantifiedTypesIssue25051.ts b/testdata/tests/cases/compiler/quantifiedTypesIssue30581.ts similarity index 73% rename from testdata/tests/cases/compiler/quantifiedTypesIssue25051.ts rename to testdata/tests/cases/compiler/quantifiedTypesIssue30581.ts index f7d75c268f0..d8a34e4f3ff 100644 --- a/testdata/tests/cases/compiler/quantifiedTypesIssue25051.ts +++ b/testdata/tests/cases/compiler/quantifiedTypesIssue30581.ts @@ -1,4 +1,4 @@ -// https://github.com/microsoft/TypeScript/issues/25051 +// https://github.com/microsoft/TypeScript/issues/30581 type NumberRecord = { kind: "n", v: number, f: (v: number) => void }; type StringRecord = { kind: "s", v: string, f: (v: string) => void }; @@ -11,4 +11,8 @@ function processRecord(record: GenericRecord) { processRecord({} as NumberRecord) processRecord({} as StringRecord) processRecord({} as BooleanRecord) -processRecord({} as NumberRecord | StringRecord | BooleanRecord) \ No newline at end of file +processRecord({} as NumberRecord | StringRecord | BooleanRecord) + +function processRecord2(record1: GenericRecord, record2: GenericRecord) { + record1.f(record2.v); // TODO: should not compile +} \ No newline at end of file From bf09fa5cfa62f33deeccbe0dd9bae220420c89a6 Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Fri, 16 Jan 2026 23:07:15 +0530 Subject: [PATCH 13/23] add failing test for parent inference context --- ...iedTypesParentInferenceContext4.errors.txt | 59 +++++ .../quantifiedTypesParentInferenceContext4.js | 71 +++++++ ...tifiedTypesParentInferenceContext4.symbols | 181 ++++++++++++++++ ...antifiedTypesParentInferenceContext4.types | 201 ++++++++++++++++++ .../quantifiedTypesParentInferenceContext4.ts | 47 ++++ 5 files changed, 559 insertions(+) create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext4.errors.txt create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext4.js create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext4.symbols create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext4.types create mode 100644 testdata/tests/cases/compiler/quantifiedTypesParentInferenceContext4.ts diff --git a/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext4.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext4.errors.txt new file mode 100644 index 00000000000..f4e36726619 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext4.errors.txt @@ -0,0 +1,59 @@ +quantifiedTypesParentInferenceContext4.ts(19,16): error TS2698: Spread types may only be created from object types. +quantifiedTypesParentInferenceContext4.ts(19,28): error TS2339: Property 'b' does not exist on type 'unknown'. +quantifiedTypesParentInferenceContext4.ts(22,15): error TS2698: Spread types may only be created from object types. + + +==== quantifiedTypesParentInferenceContext4.ts (3 errors) ==== + declare const f: + (x: + { + a: () => A, + ab: (a: A) => B, + nested: { + c: (b: B) => C, + cd: (c: C) => D, + }, + de: (d: D) => E + } + ) => void + + // TODO: this should compile just like the f1 call + f({ + a: () => ({ a: 0 }), + ab: x => ({ ...x, b: "" }), + nested: { + c: x => ({ ...x, c: +x.b }), + ~~~~ +!!! error TS2698: Spread types may only be created from object types. + ~ +!!! error TS2339: Property 'b' does not exist on type 'unknown'. + cd: x => ({ ...x, d: Boolean(x.c) }) + }, + de: x => ({ ...x, e: "" }) + ~~~~ +!!! error TS2698: Spread types may only be created from object types. + }) + + declare const f1: + + (x: + { + a: () => A, + ab: (a: A) => B, + nested: { + c: (b: B) => C, + cd: (c: C) => D, + }, + de: (d: D) => E + } + ) => void + + f1({ + a: () => ({ a: 0 }), + ab: x => ({ ...x, b: "" }), + nested: { + c: x => ({ ...x, c: +x.b }), + cd: x => ({ ...x, d: Boolean(x.c) }) + }, + de: x => ({ ...x, e: "" }) + }) \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext4.js b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext4.js new file mode 100644 index 00000000000..3e30236a66a --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext4.js @@ -0,0 +1,71 @@ +//// [tests/cases/compiler/quantifiedTypesParentInferenceContext4.ts] //// + +//// [quantifiedTypesParentInferenceContext4.ts] +declare const f: + (x: + { + a: () => A, + ab: (a: A) => B, + nested: { + c: (b: B) => C, + cd: (c: C) => D, + }, + de: (d: D) => E + } + ) => void + +// TODO: this should compile just like the f1 call +f({ + a: () => ({ a: 0 }), + ab: x => ({ ...x, b: "" }), + nested: { + c: x => ({ ...x, c: +x.b }), + cd: x => ({ ...x, d: Boolean(x.c) }) + }, + de: x => ({ ...x, e: "" }) +}) + +declare const f1: + + (x: + { + a: () => A, + ab: (a: A) => B, + nested: { + c: (b: B) => C, + cd: (c: C) => D, + }, + de: (d: D) => E + } + ) => void + +f1({ + a: () => ({ a: 0 }), + ab: x => ({ ...x, b: "" }), + nested: { + c: x => ({ ...x, c: +x.b }), + cd: x => ({ ...x, d: Boolean(x.c) }) + }, + de: x => ({ ...x, e: "" }) +}) + +//// [quantifiedTypesParentInferenceContext4.js] +// TODO: this should compile just like the f1 call +f({ + a: () => ({ a: 0 }), + ab: x => (Object.assign(Object.assign({}, x), { b: "" })), + nested: { + c: x => (Object.assign(Object.assign({}, x), { c: +x.b })), + cd: x => (Object.assign(Object.assign({}, x), { d: Boolean(x.c) })) + }, + de: x => (Object.assign(Object.assign({}, x), { e: "" })) +}); +f1({ + a: () => ({ a: 0 }), + ab: x => (Object.assign(Object.assign({}, x), { b: "" })), + nested: { + c: x => (Object.assign(Object.assign({}, x), { c: +x.b })), + cd: x => (Object.assign(Object.assign({}, x), { d: Boolean(x.c) })) + }, + de: x => (Object.assign(Object.assign({}, x), { e: "" })) +}); diff --git a/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext4.symbols b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext4.symbols new file mode 100644 index 00000000000..388aff3e9df --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext4.symbols @@ -0,0 +1,181 @@ +//// [tests/cases/compiler/quantifiedTypesParentInferenceContext4.ts] //// + +=== quantifiedTypesParentInferenceContext4.ts === +declare const f: +>f : Symbol(f, Decl(quantifiedTypesParentInferenceContext4.ts, 0, 13)) + + (x: +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext4.ts, 1, 3)) + + { +>A : Symbol(A, Decl(quantifiedTypesParentInferenceContext4.ts, 2, 5)) +>B : Symbol(B, Decl(quantifiedTypesParentInferenceContext4.ts, 2, 7)) +>D : Symbol(D, Decl(quantifiedTypesParentInferenceContext4.ts, 2, 10)) +>E : Symbol(E, Decl(quantifiedTypesParentInferenceContext4.ts, 2, 13)) + + a: () => A, +>a : Symbol(a, Decl(quantifiedTypesParentInferenceContext4.ts, 2, 18)) +>A : Symbol(A, Decl(quantifiedTypesParentInferenceContext4.ts, 2, 5)) + + ab: (a: A) => B, +>ab : Symbol(ab, Decl(quantifiedTypesParentInferenceContext4.ts, 3, 17)) +>a : Symbol(a, Decl(quantifiedTypesParentInferenceContext4.ts, 4, 11)) +>A : Symbol(A, Decl(quantifiedTypesParentInferenceContext4.ts, 2, 5)) +>B : Symbol(B, Decl(quantifiedTypesParentInferenceContext4.ts, 2, 7)) + + nested: { +>nested : Symbol(nested, Decl(quantifiedTypesParentInferenceContext4.ts, 4, 22)) +>C : Symbol(C, Decl(quantifiedTypesParentInferenceContext4.ts, 5, 15)) + + c: (b: B) => C, +>c : Symbol(c, Decl(quantifiedTypesParentInferenceContext4.ts, 5, 19)) +>b : Symbol(b, Decl(quantifiedTypesParentInferenceContext4.ts, 6, 12)) +>B : Symbol(B, Decl(quantifiedTypesParentInferenceContext4.ts, 2, 7)) +>C : Symbol(C, Decl(quantifiedTypesParentInferenceContext4.ts, 5, 15)) + + cd: (c: C) => D, +>cd : Symbol(cd, Decl(quantifiedTypesParentInferenceContext4.ts, 6, 23)) +>c : Symbol(c, Decl(quantifiedTypesParentInferenceContext4.ts, 7, 13)) +>C : Symbol(C, Decl(quantifiedTypesParentInferenceContext4.ts, 5, 15)) +>D : Symbol(D, Decl(quantifiedTypesParentInferenceContext4.ts, 2, 10)) + + }, + de: (d: D) => E +>de : Symbol(de, Decl(quantifiedTypesParentInferenceContext4.ts, 8, 8)) +>d : Symbol(d, Decl(quantifiedTypesParentInferenceContext4.ts, 9, 11)) +>D : Symbol(D, Decl(quantifiedTypesParentInferenceContext4.ts, 2, 10)) +>E : Symbol(E, Decl(quantifiedTypesParentInferenceContext4.ts, 2, 13)) + } + ) => void + +// TODO: this should compile just like the f1 call +f({ +>f : Symbol(f, Decl(quantifiedTypesParentInferenceContext4.ts, 0, 13)) + + a: () => ({ a: 0 }), +>a : Symbol(a, Decl(quantifiedTypesParentInferenceContext4.ts, 14, 3)) +>a : Symbol(a, Decl(quantifiedTypesParentInferenceContext4.ts, 15, 13)) + + ab: x => ({ ...x, b: "" }), +>ab : Symbol(ab, Decl(quantifiedTypesParentInferenceContext4.ts, 15, 22)) +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext4.ts, 16, 5)) +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext4.ts, 16, 5)) +>b : Symbol(b, Decl(quantifiedTypesParentInferenceContext4.ts, 16, 19)) + + nested: { +>nested : Symbol(nested, Decl(quantifiedTypesParentInferenceContext4.ts, 16, 29)) + + c: x => ({ ...x, c: +x.b }), +>c : Symbol(c, Decl(quantifiedTypesParentInferenceContext4.ts, 17, 11)) +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext4.ts, 18, 6)) +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext4.ts, 18, 6)) +>c : Symbol(c, Decl(quantifiedTypesParentInferenceContext4.ts, 18, 20)) +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext4.ts, 18, 6)) + + cd: x => ({ ...x, d: Boolean(x.c) }) +>cd : Symbol(cd, Decl(quantifiedTypesParentInferenceContext4.ts, 18, 32)) +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext4.ts, 19, 7)) +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext4.ts, 19, 7)) +>d : Symbol(d, Decl(quantifiedTypesParentInferenceContext4.ts, 19, 21)) +>Boolean : Symbol(Boolean, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext4.ts, 19, 7)) + + }, + de: x => ({ ...x, e: "" }) +>de : Symbol(de, Decl(quantifiedTypesParentInferenceContext4.ts, 20, 4)) +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext4.ts, 21, 5)) +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext4.ts, 21, 5)) +>e : Symbol(e, Decl(quantifiedTypesParentInferenceContext4.ts, 21, 19)) + +}) + +declare const f1: +>f1 : Symbol(f1, Decl(quantifiedTypesParentInferenceContext4.ts, 24, 13)) + + +>A : Symbol(A, Decl(quantifiedTypesParentInferenceContext4.ts, 25, 3)) +>B : Symbol(B, Decl(quantifiedTypesParentInferenceContext4.ts, 25, 5)) +>C : Symbol(C, Decl(quantifiedTypesParentInferenceContext4.ts, 25, 8)) +>D : Symbol(D, Decl(quantifiedTypesParentInferenceContext4.ts, 25, 11)) +>E : Symbol(E, Decl(quantifiedTypesParentInferenceContext4.ts, 25, 14)) + + (x: +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext4.ts, 26, 3)) + { + a: () => A, +>a : Symbol(a, Decl(quantifiedTypesParentInferenceContext4.ts, 27, 6)) +>A : Symbol(A, Decl(quantifiedTypesParentInferenceContext4.ts, 25, 3)) + + ab: (a: A) => B, +>ab : Symbol(ab, Decl(quantifiedTypesParentInferenceContext4.ts, 28, 17)) +>a : Symbol(a, Decl(quantifiedTypesParentInferenceContext4.ts, 29, 11)) +>A : Symbol(A, Decl(quantifiedTypesParentInferenceContext4.ts, 25, 3)) +>B : Symbol(B, Decl(quantifiedTypesParentInferenceContext4.ts, 25, 5)) + + nested: { +>nested : Symbol(nested, Decl(quantifiedTypesParentInferenceContext4.ts, 29, 22)) + + c: (b: B) => C, +>c : Symbol(c, Decl(quantifiedTypesParentInferenceContext4.ts, 30, 15)) +>b : Symbol(b, Decl(quantifiedTypesParentInferenceContext4.ts, 31, 12)) +>B : Symbol(B, Decl(quantifiedTypesParentInferenceContext4.ts, 25, 5)) +>C : Symbol(C, Decl(quantifiedTypesParentInferenceContext4.ts, 25, 8)) + + cd: (c: C) => D, +>cd : Symbol(cd, Decl(quantifiedTypesParentInferenceContext4.ts, 31, 23)) +>c : Symbol(c, Decl(quantifiedTypesParentInferenceContext4.ts, 32, 13)) +>C : Symbol(C, Decl(quantifiedTypesParentInferenceContext4.ts, 25, 8)) +>D : Symbol(D, Decl(quantifiedTypesParentInferenceContext4.ts, 25, 11)) + + }, + de: (d: D) => E +>de : Symbol(de, Decl(quantifiedTypesParentInferenceContext4.ts, 33, 8)) +>d : Symbol(d, Decl(quantifiedTypesParentInferenceContext4.ts, 34, 11)) +>D : Symbol(D, Decl(quantifiedTypesParentInferenceContext4.ts, 25, 11)) +>E : Symbol(E, Decl(quantifiedTypesParentInferenceContext4.ts, 25, 14)) + } + ) => void + +f1({ +>f1 : Symbol(f1, Decl(quantifiedTypesParentInferenceContext4.ts, 24, 13)) + + a: () => ({ a: 0 }), +>a : Symbol(a, Decl(quantifiedTypesParentInferenceContext4.ts, 38, 4)) +>a : Symbol(a, Decl(quantifiedTypesParentInferenceContext4.ts, 39, 13)) + + ab: x => ({ ...x, b: "" }), +>ab : Symbol(ab, Decl(quantifiedTypesParentInferenceContext4.ts, 39, 22)) +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext4.ts, 40, 5)) +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext4.ts, 40, 5)) +>b : Symbol(b, Decl(quantifiedTypesParentInferenceContext4.ts, 40, 19)) + + nested: { +>nested : Symbol(nested, Decl(quantifiedTypesParentInferenceContext4.ts, 40, 29)) + + c: x => ({ ...x, c: +x.b }), +>c : Symbol(c, Decl(quantifiedTypesParentInferenceContext4.ts, 41, 11)) +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext4.ts, 42, 6)) +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext4.ts, 42, 6)) +>c : Symbol(c, Decl(quantifiedTypesParentInferenceContext4.ts, 42, 20)) +>x.b : Symbol(b, Decl(quantifiedTypesParentInferenceContext4.ts, 40, 19)) +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext4.ts, 42, 6)) +>b : Symbol(b, Decl(quantifiedTypesParentInferenceContext4.ts, 40, 19)) + + cd: x => ({ ...x, d: Boolean(x.c) }) +>cd : Symbol(cd, Decl(quantifiedTypesParentInferenceContext4.ts, 42, 32)) +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext4.ts, 43, 7)) +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext4.ts, 43, 7)) +>d : Symbol(d, Decl(quantifiedTypesParentInferenceContext4.ts, 43, 21)) +>Boolean : Symbol(Boolean, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>x.c : Symbol(c, Decl(quantifiedTypesParentInferenceContext4.ts, 42, 20)) +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext4.ts, 43, 7)) +>c : Symbol(c, Decl(quantifiedTypesParentInferenceContext4.ts, 42, 20)) + + }, + de: x => ({ ...x, e: "" }) +>de : Symbol(de, Decl(quantifiedTypesParentInferenceContext4.ts, 44, 4)) +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext4.ts, 45, 5)) +>x : Symbol(x, Decl(quantifiedTypesParentInferenceContext4.ts, 45, 5)) +>e : Symbol(e, Decl(quantifiedTypesParentInferenceContext4.ts, 45, 19)) + +}) diff --git a/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext4.types b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext4.types new file mode 100644 index 00000000000..d4ef97110d4 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesParentInferenceContext4.types @@ -0,0 +1,201 @@ +//// [tests/cases/compiler/quantifiedTypesParentInferenceContext4.ts] //// + +=== quantifiedTypesParentInferenceContext4.ts === +declare const f: +>f : (x: { a: () => A; ab: (a: A) => B; nested: { c: (b: B) => C; cd: (c: C) => D; }; de: (d: D) => E; }) => void + + (x: +>x : { a: () => A; ab: (a: A) => B; nested: { c: (b: B) => C; cd: (c: C) => D; }; de: (d: D) => E; } + + { + a: () => A, +>a : () => A + + ab: (a: A) => B, +>ab : (a: A) => B +>a : A + + nested: { +>nested : { c: (b: B) => C; cd: (c: C) => D; } + + c: (b: B) => C, +>c : (b: B) => C +>b : B + + cd: (c: C) => D, +>cd : (c: C) => D +>c : C + + }, + de: (d: D) => E +>de : (d: D) => E +>d : D + } + ) => void + +// TODO: this should compile just like the f1 call +f({ +>f({ a: () => ({ a: 0 }), ab: x => ({ ...x, b: "" }), nested: { c: x => ({ ...x, c: +x.b }), cd: x => ({ ...x, d: Boolean(x.c) }) }, de: x => ({ ...x, e: "" })}) : void +>f : (x: { a: () => A; ab: (a: A) => B; nested: { c: (b: B) => C; cd: (c: C) => D; }; de: (d: D) => E; }) => void +>{ a: () => ({ a: 0 }), ab: x => ({ ...x, b: "" }), nested: { c: x => ({ ...x, c: +x.b }), cd: x => ({ ...x, d: Boolean(x.c) }) }, de: x => ({ ...x, e: "" })} : { a: () => { a: number; }; ab: (x: { a: number; }) => { a: number; b: string; }; nested: { c: (x: unknown) => any; cd: (x: any) => any; }; de: (x: unknown) => any; } + + a: () => ({ a: 0 }), +>a : () => { a: number; } +>() => ({ a: 0 }) : () => { a: number; } +>({ a: 0 }) : { a: number; } +>{ a: 0 } : { a: number; } +>a : number +>0 : 0 + + ab: x => ({ ...x, b: "" }), +>ab : (x: { a: number; }) => { a: number; b: string; } +>x => ({ ...x, b: "" }) : (x: { a: number; }) => { a: number; b: string; } +>x : { a: number; } +>({ ...x, b: "" }) : { a: number; b: string; } +>{ ...x, b: "" } : { a: number; b: string; } +>x : { a: number; } +>b : string +>"" : "" + + nested: { +>nested : { c: (x: unknown) => any; cd: (x: any) => any; } +>{ c: x => ({ ...x, c: +x.b }), cd: x => ({ ...x, d: Boolean(x.c) }) } : { c: (x: unknown) => any; cd: (x: any) => any; } + + c: x => ({ ...x, c: +x.b }), +>c : (x: unknown) => any +>x => ({ ...x, c: +x.b }) : (x: unknown) => any +>x : unknown +>({ ...x, c: +x.b }) : any +>{ ...x, c: +x.b } : any +>x : unknown +>c : number +>+x.b : number +>x.b : any +>x : unknown +>b : any + + cd: x => ({ ...x, d: Boolean(x.c) }) +>cd : (x: any) => any +>x => ({ ...x, d: Boolean(x.c) }) : (x: any) => any +>x : any +>({ ...x, d: Boolean(x.c) }) : any +>{ ...x, d: Boolean(x.c) } : any +>x : any +>d : boolean +>Boolean(x.c) : boolean +>Boolean : BooleanConstructor +>x.c : any +>x : any +>c : any + + }, + de: x => ({ ...x, e: "" }) +>de : (x: unknown) => any +>x => ({ ...x, e: "" }) : (x: unknown) => any +>x : unknown +>({ ...x, e: "" }) : any +>{ ...x, e: "" } : any +>x : unknown +>e : string +>"" : "" + +}) + +declare const f1: +>f1 : (x: { a: () => A; ab: (a: A) => B; nested: { c: (b: B) => C; cd: (c: C) => D; }; de: (d: D) => E; }) => void + + + (x: +>x : { a: () => A; ab: (a: A) => B; nested: { c: (b: B) => C; cd: (c: C) => D; }; de: (d: D) => E; } + { + a: () => A, +>a : () => A + + ab: (a: A) => B, +>ab : (a: A) => B +>a : A + + nested: { +>nested : { c: (b: B) => C; cd: (c: C) => D; } + + c: (b: B) => C, +>c : (b: B) => C +>b : B + + cd: (c: C) => D, +>cd : (c: C) => D +>c : C + + }, + de: (d: D) => E +>de : (d: D) => E +>d : D + } + ) => void + +f1({ +>f1({ a: () => ({ a: 0 }), ab: x => ({ ...x, b: "" }), nested: { c: x => ({ ...x, c: +x.b }), cd: x => ({ ...x, d: Boolean(x.c) }) }, de: x => ({ ...x, e: "" })}) : void +>f1 : (x: { a: () => A; ab: (a: A) => B; nested: { c: (b: B) => C; cd: (c: C) => D; }; de: (d: D) => E; }) => void +>{ a: () => ({ a: 0 }), ab: x => ({ ...x, b: "" }), nested: { c: x => ({ ...x, c: +x.b }), cd: x => ({ ...x, d: Boolean(x.c) }) }, de: x => ({ ...x, e: "" })} : { a: () => { a: number; }; ab: (x: { a: number; }) => { a: number; b: string; }; nested: { c: (x: { a: number; b: string; }) => { a: number; b: string; c: number; }; cd: (x: { a: number; b: string; c: number; }) => { a: number; b: string; c: number; d: boolean; }; }; de: (x: { a: number; b: string; c: number; d: boolean; }) => { a: number; b: string; c: number; d: boolean; e: string; }; } + + a: () => ({ a: 0 }), +>a : () => { a: number; } +>() => ({ a: 0 }) : () => { a: number; } +>({ a: 0 }) : { a: number; } +>{ a: 0 } : { a: number; } +>a : number +>0 : 0 + + ab: x => ({ ...x, b: "" }), +>ab : (x: { a: number; }) => { a: number; b: string; } +>x => ({ ...x, b: "" }) : (x: { a: number; }) => { a: number; b: string; } +>x : { a: number; } +>({ ...x, b: "" }) : { a: number; b: string; } +>{ ...x, b: "" } : { a: number; b: string; } +>x : { a: number; } +>b : string +>"" : "" + + nested: { +>nested : { c: (x: { a: number; b: string; }) => { a: number; b: string; c: number; }; cd: (x: { a: number; b: string; c: number; }) => { a: number; b: string; c: number; d: boolean; }; } +>{ c: x => ({ ...x, c: +x.b }), cd: x => ({ ...x, d: Boolean(x.c) }) } : { c: (x: { a: number; b: string; }) => { a: number; b: string; c: number; }; cd: (x: { a: number; b: string; c: number; }) => { a: number; b: string; c: number; d: boolean; }; } + + c: x => ({ ...x, c: +x.b }), +>c : (x: { a: number; b: string; }) => { a: number; b: string; c: number; } +>x => ({ ...x, c: +x.b }) : (x: { a: number; b: string; }) => { a: number; b: string; c: number; } +>x : { a: number; b: string; } +>({ ...x, c: +x.b }) : { a: number; b: string; c: number; } +>{ ...x, c: +x.b } : { a: number; b: string; c: number; } +>x : { a: number; b: string; } +>c : number +>+x.b : number +>x.b : string +>x : { a: number; b: string; } +>b : string + + cd: x => ({ ...x, d: Boolean(x.c) }) +>cd : (x: { a: number; b: string; c: number; }) => { a: number; b: string; c: number; d: boolean; } +>x => ({ ...x, d: Boolean(x.c) }) : (x: { a: number; b: string; c: number; }) => { a: number; b: string; c: number; d: boolean; } +>x : { a: number; b: string; c: number; } +>({ ...x, d: Boolean(x.c) }) : { a: number; b: string; c: number; d: boolean; } +>{ ...x, d: Boolean(x.c) } : { a: number; b: string; c: number; d: boolean; } +>x : { a: number; b: string; c: number; } +>d : boolean +>Boolean(x.c) : boolean +>Boolean : BooleanConstructor +>x.c : number +>x : { a: number; b: string; c: number; } +>c : number + + }, + de: x => ({ ...x, e: "" }) +>de : (x: { a: number; b: string; c: number; d: boolean; }) => { a: number; b: string; c: number; d: boolean; e: string; } +>x => ({ ...x, e: "" }) : (x: { a: number; b: string; c: number; d: boolean; }) => { a: number; b: string; c: number; d: boolean; e: string; } +>x : { a: number; b: string; c: number; d: boolean; } +>({ ...x, e: "" }) : { a: number; b: string; c: number; d: boolean; e: string; } +>{ ...x, e: "" } : { a: number; b: string; c: number; d: boolean; e: string; } +>x : { a: number; b: string; c: number; d: boolean; } +>e : string +>"" : "" + +}) diff --git a/testdata/tests/cases/compiler/quantifiedTypesParentInferenceContext4.ts b/testdata/tests/cases/compiler/quantifiedTypesParentInferenceContext4.ts new file mode 100644 index 00000000000..aa6fd01e1d1 --- /dev/null +++ b/testdata/tests/cases/compiler/quantifiedTypesParentInferenceContext4.ts @@ -0,0 +1,47 @@ +declare const f: + (x: + { + a: () => A, + ab: (a: A) => B, + nested: { + c: (b: B) => C, + cd: (c: C) => D, + }, + de: (d: D) => E + } + ) => void + +// TODO: this should compile just like the f1 call +f({ + a: () => ({ a: 0 }), + ab: x => ({ ...x, b: "" }), + nested: { + c: x => ({ ...x, c: +x.b }), + cd: x => ({ ...x, d: Boolean(x.c) }) + }, + de: x => ({ ...x, e: "" }) +}) + +declare const f1: + + (x: + { + a: () => A, + ab: (a: A) => B, + nested: { + c: (b: B) => C, + cd: (c: C) => D, + }, + de: (d: D) => E + } + ) => void + +f1({ + a: () => ({ a: 0 }), + ab: x => ({ ...x, b: "" }), + nested: { + c: x => ({ ...x, c: +x.b }), + cd: x => ({ ...x, d: Boolean(x.c) }) + }, + de: x => ({ ...x, e: "" }) +}) \ No newline at end of file From 5f21027f84510d008d6e66d7a0f8c489885f258e Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Sat, 17 Jan 2026 22:08:24 +0530 Subject: [PATCH 14/23] bind type parameters to variable declarations --- internal/checker/checker.go | 56 ++++++++++--- internal/checker/types.go | 4 +- ...quantifiedTypesCorrelatedUnions.errors.txt | 27 ++++++ ....js => quantifiedTypesCorrelatedUnions.js} | 10 +-- .../quantifiedTypesCorrelatedUnions.symbols | 82 +++++++++++++++++++ ... => quantifiedTypesCorrelatedUnions.types} | 8 +- .../quantifiedTypesIssue30581.symbols | 82 ------------------- ....ts => quantifiedTypesCorrelatedUnions.ts} | 2 +- 8 files changed, 165 insertions(+), 106 deletions(-) create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.errors.txt rename testdata/baselines/reference/compiler/{quantifiedTypesIssue30581.js => quantifiedTypesCorrelatedUnions.js} (77%) create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.symbols rename testdata/baselines/reference/compiler/{quantifiedTypesIssue30581.types => quantifiedTypesCorrelatedUnions.types} (88%) delete mode 100644 testdata/baselines/reference/compiler/quantifiedTypesIssue30581.symbols rename testdata/tests/cases/compiler/{quantifiedTypesIssue30581.ts => quantifiedTypesCorrelatedUnions.ts} (92%) diff --git a/internal/checker/checker.go b/internal/checker/checker.go index 7f0853aff48..d3862dddee9 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -16119,6 +16119,22 @@ func (c *Checker) getTypeOfVariableOrParameterOrProperty(symbol *ast.Symbol) *Ty if t == nil { panic("Unexpected nil type") } + if t.objectFlags&ObjectFlagsContainsQuantifiedType != 0 { + mapper := make(map[*Type]*Type) + t = c.instantiateType(t, newFunctionTypeMapper(func(t *Type) *Type { + if t.objectFlags&ObjectFlagsQuantifiedTypeParameter != 0 { + newT, seen := mapper[t] + if seen { + return newT + } + newT = c.cloneTypeParameter(t) + newT.objectFlags |= ObjectFlagsQuantifiedTypeParameter + mapper[t] = newT + return newT + } + return t + })) + } // For a contextually typed parameter it is possible that a type has already // been assigned (in assignTypeToParameterAndFixTypeParameters), and we want // to preserve this type. In fact, we need to _prefer_ that type, but it won't @@ -21670,16 +21686,23 @@ func (c *Checker) instantiateTypeWorker(t *Type, m *TypeMapper, alias *TypeAlias flags := t.flags switch { case flags&TypeFlagsTypeParameter != 0: - return m.Map(t) + newT := m.Map(t) + if newT.objectFlags&ObjectFlagsQuantifiedTypeParameter != 0 { + newT.AsTypeParameter().mapper = c.combineTypeMappers(newT.AsTypeParameter().mapper, m) + } + return newT case flags&TypeFlagsQuantified != 0: return c.newQuantifiedType( - t.AsQuantifiedType().typeParameters, - // TODO: the following does not work figure out a way to do it - /*core.Map(t.AsQuantifiedType().typeParameters, func(tp *TypeParameter) *TypeParameter { - newTp := c.cloneTypeParameter(tp.AsType()) - newTp.AsTypeParameter().constraint = c.instantiateType(newTp.AsTypeParameter().constraint, m) - return newTp.AsTypeParameter() - }),*/ + core.Map( + c.instantiateTypes( + core.Map( + t.AsQuantifiedType().typeParameters, + func(tp *TypeParameter) *Type { return tp.AsType() }, + ), + m, + ), + func(t *Type) *TypeParameter { return t.AsTypeParameter() }, + ), c.instantiateType(t.AsQuantifiedType().baseType, m), ) case flags&TypeFlagsObject != 0: @@ -24035,11 +24058,18 @@ func (c *Checker) getTypeFromImportTypeNode(node *ast.Node) *Type { func (c *Checker) getTypeFromQuantifiedTypeNode(node *ast.Node) *Type { links := c.typeNodeLinks.Get(node) if links.resolvedType == nil { + typeParameters := core.Map(node.AsQuantifiedTypeNode().TypeParameters.Nodes, func(typeParameterNode *ast.Node) *Type { + return c.getDeclaredTypeOfTypeParameter(typeParameterNode.Symbol()) + }) + newTypeParameters := core.Map(typeParameters, func(tp *Type) *Type { + newTp := c.cloneTypeParameter(tp) + newTp.objectFlags |= ObjectFlagsQuantifiedTypeParameter + return newTp + }) + mapper := newTypeMapper(typeParameters, newTypeParameters) links.resolvedType = c.newQuantifiedType( - core.Map(node.AsQuantifiedTypeNode().TypeParameters.Nodes, func(typeParameterNode *ast.Node) *TypeParameter { - return c.getDeclaredTypeOfTypeParameter(typeParameterNode.Symbol()).AsTypeParameter() - }), - c.getTypeFromTypeNode(node.AsQuantifiedTypeNode().BaseType), + core.Map(c.instantiateTypes(typeParameters, mapper), func(t *Type) *TypeParameter { return t.AsTypeParameter() }), + c.instantiateType(c.getTypeFromTypeNode(node.AsQuantifiedTypeNode().BaseType), mapper), ) } return links.resolvedType @@ -24640,7 +24670,7 @@ func (c *Checker) newQuantifiedType(typeParamters []*TypeParameter, baseType *Ty data := &QuantifiedType{} data.typeParameters = typeParamters data.baseType = baseType - return c.newType(TypeFlagsQuantified, ObjectFlagsNone, data) + return c.newType(TypeFlagsQuantified, ObjectFlagsContainsQuantifiedType, data) } func (c *Checker) newSignature(flags SignatureFlags, declaration *ast.Node, typeParameters []*Type, thisParameter *ast.Symbol, parameters []*ast.Symbol, resolvedReturnType *Type, resolvedTypePredicate *TypePredicate, minArgumentCount int) *Signature { diff --git a/internal/checker/types.go b/internal/checker/types.go index b872bd7b510..c4ae7e98d92 100644 --- a/internal/checker/types.go +++ b/internal/checker/types.go @@ -498,10 +498,12 @@ const ( ObjectFlagsCouldContainTypeVariablesComputed ObjectFlags = 1 << 19 // CouldContainTypeVariables flag has been computed ObjectFlagsCouldContainTypeVariables ObjectFlags = 1 << 20 // Type could contain a type variable ObjectFlagsMembersResolved ObjectFlags = 1 << 21 // Members have been resolved + ObjectFlagsContainsQuantifiedType ObjectFlags = 1 << 22 + ObjectFlagsQuantifiedTypeParameter ObjectFlags = 1 << 23 ObjectFlagsClassOrInterface = ObjectFlagsClass | ObjectFlagsInterface ObjectFlagsRequiresWidening = ObjectFlagsContainsWideningType | ObjectFlagsContainsObjectOrArrayLiteral - ObjectFlagsPropagatingFlags = ObjectFlagsContainsWideningType | ObjectFlagsContainsObjectOrArrayLiteral | ObjectFlagsNonInferrableType + ObjectFlagsPropagatingFlags = ObjectFlagsContainsWideningType | ObjectFlagsContainsObjectOrArrayLiteral | ObjectFlagsNonInferrableType | ObjectFlagsContainsQuantifiedType ObjectFlagsInstantiatedMapped = ObjectFlagsMapped | ObjectFlagsInstantiated // Object flags that uniquely identify the kind of ObjectType ObjectFlagsObjectTypeKindMask = ObjectFlagsClassOrInterface | ObjectFlagsReference | ObjectFlagsTuple | ObjectFlagsAnonymous | ObjectFlagsMapped | ObjectFlagsReverseMapped | ObjectFlagsEvolvingArray | ObjectFlagsInstantiationExpressionType | ObjectFlagsSingleSignatureType diff --git a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.errors.txt new file mode 100644 index 00000000000..0e382cb27b7 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.errors.txt @@ -0,0 +1,27 @@ +quantifiedTypesCorrelatedUnions.ts(17,13): error TS2345: Argument of type 'T' is not assignable to parameter of type 'T'. + 'T' could be instantiated with an arbitrary type which could be unrelated to 'T'. + + +==== quantifiedTypesCorrelatedUnions.ts (1 errors) ==== + // https://github.com/microsoft/TypeScript/issues/30581 + + type NumberRecord = { kind: "n", v: number, f: (v: number) => void }; + type StringRecord = { kind: "s", v: string, f: (v: string) => void }; + type BooleanRecord = { kind: "b", v: boolean, f: (v: boolean) => void }; + type GenericRecord = { kind: string, v: T, f: (v: T) => void }; + + function processRecord(record: GenericRecord) { + record.f(record.v); + } + processRecord({} as NumberRecord) + processRecord({} as StringRecord) + processRecord({} as BooleanRecord) + processRecord({} as NumberRecord | StringRecord | BooleanRecord) + + function processRecord2(record1: GenericRecord, record2: GenericRecord) { + record1.f(record2.v); // TODO: better error + ~~~~~~~~~ +!!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'T'. +!!! error TS2345: 'T' could be instantiated with an arbitrary type which could be unrelated to 'T'. +!!! related TS2208 quantifiedTypesCorrelatedUnions.ts:6:23: This type parameter might need an `extends T` constraint. + } \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesIssue30581.js b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.js similarity index 77% rename from testdata/baselines/reference/compiler/quantifiedTypesIssue30581.js rename to testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.js index ac5056f2b6f..88f068a0d79 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesIssue30581.js +++ b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.js @@ -1,6 +1,6 @@ -//// [tests/cases/compiler/quantifiedTypesIssue30581.ts] //// +//// [tests/cases/compiler/quantifiedTypesCorrelatedUnions.ts] //// -//// [quantifiedTypesIssue30581.ts] +//// [quantifiedTypesCorrelatedUnions.ts] // https://github.com/microsoft/TypeScript/issues/30581 type NumberRecord = { kind: "n", v: number, f: (v: number) => void }; @@ -17,10 +17,10 @@ processRecord({} as BooleanRecord) processRecord({} as NumberRecord | StringRecord | BooleanRecord) function processRecord2(record1: GenericRecord, record2: GenericRecord) { - record1.f(record2.v); // TODO: should not compile + record1.f(record2.v); // TODO: better error } -//// [quantifiedTypesIssue30581.js] +//// [quantifiedTypesCorrelatedUnions.js] // https://github.com/microsoft/TypeScript/issues/30581 function processRecord(record) { record.f(record.v); @@ -30,5 +30,5 @@ processRecord({}); processRecord({}); processRecord({}); function processRecord2(record1, record2) { - record1.f(record2.v); // TODO: should not compile + record1.f(record2.v); // TODO: better error } diff --git a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.symbols b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.symbols new file mode 100644 index 00000000000..143069aeae5 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.symbols @@ -0,0 +1,82 @@ +//// [tests/cases/compiler/quantifiedTypesCorrelatedUnions.ts] //// + +=== quantifiedTypesCorrelatedUnions.ts === +// https://github.com/microsoft/TypeScript/issues/30581 + +type NumberRecord = { kind: "n", v: number, f: (v: number) => void }; +>NumberRecord : Symbol(NumberRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 0, 0)) +>kind : Symbol(kind, Decl(quantifiedTypesCorrelatedUnions.ts, 2, 21)) +>v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 2, 32)) +>f : Symbol(f, Decl(quantifiedTypesCorrelatedUnions.ts, 2, 43)) +>v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 2, 48)) + +type StringRecord = { kind: "s", v: string, f: (v: string) => void }; +>StringRecord : Symbol(StringRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 2, 69)) +>kind : Symbol(kind, Decl(quantifiedTypesCorrelatedUnions.ts, 3, 21)) +>v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 3, 32)) +>f : Symbol(f, Decl(quantifiedTypesCorrelatedUnions.ts, 3, 43)) +>v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 3, 48)) + +type BooleanRecord = { kind: "b", v: boolean, f: (v: boolean) => void }; +>BooleanRecord : Symbol(BooleanRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 3, 69)) +>kind : Symbol(kind, Decl(quantifiedTypesCorrelatedUnions.ts, 4, 22)) +>v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 4, 33)) +>f : Symbol(f, Decl(quantifiedTypesCorrelatedUnions.ts, 4, 45)) +>v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 4, 50)) + +type GenericRecord = { kind: string, v: T, f: (v: T) => void }; +>GenericRecord : Symbol(GenericRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 4, 72)) +>T : Symbol(T, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 22)) +>kind : Symbol(kind, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 26)) +>v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 40)) +>T : Symbol(T, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 22)) +>f : Symbol(f, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 46)) +>v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 51)) +>T : Symbol(T, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 22)) + +function processRecord(record: GenericRecord) { +>processRecord : Symbol(processRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 67)) +>record : Symbol(record, Decl(quantifiedTypesCorrelatedUnions.ts, 7, 23)) +>GenericRecord : Symbol(GenericRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 4, 72)) + + record.f(record.v); +>record.f : Symbol(f, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 46)) +>record : Symbol(record, Decl(quantifiedTypesCorrelatedUnions.ts, 7, 23)) +>f : Symbol(f, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 46)) +>record.v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 40)) +>record : Symbol(record, Decl(quantifiedTypesCorrelatedUnions.ts, 7, 23)) +>v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 40)) +} +processRecord({} as NumberRecord) +>processRecord : Symbol(processRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 67)) +>NumberRecord : Symbol(NumberRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 0, 0)) + +processRecord({} as StringRecord) +>processRecord : Symbol(processRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 67)) +>StringRecord : Symbol(StringRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 2, 69)) + +processRecord({} as BooleanRecord) +>processRecord : Symbol(processRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 67)) +>BooleanRecord : Symbol(BooleanRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 3, 69)) + +processRecord({} as NumberRecord | StringRecord | BooleanRecord) +>processRecord : Symbol(processRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 67)) +>NumberRecord : Symbol(NumberRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 0, 0)) +>StringRecord : Symbol(StringRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 2, 69)) +>BooleanRecord : Symbol(BooleanRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 3, 69)) + +function processRecord2(record1: GenericRecord, record2: GenericRecord) { +>processRecord2 : Symbol(processRecord2, Decl(quantifiedTypesCorrelatedUnions.ts, 13, 64)) +>record1 : Symbol(record1, Decl(quantifiedTypesCorrelatedUnions.ts, 15, 24)) +>GenericRecord : Symbol(GenericRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 4, 72)) +>record2 : Symbol(record2, Decl(quantifiedTypesCorrelatedUnions.ts, 15, 47)) +>GenericRecord : Symbol(GenericRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 4, 72)) + + record1.f(record2.v); // TODO: better error +>record1.f : Symbol(f, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 46)) +>record1 : Symbol(record1, Decl(quantifiedTypesCorrelatedUnions.ts, 15, 24)) +>f : Symbol(f, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 46)) +>record2.v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 40)) +>record2 : Symbol(record2, Decl(quantifiedTypesCorrelatedUnions.ts, 15, 47)) +>v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 40)) +} diff --git a/testdata/baselines/reference/compiler/quantifiedTypesIssue30581.types b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.types similarity index 88% rename from testdata/baselines/reference/compiler/quantifiedTypesIssue30581.types rename to testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.types index 9044a0366f7..0fb10cc7dc7 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesIssue30581.types +++ b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.types @@ -1,6 +1,6 @@ -//// [tests/cases/compiler/quantifiedTypesIssue30581.ts] //// +//// [tests/cases/compiler/quantifiedTypesCorrelatedUnions.ts] //// -=== quantifiedTypesIssue30581.ts === +=== quantifiedTypesCorrelatedUnions.ts === // https://github.com/microsoft/TypeScript/issues/30581 type NumberRecord = { kind: "n", v: number, f: (v: number) => void }; @@ -69,11 +69,11 @@ processRecord({} as NumberRecord | StringRecord | BooleanRecord) >{} : {} function processRecord2(record1: GenericRecord, record2: GenericRecord) { ->processRecord2 : (record1: { kind: string; v: T; f: (v: T) => void; }, record2: { kind: string; v: T; f: (v: T) => void; }) => void +>processRecord2 : (record1: { kind: string; v: T; f: (v: T) => void; }, record2: { kind: string; v: T_1; f: (v: T_1) => void; }) => void >record1 : { kind: string; v: T; f: (v: T) => void; } >record2 : { kind: string; v: T; f: (v: T) => void; } - record1.f(record2.v); // TODO: should not compile + record1.f(record2.v); // TODO: better error >record1.f(record2.v) : void >record1.f : (v: T) => void >record1 : { kind: string; v: T; f: (v: T) => void; } diff --git a/testdata/baselines/reference/compiler/quantifiedTypesIssue30581.symbols b/testdata/baselines/reference/compiler/quantifiedTypesIssue30581.symbols deleted file mode 100644 index 6db3a8051e3..00000000000 --- a/testdata/baselines/reference/compiler/quantifiedTypesIssue30581.symbols +++ /dev/null @@ -1,82 +0,0 @@ -//// [tests/cases/compiler/quantifiedTypesIssue30581.ts] //// - -=== quantifiedTypesIssue30581.ts === -// https://github.com/microsoft/TypeScript/issues/30581 - -type NumberRecord = { kind: "n", v: number, f: (v: number) => void }; ->NumberRecord : Symbol(NumberRecord, Decl(quantifiedTypesIssue30581.ts, 0, 0)) ->kind : Symbol(kind, Decl(quantifiedTypesIssue30581.ts, 2, 21)) ->v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 2, 32)) ->f : Symbol(f, Decl(quantifiedTypesIssue30581.ts, 2, 43)) ->v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 2, 48)) - -type StringRecord = { kind: "s", v: string, f: (v: string) => void }; ->StringRecord : Symbol(StringRecord, Decl(quantifiedTypesIssue30581.ts, 2, 69)) ->kind : Symbol(kind, Decl(quantifiedTypesIssue30581.ts, 3, 21)) ->v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 3, 32)) ->f : Symbol(f, Decl(quantifiedTypesIssue30581.ts, 3, 43)) ->v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 3, 48)) - -type BooleanRecord = { kind: "b", v: boolean, f: (v: boolean) => void }; ->BooleanRecord : Symbol(BooleanRecord, Decl(quantifiedTypesIssue30581.ts, 3, 69)) ->kind : Symbol(kind, Decl(quantifiedTypesIssue30581.ts, 4, 22)) ->v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 4, 33)) ->f : Symbol(f, Decl(quantifiedTypesIssue30581.ts, 4, 45)) ->v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 4, 50)) - -type GenericRecord = { kind: string, v: T, f: (v: T) => void }; ->GenericRecord : Symbol(GenericRecord, Decl(quantifiedTypesIssue30581.ts, 4, 72)) ->T : Symbol(T, Decl(quantifiedTypesIssue30581.ts, 5, 22)) ->kind : Symbol(kind, Decl(quantifiedTypesIssue30581.ts, 5, 26)) ->v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 5, 40)) ->T : Symbol(T, Decl(quantifiedTypesIssue30581.ts, 5, 22)) ->f : Symbol(f, Decl(quantifiedTypesIssue30581.ts, 5, 46)) ->v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 5, 51)) ->T : Symbol(T, Decl(quantifiedTypesIssue30581.ts, 5, 22)) - -function processRecord(record: GenericRecord) { ->processRecord : Symbol(processRecord, Decl(quantifiedTypesIssue30581.ts, 5, 67)) ->record : Symbol(record, Decl(quantifiedTypesIssue30581.ts, 7, 23)) ->GenericRecord : Symbol(GenericRecord, Decl(quantifiedTypesIssue30581.ts, 4, 72)) - - record.f(record.v); ->record.f : Symbol(f, Decl(quantifiedTypesIssue30581.ts, 5, 46)) ->record : Symbol(record, Decl(quantifiedTypesIssue30581.ts, 7, 23)) ->f : Symbol(f, Decl(quantifiedTypesIssue30581.ts, 5, 46)) ->record.v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 5, 40)) ->record : Symbol(record, Decl(quantifiedTypesIssue30581.ts, 7, 23)) ->v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 5, 40)) -} -processRecord({} as NumberRecord) ->processRecord : Symbol(processRecord, Decl(quantifiedTypesIssue30581.ts, 5, 67)) ->NumberRecord : Symbol(NumberRecord, Decl(quantifiedTypesIssue30581.ts, 0, 0)) - -processRecord({} as StringRecord) ->processRecord : Symbol(processRecord, Decl(quantifiedTypesIssue30581.ts, 5, 67)) ->StringRecord : Symbol(StringRecord, Decl(quantifiedTypesIssue30581.ts, 2, 69)) - -processRecord({} as BooleanRecord) ->processRecord : Symbol(processRecord, Decl(quantifiedTypesIssue30581.ts, 5, 67)) ->BooleanRecord : Symbol(BooleanRecord, Decl(quantifiedTypesIssue30581.ts, 3, 69)) - -processRecord({} as NumberRecord | StringRecord | BooleanRecord) ->processRecord : Symbol(processRecord, Decl(quantifiedTypesIssue30581.ts, 5, 67)) ->NumberRecord : Symbol(NumberRecord, Decl(quantifiedTypesIssue30581.ts, 0, 0)) ->StringRecord : Symbol(StringRecord, Decl(quantifiedTypesIssue30581.ts, 2, 69)) ->BooleanRecord : Symbol(BooleanRecord, Decl(quantifiedTypesIssue30581.ts, 3, 69)) - -function processRecord2(record1: GenericRecord, record2: GenericRecord) { ->processRecord2 : Symbol(processRecord2, Decl(quantifiedTypesIssue30581.ts, 13, 64)) ->record1 : Symbol(record1, Decl(quantifiedTypesIssue30581.ts, 15, 24)) ->GenericRecord : Symbol(GenericRecord, Decl(quantifiedTypesIssue30581.ts, 4, 72)) ->record2 : Symbol(record2, Decl(quantifiedTypesIssue30581.ts, 15, 47)) ->GenericRecord : Symbol(GenericRecord, Decl(quantifiedTypesIssue30581.ts, 4, 72)) - - record1.f(record2.v); // TODO: should not compile ->record1.f : Symbol(f, Decl(quantifiedTypesIssue30581.ts, 5, 46)) ->record1 : Symbol(record1, Decl(quantifiedTypesIssue30581.ts, 15, 24)) ->f : Symbol(f, Decl(quantifiedTypesIssue30581.ts, 5, 46)) ->record2.v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 5, 40)) ->record2 : Symbol(record2, Decl(quantifiedTypesIssue30581.ts, 15, 47)) ->v : Symbol(v, Decl(quantifiedTypesIssue30581.ts, 5, 40)) -} diff --git a/testdata/tests/cases/compiler/quantifiedTypesIssue30581.ts b/testdata/tests/cases/compiler/quantifiedTypesCorrelatedUnions.ts similarity index 92% rename from testdata/tests/cases/compiler/quantifiedTypesIssue30581.ts rename to testdata/tests/cases/compiler/quantifiedTypesCorrelatedUnions.ts index d8a34e4f3ff..c2bc4d73f90 100644 --- a/testdata/tests/cases/compiler/quantifiedTypesIssue30581.ts +++ b/testdata/tests/cases/compiler/quantifiedTypesCorrelatedUnions.ts @@ -14,5 +14,5 @@ processRecord({} as BooleanRecord) processRecord({} as NumberRecord | StringRecord | BooleanRecord) function processRecord2(record1: GenericRecord, record2: GenericRecord) { - record1.f(record2.v); // TODO: should not compile + record1.f(record2.v); // TODO: better error } \ No newline at end of file From fdba94bef177166bbf6ce0753f2047109cad1f49 Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Sat, 17 Jan 2026 22:19:57 +0530 Subject: [PATCH 15/23] add minimal simpler test for bounded type parameters --- ...ifiedTypesBoundedTypeParameters.errors.txt | 65 +++++++++++ .../quantifiedTypesBoundedTypeParameters.js | 109 ++++++++++++++++++ ...antifiedTypesBoundedTypeParameters.symbols | 85 ++++++++++++++ ...quantifiedTypesBoundedTypeParameters.types | 82 +++++++++++++ .../quantifiedTypesBoundedTypeParameters.ts | 57 +++++++++ 5 files changed, 398 insertions(+) create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.errors.txt create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.js create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.symbols create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.types create mode 100644 testdata/tests/cases/compiler/quantifiedTypesBoundedTypeParameters.ts diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.errors.txt new file mode 100644 index 00000000000..12f54691faa --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.errors.txt @@ -0,0 +1,65 @@ +quantifiedTypesBoundedTypeParameters.ts(6,6): error TS2345: Argument of type 'T' is not assignable to parameter of type 'T'. + 'T' could be instantiated with an arbitrary type which could be unrelated to 'T'. + + +==== quantifiedTypesBoundedTypeParameters.ts (1 errors) ==== + type F = { v: T, f: (v: T) => void }; + declare let f1: F + declare let f2: F + + f1.f(f1.v) + f1.f(f2.v) + ~~~~ +!!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'T'. +!!! error TS2345: 'T' could be instantiated with an arbitrary type which could be unrelated to 'T'. +!!! related TS2208 quantifiedTypesBoundedTypeParameters.ts:1:11: This type parameter might need an `extends T` constraint. + + + + /* + declare const f: (a: { + produce: (arg: string) => T, + consume: (arg: T) => unknown, + prop: { + produce: (arg: T) => U, + consume: (arg: U) => unknown, + } + }) => void + + f({ + produce: a => Number(a), + consume: x => { + x satisfies number + }, + prop: { + produce: x => { + x satisfies number + return Boolean(x) + }, + consume: y => { + y satisfies boolean + } + } + }) + */ + + /* + declare const smallest: + >(xs: T[]) => T + + smallest([1, 2, 3]) + smallest(["a", "b", "c"]) + + smallest([1, "b", 3]) + smallest([1, 2, undefined]) + + type OneOf = + ( + Actual extends Spec + ? IsUnit extends true ? Actual : never + : Spec + ) + + type IsUnit = + [U] extends (U extends unknown ? [U] : never) ? true : false + */ \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.js b/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.js new file mode 100644 index 00000000000..37505e7c8a9 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.js @@ -0,0 +1,109 @@ +//// [tests/cases/compiler/quantifiedTypesBoundedTypeParameters.ts] //// + +//// [quantifiedTypesBoundedTypeParameters.ts] +type F = { v: T, f: (v: T) => void }; +declare let f1: F +declare let f2: F + +f1.f(f1.v) +f1.f(f2.v) + + + +/* +declare const f: (a: { + produce: (arg: string) => T, + consume: (arg: T) => unknown, + prop: { + produce: (arg: T) => U, + consume: (arg: U) => unknown, + } +}) => void + +f({ + produce: a => Number(a), + consume: x => { + x satisfies number + }, + prop: { + produce: x => { + x satisfies number + return Boolean(x) + }, + consume: y => { + y satisfies boolean + } + } +}) +*/ + +/* +declare const smallest: + >(xs: T[]) => T + +smallest([1, 2, 3]) +smallest(["a", "b", "c"]) + +smallest([1, "b", 3]) +smallest([1, 2, undefined]) + +type OneOf = + ( + Actual extends Spec + ? IsUnit extends true ? Actual : never + : Spec + ) + +type IsUnit = + [U] extends (U extends unknown ? [U] : never) ? true : false +*/ + +//// [quantifiedTypesBoundedTypeParameters.js] +f1.f(f1.v); +f1.f(f2.v); +/* +declare const f: (a: { + produce: (arg: string) => T, + consume: (arg: T) => unknown, + prop: { + produce: (arg: T) => U, + consume: (arg: U) => unknown, + } +}) => void + +f({ + produce: a => Number(a), + consume: x => { + x satisfies number + }, + prop: { + produce: x => { + x satisfies number + return Boolean(x) + }, + consume: y => { + y satisfies boolean + } + } +}) +*/ +/* +declare const smallest: + >(xs: T[]) => T + +smallest([1, 2, 3]) +smallest(["a", "b", "c"]) + +smallest([1, "b", 3]) +smallest([1, 2, undefined]) + +type OneOf = + ( + Actual extends Spec + ? IsUnit extends true ? Actual : never + : Spec + ) + +type IsUnit = + [U] extends (U extends unknown ? [U] : never) ? true : false +*/ diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.symbols b/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.symbols new file mode 100644 index 00000000000..4deb8e78164 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.symbols @@ -0,0 +1,85 @@ +//// [tests/cases/compiler/quantifiedTypesBoundedTypeParameters.ts] //// + +=== quantifiedTypesBoundedTypeParameters.ts === +type F = { v: T, f: (v: T) => void }; +>F : Symbol(F, Decl(quantifiedTypesBoundedTypeParameters.ts, 0, 0)) +>T : Symbol(T, Decl(quantifiedTypesBoundedTypeParameters.ts, 0, 10)) +>v : Symbol(v, Decl(quantifiedTypesBoundedTypeParameters.ts, 0, 14)) +>T : Symbol(T, Decl(quantifiedTypesBoundedTypeParameters.ts, 0, 10)) +>f : Symbol(f, Decl(quantifiedTypesBoundedTypeParameters.ts, 0, 20)) +>v : Symbol(v, Decl(quantifiedTypesBoundedTypeParameters.ts, 0, 25)) +>T : Symbol(T, Decl(quantifiedTypesBoundedTypeParameters.ts, 0, 10)) + +declare let f1: F +>f1 : Symbol(f1, Decl(quantifiedTypesBoundedTypeParameters.ts, 1, 11)) +>F : Symbol(F, Decl(quantifiedTypesBoundedTypeParameters.ts, 0, 0)) + +declare let f2: F +>f2 : Symbol(f2, Decl(quantifiedTypesBoundedTypeParameters.ts, 2, 11)) +>F : Symbol(F, Decl(quantifiedTypesBoundedTypeParameters.ts, 0, 0)) + +f1.f(f1.v) +>f1.f : Symbol(f, Decl(quantifiedTypesBoundedTypeParameters.ts, 0, 20)) +>f1 : Symbol(f1, Decl(quantifiedTypesBoundedTypeParameters.ts, 1, 11)) +>f : Symbol(f, Decl(quantifiedTypesBoundedTypeParameters.ts, 0, 20)) +>f1.v : Symbol(v, Decl(quantifiedTypesBoundedTypeParameters.ts, 0, 14)) +>f1 : Symbol(f1, Decl(quantifiedTypesBoundedTypeParameters.ts, 1, 11)) +>v : Symbol(v, Decl(quantifiedTypesBoundedTypeParameters.ts, 0, 14)) + +f1.f(f2.v) +>f1.f : Symbol(f, Decl(quantifiedTypesBoundedTypeParameters.ts, 0, 20)) +>f1 : Symbol(f1, Decl(quantifiedTypesBoundedTypeParameters.ts, 1, 11)) +>f : Symbol(f, Decl(quantifiedTypesBoundedTypeParameters.ts, 0, 20)) +>f2.v : Symbol(v, Decl(quantifiedTypesBoundedTypeParameters.ts, 0, 14)) +>f2 : Symbol(f2, Decl(quantifiedTypesBoundedTypeParameters.ts, 2, 11)) +>v : Symbol(v, Decl(quantifiedTypesBoundedTypeParameters.ts, 0, 14)) + + + +/* +declare const f: (a: { + produce: (arg: string) => T, + consume: (arg: T) => unknown, + prop: { + produce: (arg: T) => U, + consume: (arg: U) => unknown, + } +}) => void + +f({ + produce: a => Number(a), + consume: x => { + x satisfies number + }, + prop: { + produce: x => { + x satisfies number + return Boolean(x) + }, + consume: y => { + y satisfies boolean + } + } +}) +*/ + +/* +declare const smallest: + >(xs: T[]) => T + +smallest([1, 2, 3]) +smallest(["a", "b", "c"]) + +smallest([1, "b", 3]) +smallest([1, 2, undefined]) + +type OneOf = + ( + Actual extends Spec + ? IsUnit extends true ? Actual : never + : Spec + ) + +type IsUnit = + [U] extends (U extends unknown ? [U] : never) ? true : false +*/ diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.types b/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.types new file mode 100644 index 00000000000..e5a64931aa1 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.types @@ -0,0 +1,82 @@ +//// [tests/cases/compiler/quantifiedTypesBoundedTypeParameters.ts] //// + +=== quantifiedTypesBoundedTypeParameters.ts === +type F = { v: T, f: (v: T) => void }; +>F : { v: T; f: (v: T) => void; } +>v : T +>f : (v: T) => void +>v : T + +declare let f1: F +>f1 : { v: T; f: (v: T) => void; } + +declare let f2: F +>f2 : { v: T; f: (v: T) => void; } + +f1.f(f1.v) +>f1.f(f1.v) : void +>f1.f : (v: T) => void +>f1 : { v: T; f: (v: T) => void; } +>f : (v: T) => void +>f1.v : T +>f1 : { v: T; f: (v: T) => void; } +>v : T + +f1.f(f2.v) +>f1.f(f2.v) : void +>f1.f : (v: T) => void +>f1 : { v: T; f: (v: T) => void; } +>f : (v: T) => void +>f2.v : T +>f2 : { v: T; f: (v: T) => void; } +>v : T + + + +/* +declare const f: (a: { + produce: (arg: string) => T, + consume: (arg: T) => unknown, + prop: { + produce: (arg: T) => U, + consume: (arg: U) => unknown, + } +}) => void + +f({ + produce: a => Number(a), + consume: x => { + x satisfies number + }, + prop: { + produce: x => { + x satisfies number + return Boolean(x) + }, + consume: y => { + y satisfies boolean + } + } +}) +*/ + +/* +declare const smallest: + >(xs: T[]) => T + +smallest([1, 2, 3]) +smallest(["a", "b", "c"]) + +smallest([1, "b", 3]) +smallest([1, 2, undefined]) + +type OneOf = + ( + Actual extends Spec + ? IsUnit extends true ? Actual : never + : Spec + ) + +type IsUnit = + [U] extends (U extends unknown ? [U] : never) ? true : false +*/ diff --git a/testdata/tests/cases/compiler/quantifiedTypesBoundedTypeParameters.ts b/testdata/tests/cases/compiler/quantifiedTypesBoundedTypeParameters.ts new file mode 100644 index 00000000000..143811432c0 --- /dev/null +++ b/testdata/tests/cases/compiler/quantifiedTypesBoundedTypeParameters.ts @@ -0,0 +1,57 @@ +type F = { v: T, f: (v: T) => void }; +declare let f1: F +declare let f2: F + +f1.f(f1.v) + +f1.f(f2.v) // TOOD: better errors + + + +/* +declare const f: (a: { + produce: (arg: string) => T, + consume: (arg: T) => unknown, + prop: { + produce: (arg: T) => U, + consume: (arg: U) => unknown, + } +}) => void + +f({ + produce: a => Number(a), + consume: x => { + x satisfies number + }, + prop: { + produce: x => { + x satisfies number + return Boolean(x) + }, + consume: y => { + y satisfies boolean + } + } +}) +*/ + +/* +declare const smallest: + >(xs: T[]) => T + +smallest([1, 2, 3]) +smallest(["a", "b", "c"]) + +smallest([1, "b", 3]) +smallest([1, 2, undefined]) + +type OneOf = + ( + Actual extends Spec + ? IsUnit extends true ? Actual : never + : Spec + ) + +type IsUnit = + [U] extends (U extends unknown ? [U] : never) ? true : false +*/ \ No newline at end of file From daaefa03652b6b187dcdce59a3c504091b88bef2 Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Sat, 17 Jan 2026 23:17:31 +0530 Subject: [PATCH 16/23] way better error messages for bounded type parameters --- internal/checker/checker.go | 1 + internal/checker/relater.go | 20 +++++++++++++------ internal/checker/types.go | 1 + internal/diagnostics/diagnostics_generated.go | 8 ++++++++ .../diagnostics/extraDiagnosticMessages.json | 8 ++++++++ ...ifiedTypesBoundedTypeParameters.errors.txt | 12 +++++++---- .../quantifiedTypesBoundedTypeParameters.js | 1 + ...quantifiedTypesCorrelatedUnions.errors.txt | 9 ++++++--- .../quantifiedTypesBoundedTypeParameters.ts | 2 +- 9 files changed, 48 insertions(+), 14 deletions(-) diff --git a/internal/checker/checker.go b/internal/checker/checker.go index d3862dddee9..33b7e08283f 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -16129,6 +16129,7 @@ func (c *Checker) getTypeOfVariableOrParameterOrProperty(symbol *ast.Symbol) *Ty } newT = c.cloneTypeParameter(t) newT.objectFlags |= ObjectFlagsQuantifiedTypeParameter + newT.AsTypeParameter().boundedTo = symbol mapper[t] = newT return newT } diff --git a/internal/checker/relater.go b/internal/checker/relater.go index d75c13cdf26..9d3ee63a8e3 100644 --- a/internal/checker/relater.go +++ b/internal/checker/relater.go @@ -4723,12 +4723,17 @@ func (r *Relater) reportErrorResults(originalSource *Type, originalTarget *Type, } } r.reportRelationError(headMessage, source, target) - if source.flags&TypeFlagsTypeParameter != 0 && source.symbol != nil && len(source.symbol.Declarations) != 0 && r.c.getConstraintOfType(source) == nil { - syntheticParam := r.c.cloneTypeParameter(source) - syntheticParam.AsTypeParameter().constraint = r.c.instantiateType(target, newSimpleTypeMapper(source, syntheticParam)) - if r.c.hasNonCircularBaseConstraint(syntheticParam) { - targetConstraintString := r.c.TypeToString(target) - r.relatedInfo = append(r.relatedInfo, NewDiagnosticForNode(source.symbol.Declarations[0], diagnostics.This_type_parameter_might_need_an_extends_0_constraint, targetConstraintString)) + if source.objectFlags&ObjectFlagsQuantifiedTypeParameter != 0 && target.objectFlags&ObjectFlagsQuantifiedTypeParameter != 0 { + r.relatedInfo = append(r.relatedInfo, NewDiagnosticForNode(source.AsTypeParameter().boundedTo.Declarations[0], diagnostics.Type_parameter_0_is_bounded_to_this_variable, r.c.TypeToString(source))) + r.relatedInfo = append(r.relatedInfo, NewDiagnosticForNode(target.AsTypeParameter().boundedTo.Declarations[0], diagnostics.Type_parameter_0_is_bounded_to_this_variable, r.c.TypeToString(target))) + } else { + if source.flags&TypeFlagsTypeParameter != 0 && source.symbol != nil && len(source.symbol.Declarations) != 0 && r.c.getConstraintOfType(source) == nil { + syntheticParam := r.c.cloneTypeParameter(source) + syntheticParam.AsTypeParameter().constraint = r.c.instantiateType(target, newSimpleTypeMapper(source, syntheticParam)) + if r.c.hasNonCircularBaseConstraint(syntheticParam) { + targetConstraintString := r.c.TypeToString(target) + r.relatedInfo = append(r.relatedInfo, NewDiagnosticForNode(source.symbol.Declarations[0], diagnostics.This_type_parameter_might_need_an_extends_0_constraint, targetConstraintString)) + } } } } @@ -4763,6 +4768,9 @@ func (r *Relater) reportRelationError(message *diagnostics.Message, source *Type r.reportError(diagnostics.X_0_could_be_instantiated_with_an_arbitrary_type_which_could_be_unrelated_to_1, targetType, generalizedSourceType) } } + if target.objectFlags&ObjectFlagsQuantifiedTypeParameter != 0 && generalizedSource.objectFlags&ObjectFlagsQuantifiedTypeParameter != 0 { + r.reportError(diagnostics.Both_type_parameters_are_bound_to_different_variables) + } if message == nil { switch { case r.relation == r.c.comparableRelation: diff --git a/internal/checker/types.go b/internal/checker/types.go index c4ae7e98d92..2d49850e5de 100644 --- a/internal/checker/types.go +++ b/internal/checker/types.go @@ -1032,6 +1032,7 @@ type TypeParameter struct { mapper *TypeMapper isThisType bool resolvedDefaultType *Type + boundedTo *ast.Symbol } // IndexFlags diff --git a/internal/diagnostics/diagnostics_generated.go b/internal/diagnostics/diagnostics_generated.go index 14c2a9b0f48..0a300282e20 100644 --- a/internal/diagnostics/diagnostics_generated.go +++ b/internal/diagnostics/diagnostics_generated.go @@ -2362,6 +2362,10 @@ var Visit_https_Colon_Slash_Slashaka_ms_Slashts6_for_migration_information = &Me var X_tsconfig_json_is_present_but_will_not_be_loaded_if_files_are_specified_on_commandline_Use_ignoreConfig_to_skip_this_error = &Message{code: 5112, category: CategoryError, key: "tsconfig_json_is_present_but_will_not_be_loaded_if_files_are_specified_on_commandline_Use_ignoreConf_5112", text: "tsconfig.json is present but will not be loaded if files are specified on commandline. Use '--ignoreConfig' to skip this error."} +var Both_type_parameters_are_bound_to_different_variables = &Message{code: 5113, category: CategoryError, key: "Both_type_parameters_are_bound_to_different_variables_5113", text: "Both type parameters are bound to different variables"} + +var Type_parameter_0_is_bounded_to_this_variable = &Message{code: 5114, category: CategoryError, key: "Type_parameter_0_is_bounded_to_this_variable_5114", text: "Type parameter '{0}' is bounded to this variable"} + var Generates_a_sourcemap_for_each_corresponding_d_ts_file = &Message{code: 6000, category: CategoryMessage, key: "Generates_a_sourcemap_for_each_corresponding_d_ts_file_6000", text: "Generates a sourcemap for each corresponding '.d.ts' file."} var Concatenate_and_emit_output_to_single_file = &Message{code: 6001, category: CategoryMessage, key: "Concatenate_and_emit_output_to_single_file_6001", text: "Concatenate and emit output to single file."} @@ -6638,6 +6642,10 @@ func keyToMessage(key Key) *Message { return Visit_https_Colon_Slash_Slashaka_ms_Slashts6_for_migration_information case "tsconfig_json_is_present_but_will_not_be_loaded_if_files_are_specified_on_commandline_Use_ignoreConf_5112": return X_tsconfig_json_is_present_but_will_not_be_loaded_if_files_are_specified_on_commandline_Use_ignoreConfig_to_skip_this_error + case "Both_type_parameters_are_bound_to_different_variables_5113": + return Both_type_parameters_are_bound_to_different_variables + case "Type_parameter_0_is_bounded_to_this_variable_5114": + return Type_parameter_0_is_bounded_to_this_variable case "Generates_a_sourcemap_for_each_corresponding_d_ts_file_6000": return Generates_a_sourcemap_for_each_corresponding_d_ts_file case "Concatenate_and_emit_output_to_single_file_6001": diff --git a/internal/diagnostics/extraDiagnosticMessages.json b/internal/diagnostics/extraDiagnosticMessages.json index 2566d6ff532..e6e659dbfc4 100644 --- a/internal/diagnostics/extraDiagnosticMessages.json +++ b/internal/diagnostics/extraDiagnosticMessages.json @@ -86,5 +86,13 @@ "Option '{0}' requires value to be greater than '{1}'.": { "category": "Error", "code": 5002 + }, + "Both type parameters are bound to different variables": { + "category": "Error", + "code": 5113 + }, + "Type parameter '{0}' is bounded to this variable": { + "category": "Error", + "code": 5114 } } diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.errors.txt index 12f54691faa..3b3153875ed 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.errors.txt +++ b/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.errors.txt @@ -1,5 +1,6 @@ -quantifiedTypesBoundedTypeParameters.ts(6,6): error TS2345: Argument of type 'T' is not assignable to parameter of type 'T'. - 'T' could be instantiated with an arbitrary type which could be unrelated to 'T'. +quantifiedTypesBoundedTypeParameters.ts(7,6): error TS2345: Argument of type 'T' is not assignable to parameter of type 'T'. + Both type parameters are bound to different variables + 'T' could be instantiated with an arbitrary type which could be unrelated to 'T'. ==== quantifiedTypesBoundedTypeParameters.ts (1 errors) ==== @@ -8,11 +9,14 @@ quantifiedTypesBoundedTypeParameters.ts(6,6): error TS2345: Argument of type 'T' declare let f2: F f1.f(f1.v) + f1.f(f2.v) ~~~~ !!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'T'. -!!! error TS2345: 'T' could be instantiated with an arbitrary type which could be unrelated to 'T'. -!!! related TS2208 quantifiedTypesBoundedTypeParameters.ts:1:11: This type parameter might need an `extends T` constraint. +!!! error TS2345: Both type parameters are bound to different variables +!!! error TS2345: 'T' could be instantiated with an arbitrary type which could be unrelated to 'T'. +!!! related TS5114 quantifiedTypesBoundedTypeParameters.ts:3:13: Type parameter 'T' is bounded to this variable +!!! related TS5114 quantifiedTypesBoundedTypeParameters.ts:2:13: Type parameter 'T' is bounded to this variable diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.js b/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.js index 37505e7c8a9..8ee4c417bd1 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.js +++ b/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.js @@ -6,6 +6,7 @@ declare let f1: F declare let f2: F f1.f(f1.v) + f1.f(f2.v) diff --git a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.errors.txt index 0e382cb27b7..23d98f89b37 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.errors.txt +++ b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.errors.txt @@ -1,5 +1,6 @@ quantifiedTypesCorrelatedUnions.ts(17,13): error TS2345: Argument of type 'T' is not assignable to parameter of type 'T'. - 'T' could be instantiated with an arbitrary type which could be unrelated to 'T'. + Both type parameters are bound to different variables + 'T' could be instantiated with an arbitrary type which could be unrelated to 'T'. ==== quantifiedTypesCorrelatedUnions.ts (1 errors) ==== @@ -22,6 +23,8 @@ quantifiedTypesCorrelatedUnions.ts(17,13): error TS2345: Argument of type 'T' is record1.f(record2.v); // TODO: better error ~~~~~~~~~ !!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'T'. -!!! error TS2345: 'T' could be instantiated with an arbitrary type which could be unrelated to 'T'. -!!! related TS2208 quantifiedTypesCorrelatedUnions.ts:6:23: This type parameter might need an `extends T` constraint. +!!! error TS2345: Both type parameters are bound to different variables +!!! error TS2345: 'T' could be instantiated with an arbitrary type which could be unrelated to 'T'. +!!! related TS5114 quantifiedTypesCorrelatedUnions.ts:16:49: Type parameter 'T' is bounded to this variable +!!! related TS5114 quantifiedTypesCorrelatedUnions.ts:16:25: Type parameter 'T' is bounded to this variable } \ No newline at end of file diff --git a/testdata/tests/cases/compiler/quantifiedTypesBoundedTypeParameters.ts b/testdata/tests/cases/compiler/quantifiedTypesBoundedTypeParameters.ts index 143811432c0..4793384aa34 100644 --- a/testdata/tests/cases/compiler/quantifiedTypesBoundedTypeParameters.ts +++ b/testdata/tests/cases/compiler/quantifiedTypesBoundedTypeParameters.ts @@ -4,7 +4,7 @@ declare let f2: F f1.f(f1.v) -f1.f(f2.v) // TOOD: better errors +f1.f(f2.v) From 27efc22eff03e9defc37f018864621ea3d77482b Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Sat, 17 Jan 2026 23:25:23 +0530 Subject: [PATCH 17/23] fix grammar --- internal/checker/relater.go | 2 +- internal/diagnostics/diagnostics_generated.go | 6 +++--- internal/diagnostics/extraDiagnosticMessages.json | 2 +- .../quantifiedTypesBoundedTypeParameters.errors.txt | 4 ++-- .../compiler/quantifiedTypesCorrelatedUnions.errors.txt | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/internal/checker/relater.go b/internal/checker/relater.go index 9d3ee63a8e3..0a90939ba29 100644 --- a/internal/checker/relater.go +++ b/internal/checker/relater.go @@ -4769,7 +4769,7 @@ func (r *Relater) reportRelationError(message *diagnostics.Message, source *Type } } if target.objectFlags&ObjectFlagsQuantifiedTypeParameter != 0 && generalizedSource.objectFlags&ObjectFlagsQuantifiedTypeParameter != 0 { - r.reportError(diagnostics.Both_type_parameters_are_bound_to_different_variables) + r.reportError(diagnostics.Both_type_parameters_are_bounded_to_different_variables) } if message == nil { switch { diff --git a/internal/diagnostics/diagnostics_generated.go b/internal/diagnostics/diagnostics_generated.go index 0a300282e20..c39986e2e6b 100644 --- a/internal/diagnostics/diagnostics_generated.go +++ b/internal/diagnostics/diagnostics_generated.go @@ -2362,7 +2362,7 @@ var Visit_https_Colon_Slash_Slashaka_ms_Slashts6_for_migration_information = &Me var X_tsconfig_json_is_present_but_will_not_be_loaded_if_files_are_specified_on_commandline_Use_ignoreConfig_to_skip_this_error = &Message{code: 5112, category: CategoryError, key: "tsconfig_json_is_present_but_will_not_be_loaded_if_files_are_specified_on_commandline_Use_ignoreConf_5112", text: "tsconfig.json is present but will not be loaded if files are specified on commandline. Use '--ignoreConfig' to skip this error."} -var Both_type_parameters_are_bound_to_different_variables = &Message{code: 5113, category: CategoryError, key: "Both_type_parameters_are_bound_to_different_variables_5113", text: "Both type parameters are bound to different variables"} +var Both_type_parameters_are_bounded_to_different_variables = &Message{code: 5113, category: CategoryError, key: "Both_type_parameters_are_bounded_to_different_variables_5113", text: "Both type parameters are bounded to different variables"} var Type_parameter_0_is_bounded_to_this_variable = &Message{code: 5114, category: CategoryError, key: "Type_parameter_0_is_bounded_to_this_variable_5114", text: "Type parameter '{0}' is bounded to this variable"} @@ -6642,8 +6642,8 @@ func keyToMessage(key Key) *Message { return Visit_https_Colon_Slash_Slashaka_ms_Slashts6_for_migration_information case "tsconfig_json_is_present_but_will_not_be_loaded_if_files_are_specified_on_commandline_Use_ignoreConf_5112": return X_tsconfig_json_is_present_but_will_not_be_loaded_if_files_are_specified_on_commandline_Use_ignoreConfig_to_skip_this_error - case "Both_type_parameters_are_bound_to_different_variables_5113": - return Both_type_parameters_are_bound_to_different_variables + case "Both_type_parameters_are_bounded_to_different_variables_5113": + return Both_type_parameters_are_bounded_to_different_variables case "Type_parameter_0_is_bounded_to_this_variable_5114": return Type_parameter_0_is_bounded_to_this_variable case "Generates_a_sourcemap_for_each_corresponding_d_ts_file_6000": diff --git a/internal/diagnostics/extraDiagnosticMessages.json b/internal/diagnostics/extraDiagnosticMessages.json index e6e659dbfc4..f19c5b6ba12 100644 --- a/internal/diagnostics/extraDiagnosticMessages.json +++ b/internal/diagnostics/extraDiagnosticMessages.json @@ -87,7 +87,7 @@ "category": "Error", "code": 5002 }, - "Both type parameters are bound to different variables": { + "Both type parameters are bounded to different variables": { "category": "Error", "code": 5113 }, diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.errors.txt index 3b3153875ed..473f01d05e3 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.errors.txt +++ b/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.errors.txt @@ -1,5 +1,5 @@ quantifiedTypesBoundedTypeParameters.ts(7,6): error TS2345: Argument of type 'T' is not assignable to parameter of type 'T'. - Both type parameters are bound to different variables + Both type parameters are bounded to different variables 'T' could be instantiated with an arbitrary type which could be unrelated to 'T'. @@ -13,7 +13,7 @@ quantifiedTypesBoundedTypeParameters.ts(7,6): error TS2345: Argument of type 'T' f1.f(f2.v) ~~~~ !!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'T'. -!!! error TS2345: Both type parameters are bound to different variables +!!! error TS2345: Both type parameters are bounded to different variables !!! error TS2345: 'T' could be instantiated with an arbitrary type which could be unrelated to 'T'. !!! related TS5114 quantifiedTypesBoundedTypeParameters.ts:3:13: Type parameter 'T' is bounded to this variable !!! related TS5114 quantifiedTypesBoundedTypeParameters.ts:2:13: Type parameter 'T' is bounded to this variable diff --git a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.errors.txt index 23d98f89b37..4f10d005bb4 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.errors.txt +++ b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.errors.txt @@ -1,5 +1,5 @@ quantifiedTypesCorrelatedUnions.ts(17,13): error TS2345: Argument of type 'T' is not assignable to parameter of type 'T'. - Both type parameters are bound to different variables + Both type parameters are bounded to different variables 'T' could be instantiated with an arbitrary type which could be unrelated to 'T'. @@ -23,7 +23,7 @@ quantifiedTypesCorrelatedUnions.ts(17,13): error TS2345: Argument of type 'T' is record1.f(record2.v); // TODO: better error ~~~~~~~~~ !!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'T'. -!!! error TS2345: Both type parameters are bound to different variables +!!! error TS2345: Both type parameters are bounded to different variables !!! error TS2345: 'T' could be instantiated with an arbitrary type which could be unrelated to 'T'. !!! related TS5114 quantifiedTypesCorrelatedUnions.ts:16:49: Type parameter 'T' is bounded to this variable !!! related TS5114 quantifiedTypesCorrelatedUnions.ts:16:25: Type parameter 'T' is bounded to this variable From c803b198bc08edf85c82ba5624bf02c5b961d1b9 Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Sun, 18 Jan 2026 19:32:55 +0530 Subject: [PATCH 18/23] delete correlated union tests case because it doesn't really solve the majority of usecases --- ...quantifiedTypesCorrelatedUnions.errors.txt | 30 ------- .../quantifiedTypesCorrelatedUnions.js | 34 -------- .../quantifiedTypesCorrelatedUnions.symbols | 82 ------------------ .../quantifiedTypesCorrelatedUnions.types | 84 ------------------- .../quantifiedTypesCorrelatedUnions.ts | 18 ---- 5 files changed, 248 deletions(-) delete mode 100644 testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.errors.txt delete mode 100644 testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.js delete mode 100644 testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.symbols delete mode 100644 testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.types delete mode 100644 testdata/tests/cases/compiler/quantifiedTypesCorrelatedUnions.ts diff --git a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.errors.txt deleted file mode 100644 index 4f10d005bb4..00000000000 --- a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.errors.txt +++ /dev/null @@ -1,30 +0,0 @@ -quantifiedTypesCorrelatedUnions.ts(17,13): error TS2345: Argument of type 'T' is not assignable to parameter of type 'T'. - Both type parameters are bounded to different variables - 'T' could be instantiated with an arbitrary type which could be unrelated to 'T'. - - -==== quantifiedTypesCorrelatedUnions.ts (1 errors) ==== - // https://github.com/microsoft/TypeScript/issues/30581 - - type NumberRecord = { kind: "n", v: number, f: (v: number) => void }; - type StringRecord = { kind: "s", v: string, f: (v: string) => void }; - type BooleanRecord = { kind: "b", v: boolean, f: (v: boolean) => void }; - type GenericRecord = { kind: string, v: T, f: (v: T) => void }; - - function processRecord(record: GenericRecord) { - record.f(record.v); - } - processRecord({} as NumberRecord) - processRecord({} as StringRecord) - processRecord({} as BooleanRecord) - processRecord({} as NumberRecord | StringRecord | BooleanRecord) - - function processRecord2(record1: GenericRecord, record2: GenericRecord) { - record1.f(record2.v); // TODO: better error - ~~~~~~~~~ -!!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'T'. -!!! error TS2345: Both type parameters are bounded to different variables -!!! error TS2345: 'T' could be instantiated with an arbitrary type which could be unrelated to 'T'. -!!! related TS5114 quantifiedTypesCorrelatedUnions.ts:16:49: Type parameter 'T' is bounded to this variable -!!! related TS5114 quantifiedTypesCorrelatedUnions.ts:16:25: Type parameter 'T' is bounded to this variable - } \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.js b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.js deleted file mode 100644 index 88f068a0d79..00000000000 --- a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.js +++ /dev/null @@ -1,34 +0,0 @@ -//// [tests/cases/compiler/quantifiedTypesCorrelatedUnions.ts] //// - -//// [quantifiedTypesCorrelatedUnions.ts] -// https://github.com/microsoft/TypeScript/issues/30581 - -type NumberRecord = { kind: "n", v: number, f: (v: number) => void }; -type StringRecord = { kind: "s", v: string, f: (v: string) => void }; -type BooleanRecord = { kind: "b", v: boolean, f: (v: boolean) => void }; -type GenericRecord = { kind: string, v: T, f: (v: T) => void }; - -function processRecord(record: GenericRecord) { - record.f(record.v); -} -processRecord({} as NumberRecord) -processRecord({} as StringRecord) -processRecord({} as BooleanRecord) -processRecord({} as NumberRecord | StringRecord | BooleanRecord) - -function processRecord2(record1: GenericRecord, record2: GenericRecord) { - record1.f(record2.v); // TODO: better error -} - -//// [quantifiedTypesCorrelatedUnions.js] -// https://github.com/microsoft/TypeScript/issues/30581 -function processRecord(record) { - record.f(record.v); -} -processRecord({}); -processRecord({}); -processRecord({}); -processRecord({}); -function processRecord2(record1, record2) { - record1.f(record2.v); // TODO: better error -} diff --git a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.symbols b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.symbols deleted file mode 100644 index 143069aeae5..00000000000 --- a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.symbols +++ /dev/null @@ -1,82 +0,0 @@ -//// [tests/cases/compiler/quantifiedTypesCorrelatedUnions.ts] //// - -=== quantifiedTypesCorrelatedUnions.ts === -// https://github.com/microsoft/TypeScript/issues/30581 - -type NumberRecord = { kind: "n", v: number, f: (v: number) => void }; ->NumberRecord : Symbol(NumberRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 0, 0)) ->kind : Symbol(kind, Decl(quantifiedTypesCorrelatedUnions.ts, 2, 21)) ->v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 2, 32)) ->f : Symbol(f, Decl(quantifiedTypesCorrelatedUnions.ts, 2, 43)) ->v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 2, 48)) - -type StringRecord = { kind: "s", v: string, f: (v: string) => void }; ->StringRecord : Symbol(StringRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 2, 69)) ->kind : Symbol(kind, Decl(quantifiedTypesCorrelatedUnions.ts, 3, 21)) ->v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 3, 32)) ->f : Symbol(f, Decl(quantifiedTypesCorrelatedUnions.ts, 3, 43)) ->v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 3, 48)) - -type BooleanRecord = { kind: "b", v: boolean, f: (v: boolean) => void }; ->BooleanRecord : Symbol(BooleanRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 3, 69)) ->kind : Symbol(kind, Decl(quantifiedTypesCorrelatedUnions.ts, 4, 22)) ->v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 4, 33)) ->f : Symbol(f, Decl(quantifiedTypesCorrelatedUnions.ts, 4, 45)) ->v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 4, 50)) - -type GenericRecord = { kind: string, v: T, f: (v: T) => void }; ->GenericRecord : Symbol(GenericRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 4, 72)) ->T : Symbol(T, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 22)) ->kind : Symbol(kind, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 26)) ->v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 40)) ->T : Symbol(T, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 22)) ->f : Symbol(f, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 46)) ->v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 51)) ->T : Symbol(T, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 22)) - -function processRecord(record: GenericRecord) { ->processRecord : Symbol(processRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 67)) ->record : Symbol(record, Decl(quantifiedTypesCorrelatedUnions.ts, 7, 23)) ->GenericRecord : Symbol(GenericRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 4, 72)) - - record.f(record.v); ->record.f : Symbol(f, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 46)) ->record : Symbol(record, Decl(quantifiedTypesCorrelatedUnions.ts, 7, 23)) ->f : Symbol(f, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 46)) ->record.v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 40)) ->record : Symbol(record, Decl(quantifiedTypesCorrelatedUnions.ts, 7, 23)) ->v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 40)) -} -processRecord({} as NumberRecord) ->processRecord : Symbol(processRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 67)) ->NumberRecord : Symbol(NumberRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 0, 0)) - -processRecord({} as StringRecord) ->processRecord : Symbol(processRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 67)) ->StringRecord : Symbol(StringRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 2, 69)) - -processRecord({} as BooleanRecord) ->processRecord : Symbol(processRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 67)) ->BooleanRecord : Symbol(BooleanRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 3, 69)) - -processRecord({} as NumberRecord | StringRecord | BooleanRecord) ->processRecord : Symbol(processRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 67)) ->NumberRecord : Symbol(NumberRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 0, 0)) ->StringRecord : Symbol(StringRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 2, 69)) ->BooleanRecord : Symbol(BooleanRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 3, 69)) - -function processRecord2(record1: GenericRecord, record2: GenericRecord) { ->processRecord2 : Symbol(processRecord2, Decl(quantifiedTypesCorrelatedUnions.ts, 13, 64)) ->record1 : Symbol(record1, Decl(quantifiedTypesCorrelatedUnions.ts, 15, 24)) ->GenericRecord : Symbol(GenericRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 4, 72)) ->record2 : Symbol(record2, Decl(quantifiedTypesCorrelatedUnions.ts, 15, 47)) ->GenericRecord : Symbol(GenericRecord, Decl(quantifiedTypesCorrelatedUnions.ts, 4, 72)) - - record1.f(record2.v); // TODO: better error ->record1.f : Symbol(f, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 46)) ->record1 : Symbol(record1, Decl(quantifiedTypesCorrelatedUnions.ts, 15, 24)) ->f : Symbol(f, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 46)) ->record2.v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 40)) ->record2 : Symbol(record2, Decl(quantifiedTypesCorrelatedUnions.ts, 15, 47)) ->v : Symbol(v, Decl(quantifiedTypesCorrelatedUnions.ts, 5, 40)) -} diff --git a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.types b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.types deleted file mode 100644 index 0fb10cc7dc7..00000000000 --- a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions.types +++ /dev/null @@ -1,84 +0,0 @@ -//// [tests/cases/compiler/quantifiedTypesCorrelatedUnions.ts] //// - -=== quantifiedTypesCorrelatedUnions.ts === -// https://github.com/microsoft/TypeScript/issues/30581 - -type NumberRecord = { kind: "n", v: number, f: (v: number) => void }; ->NumberRecord : NumberRecord ->kind : "n" ->v : number ->f : (v: number) => void ->v : number - -type StringRecord = { kind: "s", v: string, f: (v: string) => void }; ->StringRecord : StringRecord ->kind : "s" ->v : string ->f : (v: string) => void ->v : string - -type BooleanRecord = { kind: "b", v: boolean, f: (v: boolean) => void }; ->BooleanRecord : BooleanRecord ->kind : "b" ->v : boolean ->f : (v: boolean) => void ->v : boolean - -type GenericRecord = { kind: string, v: T, f: (v: T) => void }; ->GenericRecord : { kind: string; v: T; f: (v: T) => void; } ->kind : string ->v : T ->f : (v: T) => void ->v : T - -function processRecord(record: GenericRecord) { ->processRecord : (record: { kind: string; v: T; f: (v: T) => void; }) => void ->record : { kind: string; v: T; f: (v: T) => void; } - - record.f(record.v); ->record.f(record.v) : void ->record.f : (v: T) => void ->record : { kind: string; v: T; f: (v: T) => void; } ->f : (v: T) => void ->record.v : T ->record : { kind: string; v: T; f: (v: T) => void; } ->v : T -} -processRecord({} as NumberRecord) ->processRecord({} as NumberRecord) : void ->processRecord : (record: { kind: string; v: T; f: (v: T) => void; }) => void ->{} as NumberRecord : NumberRecord ->{} : {} - -processRecord({} as StringRecord) ->processRecord({} as StringRecord) : void ->processRecord : (record: { kind: string; v: T; f: (v: T) => void; }) => void ->{} as StringRecord : StringRecord ->{} : {} - -processRecord({} as BooleanRecord) ->processRecord({} as BooleanRecord) : void ->processRecord : (record: { kind: string; v: T; f: (v: T) => void; }) => void ->{} as BooleanRecord : BooleanRecord ->{} : {} - -processRecord({} as NumberRecord | StringRecord | BooleanRecord) ->processRecord({} as NumberRecord | StringRecord | BooleanRecord) : void ->processRecord : (record: { kind: string; v: T; f: (v: T) => void; }) => void ->{} as NumberRecord | StringRecord | BooleanRecord : BooleanRecord | NumberRecord | StringRecord ->{} : {} - -function processRecord2(record1: GenericRecord, record2: GenericRecord) { ->processRecord2 : (record1: { kind: string; v: T; f: (v: T) => void; }, record2: { kind: string; v: T_1; f: (v: T_1) => void; }) => void ->record1 : { kind: string; v: T; f: (v: T) => void; } ->record2 : { kind: string; v: T; f: (v: T) => void; } - - record1.f(record2.v); // TODO: better error ->record1.f(record2.v) : void ->record1.f : (v: T) => void ->record1 : { kind: string; v: T; f: (v: T) => void; } ->f : (v: T) => void ->record2.v : T ->record2 : { kind: string; v: T; f: (v: T) => void; } ->v : T -} diff --git a/testdata/tests/cases/compiler/quantifiedTypesCorrelatedUnions.ts b/testdata/tests/cases/compiler/quantifiedTypesCorrelatedUnions.ts deleted file mode 100644 index c2bc4d73f90..00000000000 --- a/testdata/tests/cases/compiler/quantifiedTypesCorrelatedUnions.ts +++ /dev/null @@ -1,18 +0,0 @@ -// https://github.com/microsoft/TypeScript/issues/30581 - -type NumberRecord = { kind: "n", v: number, f: (v: number) => void }; -type StringRecord = { kind: "s", v: string, f: (v: string) => void }; -type BooleanRecord = { kind: "b", v: boolean, f: (v: boolean) => void }; -type GenericRecord = { kind: string, v: T, f: (v: T) => void }; - -function processRecord(record: GenericRecord) { - record.f(record.v); -} -processRecord({} as NumberRecord) -processRecord({} as StringRecord) -processRecord({} as BooleanRecord) -processRecord({} as NumberRecord | StringRecord | BooleanRecord) - -function processRecord2(record1: GenericRecord, record2: GenericRecord) { - record1.f(record2.v); // TODO: better error -} \ No newline at end of file From 7f46918230e21e797eee854ce74b12d632f7f9be Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Mon, 19 Jan 2026 18:11:01 +0530 Subject: [PATCH 19/23] unwrap baseType at a couple of more places --- internal/checker/checker.go | 6 + .../quantifiedTypesUnwrapBaseType.errors.txt | 93 ++++++++++ .../compiler/quantifiedTypesUnwrapBaseType.js | 159 ++++++++++++++++++ .../quantifiedTypesUnwrapBaseType.symbols | 106 ++++++++++++ .../quantifiedTypesUnwrapBaseType.types | 103 ++++++++++++ .../compiler/quantifiedTypesUnwrapBaseType.ts | 85 ++++++++++ 6 files changed, 552 insertions(+) create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.errors.txt create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.js create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.symbols create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.types create mode 100644 testdata/tests/cases/compiler/quantifiedTypesUnwrapBaseType.ts diff --git a/internal/checker/checker.go b/internal/checker/checker.go index 33b7e08283f..956bf91e07a 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -8380,6 +8380,9 @@ func (c *Checker) resolveCallExpression(node *ast.Node, candidatesOutArray *[]*S } var callChainFlags SignatureFlags funcType := c.checkExpression(node.Expression()) + if funcType.flags&TypeFlagsQuantified != 0 { + funcType = funcType.AsQuantifiedType().baseType + } if isCallChain(node) { nonOptionalType := c.getOptionalExpressionType(funcType, node.Expression()) switch { @@ -17298,6 +17301,9 @@ func (c *Checker) getBindingElementTypeFromParentType(declaration *ast.Node, par } else if c.strictNullChecks && pattern.Parent.Initializer() != nil && !(c.hasTypeFacts(c.getTypeOfInitializer(pattern.Parent.Initializer()), TypeFactsEQUndefined)) { parentType = c.getTypeWithFacts(parentType, TypeFactsNEUndefined) } + if parentType.flags&TypeFlagsQuantified != 0 { + parentType = parentType.AsQuantifiedType().baseType + } accessFlags := AccessFlagsExpressionPosition | core.IfElse(noTupleBoundsCheck || c.hasDefaultValue(declaration), AccessFlagsAllowMissing, 0) var t *Type switch pattern.Kind { diff --git a/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.errors.txt new file mode 100644 index 00000000000..998d0953780 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.errors.txt @@ -0,0 +1,93 @@ +quantifiedTypesUnwrapBaseType.ts(6,5): error TS2345: Argument of type 'number' is not assignable to parameter of type 'T'. + 'T' could be instantiated with an arbitrary type which could be unrelated to 'number'. + + +==== quantifiedTypesUnwrapBaseType.ts (1 errors) ==== + const f = (x: [T, NoInfer]) => { + let [t0, t1] = x + } + + const g = (f: ((t: T) => T)) => { + f(0) + ~ +!!! error TS2345: Argument of type 'number' is not assignable to parameter of type 'T'. +!!! error TS2345: 'T' could be instantiated with an arbitrary type which could be unrelated to 'number'. + } + + + + + + + + + + + + + + + /* + declare const str: string; + declare const num: number; + function acceptString(str: string) { } + function acceptNumber(num: number) { } + + const arr: ( [T, (t: T) => void])[] = [ + [str, acceptString], + [num, acceptNumber], + [str, acceptNumber], // should be error + ]; + + for (const pair of arr) { + const [arg, func] = pair; + func(arg); // should be no error + } + */ + /* + declare const f: (a: { + produce: (arg: string) => T, + consume: (arg: T) => unknown, + prop: { + produce: (arg: T) => U, + consume: (arg: U) => unknown, + } + }) => void + + f({ + produce: a => Number(a), + consume: x => { + x satisfies number + }, + prop: { + produce: x => { + x satisfies number + return Boolean(x) + }, + consume: y => { + y satisfies boolean + } + } + }) + */ + + /* + declare const smallest: + >(xs: T[]) => T + + smallest([1, 2, 3]) + smallest(["a", "b", "c"]) + + smallest([1, "b", 3]) + smallest([1, 2, undefined]) + + type OneOf = + ( + Actual extends Spec + ? IsUnit extends true ? Actual : never + : Spec + ) + + type IsUnit = + [U] extends (U extends unknown ? [U] : never) ? true : false + */ \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.js b/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.js new file mode 100644 index 00000000000..576c75ac18b --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.js @@ -0,0 +1,159 @@ +//// [tests/cases/compiler/quantifiedTypesUnwrapBaseType.ts] //// + +//// [quantifiedTypesUnwrapBaseType.ts] +const f = (x: [T, NoInfer]) => { + let [t0, t1] = x +} + +const g = (f: ((t: T) => T)) => { + f(0) +} + + + + + + + + + + + + + + +/* +declare const str: string; +declare const num: number; +function acceptString(str: string) { } +function acceptNumber(num: number) { } + +const arr: ( [T, (t: T) => void])[] = [ + [str, acceptString], + [num, acceptNumber], + [str, acceptNumber], // should be error +]; + +for (const pair of arr) { + const [arg, func] = pair; + func(arg); // should be no error +} +*/ +/* +declare const f: (a: { + produce: (arg: string) => T, + consume: (arg: T) => unknown, + prop: { + produce: (arg: T) => U, + consume: (arg: U) => unknown, + } +}) => void + +f({ + produce: a => Number(a), + consume: x => { + x satisfies number + }, + prop: { + produce: x => { + x satisfies number + return Boolean(x) + }, + consume: y => { + y satisfies boolean + } + } +}) +*/ + +/* +declare const smallest: + >(xs: T[]) => T + +smallest([1, 2, 3]) +smallest(["a", "b", "c"]) + +smallest([1, "b", 3]) +smallest([1, 2, undefined]) + +type OneOf = + ( + Actual extends Spec + ? IsUnit extends true ? Actual : never + : Spec + ) + +type IsUnit = + [U] extends (U extends unknown ? [U] : never) ? true : false +*/ + +//// [quantifiedTypesUnwrapBaseType.js] +const f = (x) => { + let [t0, t1] = x; +}; +const g = (f) => { + f(0); +}; +/* +declare const str: string; +declare const num: number; +function acceptString(str: string) { } +function acceptNumber(num: number) { } + +const arr: ( [T, (t: T) => void])[] = [ + [str, acceptString], + [num, acceptNumber], + [str, acceptNumber], // should be error +]; + +for (const pair of arr) { + const [arg, func] = pair; + func(arg); // should be no error +} +*/ +/* +declare const f: (a: { + produce: (arg: string) => T, + consume: (arg: T) => unknown, + prop: { + produce: (arg: T) => U, + consume: (arg: U) => unknown, + } +}) => void + +f({ + produce: a => Number(a), + consume: x => { + x satisfies number + }, + prop: { + produce: x => { + x satisfies number + return Boolean(x) + }, + consume: y => { + y satisfies boolean + } + } +}) +*/ +/* +declare const smallest: + >(xs: T[]) => T + +smallest([1, 2, 3]) +smallest(["a", "b", "c"]) + +smallest([1, "b", 3]) +smallest([1, 2, undefined]) + +type OneOf = + ( + Actual extends Spec + ? IsUnit extends true ? Actual : never + : Spec + ) + +type IsUnit = + [U] extends (U extends unknown ? [U] : never) ? true : false +*/ diff --git a/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.symbols b/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.symbols new file mode 100644 index 00000000000..ce9b7bcd5b8 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.symbols @@ -0,0 +1,106 @@ +//// [tests/cases/compiler/quantifiedTypesUnwrapBaseType.ts] //// + +=== quantifiedTypesUnwrapBaseType.ts === +const f = (x: [T, NoInfer]) => { +>f : Symbol(f, Decl(quantifiedTypesUnwrapBaseType.ts, 0, 5)) +>x : Symbol(x, Decl(quantifiedTypesUnwrapBaseType.ts, 0, 11)) +>T : Symbol(T, Decl(quantifiedTypesUnwrapBaseType.ts, 0, 15)) +>T : Symbol(T, Decl(quantifiedTypesUnwrapBaseType.ts, 0, 15)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(quantifiedTypesUnwrapBaseType.ts, 0, 15)) + + let [t0, t1] = x +>t0 : Symbol(t0, Decl(quantifiedTypesUnwrapBaseType.ts, 1, 7)) +>t1 : Symbol(t1, Decl(quantifiedTypesUnwrapBaseType.ts, 1, 10)) +>x : Symbol(x, Decl(quantifiedTypesUnwrapBaseType.ts, 0, 11)) +} + +const g = (f: ((t: T) => T)) => { +>g : Symbol(g, Decl(quantifiedTypesUnwrapBaseType.ts, 4, 5)) +>f : Symbol(f, Decl(quantifiedTypesUnwrapBaseType.ts, 4, 11)) +>T : Symbol(T, Decl(quantifiedTypesUnwrapBaseType.ts, 4, 15)) +>t : Symbol(t, Decl(quantifiedTypesUnwrapBaseType.ts, 4, 20)) +>T : Symbol(T, Decl(quantifiedTypesUnwrapBaseType.ts, 4, 15)) +>T : Symbol(T, Decl(quantifiedTypesUnwrapBaseType.ts, 4, 15)) + + f(0) +>f : Symbol(f, Decl(quantifiedTypesUnwrapBaseType.ts, 4, 11)) +} + + + + + + + + + + + + + + +/* +declare const str: string; +declare const num: number; +function acceptString(str: string) { } +function acceptNumber(num: number) { } + +const arr: ( [T, (t: T) => void])[] = [ + [str, acceptString], + [num, acceptNumber], + [str, acceptNumber], // should be error +]; + +for (const pair of arr) { + const [arg, func] = pair; + func(arg); // should be no error +} +*/ +/* +declare const f: (a: { + produce: (arg: string) => T, + consume: (arg: T) => unknown, + prop: { + produce: (arg: T) => U, + consume: (arg: U) => unknown, + } +}) => void + +f({ + produce: a => Number(a), + consume: x => { + x satisfies number + }, + prop: { + produce: x => { + x satisfies number + return Boolean(x) + }, + consume: y => { + y satisfies boolean + } + } +}) +*/ + +/* +declare const smallest: + >(xs: T[]) => T + +smallest([1, 2, 3]) +smallest(["a", "b", "c"]) + +smallest([1, "b", 3]) +smallest([1, 2, undefined]) + +type OneOf = + ( + Actual extends Spec + ? IsUnit extends true ? Actual : never + : Spec + ) + +type IsUnit = + [U] extends (U extends unknown ? [U] : never) ? true : false +*/ diff --git a/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.types b/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.types new file mode 100644 index 00000000000..99fcdb82d42 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.types @@ -0,0 +1,103 @@ +//// [tests/cases/compiler/quantifiedTypesUnwrapBaseType.ts] //// + +=== quantifiedTypesUnwrapBaseType.ts === +const f = (x: [T, NoInfer]) => { +>f : (x: [T, NoInfer]) => void +>(x: [T, NoInfer]) => { let [t0, t1] = x} : (x: [T, NoInfer]) => void +>x : [T, NoInfer] + + let [t0, t1] = x +>t0 : T +>t1 : NoInfer +>x : [T, NoInfer] +} + +const g = (f: ((t: T) => T)) => { +>g : (f: (t: T) => T) => void +>(f: ((t: T) => T)) => { f(0)} : (f: (t: T) => T) => void +>f : (t: T) => T +>t : T + + f(0) +>f(0) : T +>f : (t: T) => T +>0 : 0 +} + + + + + + + + + + + + + + +/* +declare const str: string; +declare const num: number; +function acceptString(str: string) { } +function acceptNumber(num: number) { } + +const arr: ( [T, (t: T) => void])[] = [ + [str, acceptString], + [num, acceptNumber], + [str, acceptNumber], // should be error +]; + +for (const pair of arr) { + const [arg, func] = pair; + func(arg); // should be no error +} +*/ +/* +declare const f: (a: { + produce: (arg: string) => T, + consume: (arg: T) => unknown, + prop: { + produce: (arg: T) => U, + consume: (arg: U) => unknown, + } +}) => void + +f({ + produce: a => Number(a), + consume: x => { + x satisfies number + }, + prop: { + produce: x => { + x satisfies number + return Boolean(x) + }, + consume: y => { + y satisfies boolean + } + } +}) +*/ + +/* +declare const smallest: + >(xs: T[]) => T + +smallest([1, 2, 3]) +smallest(["a", "b", "c"]) + +smallest([1, "b", 3]) +smallest([1, 2, undefined]) + +type OneOf = + ( + Actual extends Spec + ? IsUnit extends true ? Actual : never + : Spec + ) + +type IsUnit = + [U] extends (U extends unknown ? [U] : never) ? true : false +*/ diff --git a/testdata/tests/cases/compiler/quantifiedTypesUnwrapBaseType.ts b/testdata/tests/cases/compiler/quantifiedTypesUnwrapBaseType.ts new file mode 100644 index 00000000000..652ea218a37 --- /dev/null +++ b/testdata/tests/cases/compiler/quantifiedTypesUnwrapBaseType.ts @@ -0,0 +1,85 @@ +const f = (x: [T, NoInfer]) => { + let [t0, t1] = x +} + +const g = (f: ((t: T) => T)) => { + f(0) +} + + + + + + + + + + + + + + +/* +declare const str: string; +declare const num: number; +function acceptString(str: string) { } +function acceptNumber(num: number) { } + +const arr: ( [T, (t: T) => void])[] = [ + [str, acceptString], + [num, acceptNumber], + [str, acceptNumber], // should be error +]; + +for (const pair of arr) { + const [arg, func] = pair; + func(arg); // should be no error +} +*/ +/* +declare const f: (a: { + produce: (arg: string) => T, + consume: (arg: T) => unknown, + prop: { + produce: (arg: T) => U, + consume: (arg: U) => unknown, + } +}) => void + +f({ + produce: a => Number(a), + consume: x => { + x satisfies number + }, + prop: { + produce: x => { + x satisfies number + return Boolean(x) + }, + consume: y => { + y satisfies boolean + } + } +}) +*/ + +/* +declare const smallest: + >(xs: T[]) => T + +smallest([1, 2, 3]) +smallest(["a", "b", "c"]) + +smallest([1, "b", 3]) +smallest([1, 2, undefined]) + +type OneOf = + ( + Actual extends Spec + ? IsUnit extends true ? Actual : never + : Spec + ) + +type IsUnit = + [U] extends (U extends unknown ? [U] : never) ? true : false +*/ \ No newline at end of file From d9b6e8ad160cc5819730e8915c8a4491ec2d361a Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Fri, 23 Jan 2026 10:52:34 +0530 Subject: [PATCH 20/23] remove accidentally committed comments --- .../quantifiedTypesUnwrapBaseType.errors.txt | 79 +--------- .../compiler/quantifiedTypesUnwrapBaseType.js | 142 +----------------- .../quantifiedTypesUnwrapBaseType.symbols | 77 ---------- .../quantifiedTypesUnwrapBaseType.types | 77 ---------- .../compiler/quantifiedTypesUnwrapBaseType.ts | 78 ---------- 5 files changed, 2 insertions(+), 451 deletions(-) diff --git a/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.errors.txt index 998d0953780..8a15ce4f0d6 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.errors.txt +++ b/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.errors.txt @@ -13,81 +13,4 @@ quantifiedTypesUnwrapBaseType.ts(6,5): error TS2345: Argument of type 'number' i !!! error TS2345: Argument of type 'number' is not assignable to parameter of type 'T'. !!! error TS2345: 'T' could be instantiated with an arbitrary type which could be unrelated to 'number'. } - - - - - - - - - - - - - - - /* - declare const str: string; - declare const num: number; - function acceptString(str: string) { } - function acceptNumber(num: number) { } - - const arr: ( [T, (t: T) => void])[] = [ - [str, acceptString], - [num, acceptNumber], - [str, acceptNumber], // should be error - ]; - - for (const pair of arr) { - const [arg, func] = pair; - func(arg); // should be no error - } - */ - /* - declare const f: (a: { - produce: (arg: string) => T, - consume: (arg: T) => unknown, - prop: { - produce: (arg: T) => U, - consume: (arg: U) => unknown, - } - }) => void - - f({ - produce: a => Number(a), - consume: x => { - x satisfies number - }, - prop: { - produce: x => { - x satisfies number - return Boolean(x) - }, - consume: y => { - y satisfies boolean - } - } - }) - */ - - /* - declare const smallest: - >(xs: T[]) => T - - smallest([1, 2, 3]) - smallest(["a", "b", "c"]) - - smallest([1, "b", 3]) - smallest([1, 2, undefined]) - - type OneOf = - ( - Actual extends Spec - ? IsUnit extends true ? Actual : never - : Spec - ) - - type IsUnit = - [U] extends (U extends unknown ? [U] : never) ? true : false - */ \ No newline at end of file + \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.js b/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.js index 576c75ac18b..f3beaae75f1 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.js +++ b/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.js @@ -8,84 +8,7 @@ const f = (x: [T, NoInfer]) => { const g = (f: ((t: T) => T)) => { f(0) } - - - - - - - - - - - - - - -/* -declare const str: string; -declare const num: number; -function acceptString(str: string) { } -function acceptNumber(num: number) { } - -const arr: ( [T, (t: T) => void])[] = [ - [str, acceptString], - [num, acceptNumber], - [str, acceptNumber], // should be error -]; - -for (const pair of arr) { - const [arg, func] = pair; - func(arg); // should be no error -} -*/ -/* -declare const f: (a: { - produce: (arg: string) => T, - consume: (arg: T) => unknown, - prop: { - produce: (arg: T) => U, - consume: (arg: U) => unknown, - } -}) => void - -f({ - produce: a => Number(a), - consume: x => { - x satisfies number - }, - prop: { - produce: x => { - x satisfies number - return Boolean(x) - }, - consume: y => { - y satisfies boolean - } - } -}) -*/ - -/* -declare const smallest: - >(xs: T[]) => T - -smallest([1, 2, 3]) -smallest(["a", "b", "c"]) - -smallest([1, "b", 3]) -smallest([1, 2, undefined]) - -type OneOf = - ( - Actual extends Spec - ? IsUnit extends true ? Actual : never - : Spec - ) - -type IsUnit = - [U] extends (U extends unknown ? [U] : never) ? true : false -*/ + //// [quantifiedTypesUnwrapBaseType.js] const f = (x) => { @@ -94,66 +17,3 @@ const f = (x) => { const g = (f) => { f(0); }; -/* -declare const str: string; -declare const num: number; -function acceptString(str: string) { } -function acceptNumber(num: number) { } - -const arr: ( [T, (t: T) => void])[] = [ - [str, acceptString], - [num, acceptNumber], - [str, acceptNumber], // should be error -]; - -for (const pair of arr) { - const [arg, func] = pair; - func(arg); // should be no error -} -*/ -/* -declare const f: (a: { - produce: (arg: string) => T, - consume: (arg: T) => unknown, - prop: { - produce: (arg: T) => U, - consume: (arg: U) => unknown, - } -}) => void - -f({ - produce: a => Number(a), - consume: x => { - x satisfies number - }, - prop: { - produce: x => { - x satisfies number - return Boolean(x) - }, - consume: y => { - y satisfies boolean - } - } -}) -*/ -/* -declare const smallest: - >(xs: T[]) => T - -smallest([1, 2, 3]) -smallest(["a", "b", "c"]) - -smallest([1, "b", 3]) -smallest([1, 2, undefined]) - -type OneOf = - ( - Actual extends Spec - ? IsUnit extends true ? Actual : never - : Spec - ) - -type IsUnit = - [U] extends (U extends unknown ? [U] : never) ? true : false -*/ diff --git a/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.symbols b/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.symbols index ce9b7bcd5b8..8593dc78547 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.symbols +++ b/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.symbols @@ -27,80 +27,3 @@ const g = (f: ((t: T) => T)) => { >f : Symbol(f, Decl(quantifiedTypesUnwrapBaseType.ts, 4, 11)) } - - - - - - - - - - - - - -/* -declare const str: string; -declare const num: number; -function acceptString(str: string) { } -function acceptNumber(num: number) { } - -const arr: ( [T, (t: T) => void])[] = [ - [str, acceptString], - [num, acceptNumber], - [str, acceptNumber], // should be error -]; - -for (const pair of arr) { - const [arg, func] = pair; - func(arg); // should be no error -} -*/ -/* -declare const f: (a: { - produce: (arg: string) => T, - consume: (arg: T) => unknown, - prop: { - produce: (arg: T) => U, - consume: (arg: U) => unknown, - } -}) => void - -f({ - produce: a => Number(a), - consume: x => { - x satisfies number - }, - prop: { - produce: x => { - x satisfies number - return Boolean(x) - }, - consume: y => { - y satisfies boolean - } - } -}) -*/ - -/* -declare const smallest: - >(xs: T[]) => T - -smallest([1, 2, 3]) -smallest(["a", "b", "c"]) - -smallest([1, "b", 3]) -smallest([1, 2, undefined]) - -type OneOf = - ( - Actual extends Spec - ? IsUnit extends true ? Actual : never - : Spec - ) - -type IsUnit = - [U] extends (U extends unknown ? [U] : never) ? true : false -*/ diff --git a/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.types b/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.types index 99fcdb82d42..603d38a51c1 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.types +++ b/testdata/baselines/reference/compiler/quantifiedTypesUnwrapBaseType.types @@ -24,80 +24,3 @@ const g = (f: ((t: T) => T)) => { >0 : 0 } - - - - - - - - - - - - - -/* -declare const str: string; -declare const num: number; -function acceptString(str: string) { } -function acceptNumber(num: number) { } - -const arr: ( [T, (t: T) => void])[] = [ - [str, acceptString], - [num, acceptNumber], - [str, acceptNumber], // should be error -]; - -for (const pair of arr) { - const [arg, func] = pair; - func(arg); // should be no error -} -*/ -/* -declare const f: (a: { - produce: (arg: string) => T, - consume: (arg: T) => unknown, - prop: { - produce: (arg: T) => U, - consume: (arg: U) => unknown, - } -}) => void - -f({ - produce: a => Number(a), - consume: x => { - x satisfies number - }, - prop: { - produce: x => { - x satisfies number - return Boolean(x) - }, - consume: y => { - y satisfies boolean - } - } -}) -*/ - -/* -declare const smallest: - >(xs: T[]) => T - -smallest([1, 2, 3]) -smallest(["a", "b", "c"]) - -smallest([1, "b", 3]) -smallest([1, 2, undefined]) - -type OneOf = - ( - Actual extends Spec - ? IsUnit extends true ? Actual : never - : Spec - ) - -type IsUnit = - [U] extends (U extends unknown ? [U] : never) ? true : false -*/ diff --git a/testdata/tests/cases/compiler/quantifiedTypesUnwrapBaseType.ts b/testdata/tests/cases/compiler/quantifiedTypesUnwrapBaseType.ts index 652ea218a37..3a3cc7a58fa 100644 --- a/testdata/tests/cases/compiler/quantifiedTypesUnwrapBaseType.ts +++ b/testdata/tests/cases/compiler/quantifiedTypesUnwrapBaseType.ts @@ -5,81 +5,3 @@ const f = (x: [T, NoInfer]) => { const g = (f: ((t: T) => T)) => { f(0) } - - - - - - - - - - - - - - -/* -declare const str: string; -declare const num: number; -function acceptString(str: string) { } -function acceptNumber(num: number) { } - -const arr: ( [T, (t: T) => void])[] = [ - [str, acceptString], - [num, acceptNumber], - [str, acceptNumber], // should be error -]; - -for (const pair of arr) { - const [arg, func] = pair; - func(arg); // should be no error -} -*/ -/* -declare const f: (a: { - produce: (arg: string) => T, - consume: (arg: T) => unknown, - prop: { - produce: (arg: T) => U, - consume: (arg: U) => unknown, - } -}) => void - -f({ - produce: a => Number(a), - consume: x => { - x satisfies number - }, - prop: { - produce: x => { - x satisfies number - return Boolean(x) - }, - consume: y => { - y satisfies boolean - } - } -}) -*/ - -/* -declare const smallest: - >(xs: T[]) => T - -smallest([1, 2, 3]) -smallest(["a", "b", "c"]) - -smallest([1, "b", 3]) -smallest([1, 2, undefined]) - -type OneOf = - ( - Actual extends Spec - ? IsUnit extends true ? Actual : never - : Spec - ) - -type IsUnit = - [U] extends (U extends unknown ? [U] : never) ? true : false -*/ \ No newline at end of file From d4f68f1c1dec036e86ad4d71b6825c3778ab4614 Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Sat, 24 Jan 2026 14:09:03 +0530 Subject: [PATCH 21/23] add an example of correlated union cases that is unsolved --- ...uantifiedTypesCorrelatedUnions1.errors.txt | 28 ++++++++++ .../quantifiedTypesCorrelatedUnions1.js | 35 ++++++++++++ .../quantifiedTypesCorrelatedUnions1.symbols | 55 ++++++++++++++++++ .../quantifiedTypesCorrelatedUnions1.types | 56 +++++++++++++++++++ .../quantifiedTypesCorrelatedUnions1.ts | 17 ++++++ 5 files changed, 191 insertions(+) create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.errors.txt create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.js create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.symbols create mode 100644 testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.types create mode 100644 testdata/tests/cases/compiler/quantifiedTypesCorrelatedUnions1.ts diff --git a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.errors.txt new file mode 100644 index 00000000000..f7e84dd6c9a --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.errors.txt @@ -0,0 +1,28 @@ +quantifiedTypesCorrelatedUnions1.ts(11,11): error TS2322: Type '(num: number) => void' is not assignable to type '(t: string) => void'. + Types of parameters 'num' and 't' are incompatible. + Type 'string' is not assignable to type 'number'. + + +==== quantifiedTypesCorrelatedUnions1.ts (1 errors) ==== + // https://github.com/microsoft/TypeScript/issues/30581#issuecomment-493492463 + + declare const str: string; + declare const num: number; + function acceptString(str: string) { } + function acceptNumber(num: number) { } + + const arr: ( [T, (t: NoInfer) => void])[] = [ + [str, acceptString], + [num, acceptNumber], + [str, acceptNumber], // error as expected + ~~~~~~~~~~~~ +!!! error TS2322: Type '(num: number) => void' is not assignable to type '(t: string) => void'. +!!! error TS2322: Types of parameters 'num' and 't' are incompatible. +!!! error TS2322: Type 'string' is not assignable to type 'number'. + ]; + + for (const pair of arr) { + const [arg, func] = pair; // no error + func(arg); + } + \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.js b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.js new file mode 100644 index 00000000000..2387942d149 --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.js @@ -0,0 +1,35 @@ +//// [tests/cases/compiler/quantifiedTypesCorrelatedUnions1.ts] //// + +//// [quantifiedTypesCorrelatedUnions1.ts] +// https://github.com/microsoft/TypeScript/issues/30581#issuecomment-493492463 + +declare const str: string; +declare const num: number; +function acceptString(str: string) { } +function acceptNumber(num: number) { } + +const arr: ( [T, (t: NoInfer) => void])[] = [ + [str, acceptString], + [num, acceptNumber], + [str, acceptNumber], // error as expected +]; + +for (const pair of arr) { + const [arg, func] = pair; // no error + func(arg); +} + + +//// [quantifiedTypesCorrelatedUnions1.js] +// https://github.com/microsoft/TypeScript/issues/30581#issuecomment-493492463 +function acceptString(str) { } +function acceptNumber(num) { } +const arr = [ + [str, acceptString], + [num, acceptNumber], + [str, acceptNumber], // error as expected +]; +for (const pair of arr) { + const [arg, func] = pair; // no error + func(arg); +} diff --git a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.symbols b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.symbols new file mode 100644 index 00000000000..6118060f52b --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.symbols @@ -0,0 +1,55 @@ +//// [tests/cases/compiler/quantifiedTypesCorrelatedUnions1.ts] //// + +=== quantifiedTypesCorrelatedUnions1.ts === +// https://github.com/microsoft/TypeScript/issues/30581#issuecomment-493492463 + +declare const str: string; +>str : Symbol(str, Decl(quantifiedTypesCorrelatedUnions1.ts, 2, 13)) + +declare const num: number; +>num : Symbol(num, Decl(quantifiedTypesCorrelatedUnions1.ts, 3, 13)) + +function acceptString(str: string) { } +>acceptString : Symbol(acceptString, Decl(quantifiedTypesCorrelatedUnions1.ts, 3, 26)) +>str : Symbol(str, Decl(quantifiedTypesCorrelatedUnions1.ts, 4, 22)) + +function acceptNumber(num: number) { } +>acceptNumber : Symbol(acceptNumber, Decl(quantifiedTypesCorrelatedUnions1.ts, 4, 38)) +>num : Symbol(num, Decl(quantifiedTypesCorrelatedUnions1.ts, 5, 22)) + +const arr: ( [T, (t: NoInfer) => void])[] = [ +>arr : Symbol(arr, Decl(quantifiedTypesCorrelatedUnions1.ts, 7, 5)) +>T : Symbol(T, Decl(quantifiedTypesCorrelatedUnions1.ts, 7, 13)) +>T : Symbol(T, Decl(quantifiedTypesCorrelatedUnions1.ts, 7, 13)) +>t : Symbol(t, Decl(quantifiedTypesCorrelatedUnions1.ts, 7, 21)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(quantifiedTypesCorrelatedUnions1.ts, 7, 13)) + + [str, acceptString], +>str : Symbol(str, Decl(quantifiedTypesCorrelatedUnions1.ts, 2, 13)) +>acceptString : Symbol(acceptString, Decl(quantifiedTypesCorrelatedUnions1.ts, 3, 26)) + + [num, acceptNumber], +>num : Symbol(num, Decl(quantifiedTypesCorrelatedUnions1.ts, 3, 13)) +>acceptNumber : Symbol(acceptNumber, Decl(quantifiedTypesCorrelatedUnions1.ts, 4, 38)) + + [str, acceptNumber], // error as expected +>str : Symbol(str, Decl(quantifiedTypesCorrelatedUnions1.ts, 2, 13)) +>acceptNumber : Symbol(acceptNumber, Decl(quantifiedTypesCorrelatedUnions1.ts, 4, 38)) + +]; + +for (const pair of arr) { +>pair : Symbol(pair, Decl(quantifiedTypesCorrelatedUnions1.ts, 13, 10)) +>arr : Symbol(arr, Decl(quantifiedTypesCorrelatedUnions1.ts, 7, 5)) + + const [arg, func] = pair; // no error +>arg : Symbol(arg, Decl(quantifiedTypesCorrelatedUnions1.ts, 14, 11)) +>func : Symbol(func, Decl(quantifiedTypesCorrelatedUnions1.ts, 14, 15)) +>pair : Symbol(pair, Decl(quantifiedTypesCorrelatedUnions1.ts, 13, 10)) + + func(arg); +>func : Symbol(func, Decl(quantifiedTypesCorrelatedUnions1.ts, 14, 15)) +>arg : Symbol(arg, Decl(quantifiedTypesCorrelatedUnions1.ts, 14, 11)) +} + diff --git a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.types b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.types new file mode 100644 index 00000000000..5c2db1cbd7a --- /dev/null +++ b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.types @@ -0,0 +1,56 @@ +//// [tests/cases/compiler/quantifiedTypesCorrelatedUnions1.ts] //// + +=== quantifiedTypesCorrelatedUnions1.ts === +// https://github.com/microsoft/TypeScript/issues/30581#issuecomment-493492463 + +declare const str: string; +>str : string + +declare const num: number; +>num : number + +function acceptString(str: string) { } +>acceptString : (str: string) => void +>str : string + +function acceptNumber(num: number) { } +>acceptNumber : (num: number) => void +>num : number + +const arr: ( [T, (t: NoInfer) => void])[] = [ +>arr : ( [T, (t: NoInfer) => void])[] +>t : NoInfer +>[ [str, acceptString], [num, acceptNumber], [str, acceptNumber], // error as expected] : any[] + + [str, acceptString], +>[str, acceptString] : [string, (str: string) => void] +>str : string +>acceptString : (str: string) => void + + [num, acceptNumber], +>[num, acceptNumber] : [number, (num: number) => void] +>num : number +>acceptNumber : (num: number) => void + + [str, acceptNumber], // error as expected +>[str, acceptNumber] : any +>str : string +>acceptNumber : (num: number) => void + +]; + +for (const pair of arr) { +>pair : [T, (t: NoInfer) => void] +>arr : ( [T, (t: NoInfer) => void])[] + + const [arg, func] = pair; // no error +>arg : T +>func : (t: NoInfer) => void +>pair : [T, (t: NoInfer) => void] + + func(arg); +>func(arg) : void +>func : (t: NoInfer) => void +>arg : T +} + diff --git a/testdata/tests/cases/compiler/quantifiedTypesCorrelatedUnions1.ts b/testdata/tests/cases/compiler/quantifiedTypesCorrelatedUnions1.ts new file mode 100644 index 00000000000..ca8551acf50 --- /dev/null +++ b/testdata/tests/cases/compiler/quantifiedTypesCorrelatedUnions1.ts @@ -0,0 +1,17 @@ +// https://github.com/microsoft/TypeScript/issues/30581#issuecomment-493492463 + +declare const str: string; +declare const num: number; +function acceptString(str: string) { } +function acceptNumber(num: number) { } + +const arr: ( [T, (t: NoInfer) => void])[] = [ + [str, acceptString], + [num, acceptNumber], + [str, acceptNumber], // error as expected +]; + +for (const pair of arr) { + const [arg, func] = pair; // no error + func(arg); +} From d9737f1166d9f593fb70f76ec6fc00ae7e8fc743 Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Sat, 24 Jan 2026 14:18:24 +0530 Subject: [PATCH 22/23] fix comment --- .../compiler/quantifiedTypesCorrelatedUnions1.errors.txt | 4 ++-- .../compiler/quantifiedTypesCorrelatedUnions1.js | 8 ++++---- .../compiler/quantifiedTypesCorrelatedUnions1.symbols | 4 ++-- .../compiler/quantifiedTypesCorrelatedUnions1.types | 4 ++-- .../cases/compiler/quantifiedTypesCorrelatedUnions1.ts | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.errors.txt index f7e84dd6c9a..993ff8708df 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.errors.txt +++ b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.errors.txt @@ -22,7 +22,7 @@ quantifiedTypesCorrelatedUnions1.ts(11,11): error TS2322: Type '(num: number) => ]; for (const pair of arr) { - const [arg, func] = pair; // no error - func(arg); + const [arg, func] = pair; + func(arg); // no error } \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.js b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.js index 2387942d149..fc56e482657 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.js +++ b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.js @@ -15,8 +15,8 @@ const arr: ( [T, (t: NoInfer) => void])[] = [ ]; for (const pair of arr) { - const [arg, func] = pair; // no error - func(arg); + const [arg, func] = pair; + func(arg); // no error } @@ -30,6 +30,6 @@ const arr = [ [str, acceptNumber], // error as expected ]; for (const pair of arr) { - const [arg, func] = pair; // no error - func(arg); + const [arg, func] = pair; + func(arg); // no error } diff --git a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.symbols b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.symbols index 6118060f52b..e3e8cec7a9c 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.symbols +++ b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.symbols @@ -43,12 +43,12 @@ for (const pair of arr) { >pair : Symbol(pair, Decl(quantifiedTypesCorrelatedUnions1.ts, 13, 10)) >arr : Symbol(arr, Decl(quantifiedTypesCorrelatedUnions1.ts, 7, 5)) - const [arg, func] = pair; // no error + const [arg, func] = pair; >arg : Symbol(arg, Decl(quantifiedTypesCorrelatedUnions1.ts, 14, 11)) >func : Symbol(func, Decl(quantifiedTypesCorrelatedUnions1.ts, 14, 15)) >pair : Symbol(pair, Decl(quantifiedTypesCorrelatedUnions1.ts, 13, 10)) - func(arg); + func(arg); // no error >func : Symbol(func, Decl(quantifiedTypesCorrelatedUnions1.ts, 14, 15)) >arg : Symbol(arg, Decl(quantifiedTypesCorrelatedUnions1.ts, 14, 11)) } diff --git a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.types b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.types index 5c2db1cbd7a..9dc1ebbb859 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.types +++ b/testdata/baselines/reference/compiler/quantifiedTypesCorrelatedUnions1.types @@ -43,12 +43,12 @@ for (const pair of arr) { >pair : [T, (t: NoInfer) => void] >arr : ( [T, (t: NoInfer) => void])[] - const [arg, func] = pair; // no error + const [arg, func] = pair; >arg : T >func : (t: NoInfer) => void >pair : [T, (t: NoInfer) => void] - func(arg); + func(arg); // no error >func(arg) : void >func : (t: NoInfer) => void >arg : T diff --git a/testdata/tests/cases/compiler/quantifiedTypesCorrelatedUnions1.ts b/testdata/tests/cases/compiler/quantifiedTypesCorrelatedUnions1.ts index ca8551acf50..67c01e463b3 100644 --- a/testdata/tests/cases/compiler/quantifiedTypesCorrelatedUnions1.ts +++ b/testdata/tests/cases/compiler/quantifiedTypesCorrelatedUnions1.ts @@ -12,6 +12,6 @@ const arr: ( [T, (t: NoInfer) => void])[] = [ ]; for (const pair of arr) { - const [arg, func] = pair; // no error - func(arg); + const [arg, func] = pair; + func(arg); // no error } From 1c5e9f848c6adaa0ec3b7666dfa6d2df10770ced Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Sat, 24 Jan 2026 14:34:58 +0530 Subject: [PATCH 23/23] remove accidentally added comment --- ...ifiedTypesBoundedTypeParameters.errors.txt | 54 +--------- .../quantifiedTypesBoundedTypeParameters.js | 98 +------------------ ...antifiedTypesBoundedTypeParameters.symbols | 49 ---------- ...quantifiedTypesBoundedTypeParameters.types | 49 ---------- .../quantifiedTypesBoundedTypeParameters.ts | 51 ---------- 5 files changed, 3 insertions(+), 298 deletions(-) diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.errors.txt b/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.errors.txt index 473f01d05e3..59b8a943742 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.errors.txt +++ b/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.errors.txt @@ -1,4 +1,4 @@ -quantifiedTypesBoundedTypeParameters.ts(7,6): error TS2345: Argument of type 'T' is not assignable to parameter of type 'T'. +quantifiedTypesBoundedTypeParameters.ts(6,6): error TS2345: Argument of type 'T' is not assignable to parameter of type 'T'. Both type parameters are bounded to different variables 'T' could be instantiated with an arbitrary type which could be unrelated to 'T'. @@ -9,7 +9,6 @@ quantifiedTypesBoundedTypeParameters.ts(7,6): error TS2345: Argument of type 'T' declare let f2: F f1.f(f1.v) - f1.f(f2.v) ~~~~ !!! error TS2345: Argument of type 'T' is not assignable to parameter of type 'T'. @@ -17,53 +16,4 @@ quantifiedTypesBoundedTypeParameters.ts(7,6): error TS2345: Argument of type 'T' !!! error TS2345: 'T' could be instantiated with an arbitrary type which could be unrelated to 'T'. !!! related TS5114 quantifiedTypesBoundedTypeParameters.ts:3:13: Type parameter 'T' is bounded to this variable !!! related TS5114 quantifiedTypesBoundedTypeParameters.ts:2:13: Type parameter 'T' is bounded to this variable - - - - /* - declare const f: (a: { - produce: (arg: string) => T, - consume: (arg: T) => unknown, - prop: { - produce: (arg: T) => U, - consume: (arg: U) => unknown, - } - }) => void - - f({ - produce: a => Number(a), - consume: x => { - x satisfies number - }, - prop: { - produce: x => { - x satisfies number - return Boolean(x) - }, - consume: y => { - y satisfies boolean - } - } - }) - */ - - /* - declare const smallest: - >(xs: T[]) => T - - smallest([1, 2, 3]) - smallest(["a", "b", "c"]) - - smallest([1, "b", 3]) - smallest([1, 2, undefined]) - - type OneOf = - ( - Actual extends Spec - ? IsUnit extends true ? Actual : never - : Spec - ) - - type IsUnit = - [U] extends (U extends unknown ? [U] : never) ? true : false - */ \ No newline at end of file + \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.js b/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.js index 8ee4c417bd1..4b00a72d0b3 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.js +++ b/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.js @@ -6,105 +6,9 @@ declare let f1: F declare let f2: F f1.f(f1.v) - f1.f(f2.v) - - - -/* -declare const f: (a: { - produce: (arg: string) => T, - consume: (arg: T) => unknown, - prop: { - produce: (arg: T) => U, - consume: (arg: U) => unknown, - } -}) => void - -f({ - produce: a => Number(a), - consume: x => { - x satisfies number - }, - prop: { - produce: x => { - x satisfies number - return Boolean(x) - }, - consume: y => { - y satisfies boolean - } - } -}) -*/ - -/* -declare const smallest: - >(xs: T[]) => T - -smallest([1, 2, 3]) -smallest(["a", "b", "c"]) - -smallest([1, "b", 3]) -smallest([1, 2, undefined]) - -type OneOf = - ( - Actual extends Spec - ? IsUnit extends true ? Actual : never - : Spec - ) - -type IsUnit = - [U] extends (U extends unknown ? [U] : never) ? true : false -*/ + //// [quantifiedTypesBoundedTypeParameters.js] f1.f(f1.v); f1.f(f2.v); -/* -declare const f: (a: { - produce: (arg: string) => T, - consume: (arg: T) => unknown, - prop: { - produce: (arg: T) => U, - consume: (arg: U) => unknown, - } -}) => void - -f({ - produce: a => Number(a), - consume: x => { - x satisfies number - }, - prop: { - produce: x => { - x satisfies number - return Boolean(x) - }, - consume: y => { - y satisfies boolean - } - } -}) -*/ -/* -declare const smallest: - >(xs: T[]) => T - -smallest([1, 2, 3]) -smallest(["a", "b", "c"]) - -smallest([1, "b", 3]) -smallest([1, 2, undefined]) - -type OneOf = - ( - Actual extends Spec - ? IsUnit extends true ? Actual : never - : Spec - ) - -type IsUnit = - [U] extends (U extends unknown ? [U] : never) ? true : false -*/ diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.symbols b/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.symbols index 4deb8e78164..f56b3f519f2 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.symbols +++ b/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.symbols @@ -34,52 +34,3 @@ f1.f(f2.v) >f2 : Symbol(f2, Decl(quantifiedTypesBoundedTypeParameters.ts, 2, 11)) >v : Symbol(v, Decl(quantifiedTypesBoundedTypeParameters.ts, 0, 14)) - - -/* -declare const f: (a: { - produce: (arg: string) => T, - consume: (arg: T) => unknown, - prop: { - produce: (arg: T) => U, - consume: (arg: U) => unknown, - } -}) => void - -f({ - produce: a => Number(a), - consume: x => { - x satisfies number - }, - prop: { - produce: x => { - x satisfies number - return Boolean(x) - }, - consume: y => { - y satisfies boolean - } - } -}) -*/ - -/* -declare const smallest: - >(xs: T[]) => T - -smallest([1, 2, 3]) -smallest(["a", "b", "c"]) - -smallest([1, "b", 3]) -smallest([1, 2, undefined]) - -type OneOf = - ( - Actual extends Spec - ? IsUnit extends true ? Actual : never - : Spec - ) - -type IsUnit = - [U] extends (U extends unknown ? [U] : never) ? true : false -*/ diff --git a/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.types b/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.types index e5a64931aa1..e5689db2d92 100644 --- a/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.types +++ b/testdata/baselines/reference/compiler/quantifiedTypesBoundedTypeParameters.types @@ -31,52 +31,3 @@ f1.f(f2.v) >f2 : { v: T; f: (v: T) => void; } >v : T - - -/* -declare const f: (a: { - produce: (arg: string) => T, - consume: (arg: T) => unknown, - prop: { - produce: (arg: T) => U, - consume: (arg: U) => unknown, - } -}) => void - -f({ - produce: a => Number(a), - consume: x => { - x satisfies number - }, - prop: { - produce: x => { - x satisfies number - return Boolean(x) - }, - consume: y => { - y satisfies boolean - } - } -}) -*/ - -/* -declare const smallest: - >(xs: T[]) => T - -smallest([1, 2, 3]) -smallest(["a", "b", "c"]) - -smallest([1, "b", 3]) -smallest([1, 2, undefined]) - -type OneOf = - ( - Actual extends Spec - ? IsUnit extends true ? Actual : never - : Spec - ) - -type IsUnit = - [U] extends (U extends unknown ? [U] : never) ? true : false -*/ diff --git a/testdata/tests/cases/compiler/quantifiedTypesBoundedTypeParameters.ts b/testdata/tests/cases/compiler/quantifiedTypesBoundedTypeParameters.ts index 4793384aa34..6e1af86bc45 100644 --- a/testdata/tests/cases/compiler/quantifiedTypesBoundedTypeParameters.ts +++ b/testdata/tests/cases/compiler/quantifiedTypesBoundedTypeParameters.ts @@ -3,55 +3,4 @@ declare let f1: F declare let f2: F f1.f(f1.v) - f1.f(f2.v) - - - -/* -declare const f: (a: { - produce: (arg: string) => T, - consume: (arg: T) => unknown, - prop: { - produce: (arg: T) => U, - consume: (arg: U) => unknown, - } -}) => void - -f({ - produce: a => Number(a), - consume: x => { - x satisfies number - }, - prop: { - produce: x => { - x satisfies number - return Boolean(x) - }, - consume: y => { - y satisfies boolean - } - } -}) -*/ - -/* -declare const smallest: - >(xs: T[]) => T - -smallest([1, 2, 3]) -smallest(["a", "b", "c"]) - -smallest([1, "b", 3]) -smallest([1, 2, undefined]) - -type OneOf = - ( - Actual extends Spec - ? IsUnit extends true ? Actual : never - : Spec - ) - -type IsUnit = - [U] extends (U extends unknown ? [U] : never) ? true : false -*/ \ No newline at end of file