From b2005d0618165d273926ab7fed4ca5854c486079 Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Tue, 30 Dec 2025 21:05:55 +0530 Subject: [PATCH 1/9] 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 3d6dbcffcc..acd5d37875 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 ed98bd68ff..6a359cefed 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 3430cc2cb1..4a6ac4ed3a 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 9acf84a78f..b3113f62ef 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 f7339d9870..341beb946b 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 f2a212a060..df49fca0ee 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 332a72569e..4cbbc1f6ed 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 9bf61948b9..f6f18c85bd 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 1fb4c35794..8d0bdc1fa9 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 bf65552c7f..28d74c049c 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 3e2aafbd4c..b872bd7b51 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 00436c0a1b..8b982b40b7 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 fec95a7ab1..8b37ec0d9b 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 0000000000..94e01d9ba6 --- /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 0000000000..e8ead920d7 --- /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 0000000000..600f750c1d --- /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 0000000000..8b17ec27ca --- /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 0000000000..d4bdf87766 --- /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 0000000000..cf4677eeb3 --- /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 0000000000..0ee3169345 --- /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 0000000000..c3f9c3a878 --- /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 0000000000..014c66f234 --- /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 0000000000..a5cca619d1 --- /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 0000000000..62c7cbe1e5 --- /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 0000000000..14214eb5c2 --- /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 0000000000..957017a7b0 --- /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 0000000000..3099c513f4 --- /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 0000000000..c3021a7a17 --- /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 0000000000..be578a75d1 --- /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 0000000000..eb438b6078 --- /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 0000000000..382b53bd89 --- /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 0000000000..df6663b3dd --- /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 0000000000..9f7e3c3332 --- /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 0000000000..a0bc31d741 --- /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 0000000000..1ff71c460c --- /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 0000000000..7e2c259a0e --- /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 0000000000..6dfb104ba1 --- /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 0000000000..6175a59ba0 --- /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 0000000000..0ce23b0287 --- /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 0000000000..393ffb003c --- /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 0000000000..71ba0c99c8 --- /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 0000000000..ac06e2aedb --- /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 0000000000..3c5167ee4d --- /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 0000000000..5cab18f873 --- /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 0000000000..2c1b5080f6 --- /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 0000000000..e69de29bb2 diff --git a/testdata/tests/cases/compiler/quantifiedTypesBasic.ts b/testdata/tests/cases/compiler/quantifiedTypesBasic.ts new file mode 100644 index 0000000000..7abdd40a2a --- /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 0000000000..adb6a4cfdc --- /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 0000000000..e32b1c9dda --- /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 0000000000..b1f0876e06 --- /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 0000000000..5a06230a30 --- /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 0000000000..324a8920bb --- /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 0000000000..bd9746035b --- /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 2/9] 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 e69de29bb2..0000000000 From a051f76be96ea80243d0b981760721e6c78900d6 Mon Sep 17 00:00:00 2001 From: Devansh Jethmalani Date: Sun, 4 Jan 2026 20:11:02 +0530 Subject: [PATCH 3/9] 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 df49fca0ee..06bb36aa0e 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 4/9] 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 06bb36aa0e..48811de607 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 0000000000..adeb814c1c --- /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 0000000000..0124660873 --- /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 0000000000..1fd1571ee0 --- /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 0000000000..4eb2f83c33 --- /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 8b17ec27ca..38148ca7e8 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 0ee3169345..1908d24f2a 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 c3f9c3a878..3e04efef51 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 62c7cbe1e5..a5f6f0f448 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 14214eb5c2..709c2fa0a5 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 c3021a7a17..82d96e3f35 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 be578a75d1..7a19c68884 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 df6663b3dd..3adbdf63e7 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 9f7e3c3332..49820d3d45 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 7e2c259a0e..a056d39039 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 6dfb104ba1..7eb9c7328a 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 393ffb003c..81fd7caee9 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 71ba0c99c8..6332d61108 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 5cab18f873..59bd1d8cb9 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 0000000000..56c71fd147 --- /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 5/9] 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 28d74c049c..d75c13cdf2 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 6/9] 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 56c71fd147..d3ecd39e6d 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 7/9] 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 48811de607..8893eb1163 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 8b37ec0d9b..b21646cfc4 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 0000000000..3a786df798 --- /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 0000000000..0a7a9c737a --- /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 0000000000..4dd5c97fed --- /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 0000000000..298ef12633 --- /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 0000000000..b65ea49e8b --- /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 0000000000..2ce8c87df1 --- /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 0000000000..3fba34c1f1 --- /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 0000000000..ec538b5d50 --- /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 8/9] 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 8893eb1163..fc0b358c6b 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 4eb2f83c33..b7d1ffad49 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 0000000000..bf2cb764c7 --- /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 0000000000..ab66b8caf4 --- /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 0000000000..e9cc9744c5 --- /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 0000000000..168335e035 --- /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 9/9] 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 0000000000..ddc1590c26 --- /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 0000000000..0f1d6da794 --- /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 0000000000..66f3d99d61 --- /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 0000000000..357dd94445 --- /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 0000000000..522a3f52c7 --- /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 +}