From a414fc8c76781d3d1cca6e97b3c1261a149c50fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 30 Aug 2026 19:12:19 +0200 Subject: [PATCH 1/6] Fixed an issue with mapped property symbol not displaying added `| undefined` when its origin symbol was optional --- tsc/internal/checker/emitresolver.go | 13 +++++++-- ...kInfoMappedPropertyUnionUndefined1_test.go | 29 +++++++++++++++++++ ...kInfoMappedPropertyUnionUndefined2_test.go | 27 +++++++++++++++++ ...kInfoMappedPropertyUnionUndefined3_test.go | 21 ++++++++++++++ ...kInfoMappedPropertyUnionUndefined4_test.go | 20 +++++++++++++ ...kInfoMappedPropertyUnionUndefined5_test.go | 28 ++++++++++++++++++ ...eOptionalPropertyExplicitUndefined_test.go | 19 ++++++++++++ 7 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 tsc/internal/fourslash/tests/quickInfoMappedPropertyUnionUndefined1_test.go create mode 100644 tsc/internal/fourslash/tests/quickInfoMappedPropertyUnionUndefined2_test.go create mode 100644 tsc/internal/fourslash/tests/quickInfoMappedPropertyUnionUndefined3_test.go create mode 100644 tsc/internal/fourslash/tests/quickInfoMappedPropertyUnionUndefined4_test.go create mode 100644 tsc/internal/fourslash/tests/quickInfoMappedPropertyUnionUndefined5_test.go create mode 100644 tsc/internal/fourslash/tests/quickInfoMappedTypeOptionalPropertyExplicitUndefined_test.go diff --git a/tsc/internal/checker/emitresolver.go b/tsc/internal/checker/emitresolver.go index 1a4f86696fd2a..eaa72add36a92 100644 --- a/tsc/internal/checker/emitresolver.go +++ b/tsc/internal/checker/emitresolver.go @@ -589,12 +589,21 @@ func (r *EmitResolver) requiresAddingImplicitUndefined(declaration *ast.Node, sy } switch declaration.Kind { case ast.KindPropertyDeclaration, ast.KindPropertySignature, ast.KindJSDocPropertyTag: + if !isOptionalDeclaration(declaration) { + return false + } if symbol == nil { symbol = r.checker.getSymbolOfDeclaration(declaration) } + if symbol.Flags&ast.SymbolFlagsProperty == 0 || symbol.CheckFlags&ast.CheckFlagsMapped == 0 { + return false + } t := r.checker.getTypeOfSymbol(symbol) - r.checker.mappedSymbolLinks.Has(symbol) - return (symbol.Flags&ast.SymbolFlagsProperty != 0) && (symbol.Flags&ast.SymbolFlagsOptional != 0) && isOptionalDeclaration(declaration) && r.checker.ReverseMappedSymbolLinks.Has(symbol) && r.checker.ReverseMappedSymbolLinks.Get(symbol).mappedType != nil && containsNonMissingUndefinedType(r.checker, t) + if !containsNonMissingUndefinedType(r.checker, t) { + return false + } + declaredType := declaration.Type() + return declaredType != nil && !r.checker.containsUndefinedType(r.checker.getTypeFromTypeNode(declaredType)) case ast.KindParameter, ast.KindJSDocParameterTag: return r.requiresAddingImplicitUndefinedWorker(declaration, enclosingDeclaration) default: diff --git a/tsc/internal/fourslash/tests/quickInfoMappedPropertyUnionUndefined1_test.go b/tsc/internal/fourslash/tests/quickInfoMappedPropertyUnionUndefined1_test.go new file mode 100644 index 0000000000000..40a007928c04f --- /dev/null +++ b/tsc/internal/fourslash/tests/quickInfoMappedPropertyUnionUndefined1_test.go @@ -0,0 +1,29 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/TypeScript/tsc/internal/fourslash" + "github.com/microsoft/TypeScript/tsc/internal/testutil" +) + +func TestQuickInfoMappedPropertyUnionUndefined1(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @strict: true +// @exactOptionalPropertyTypes: true +// https://github.com/microsoft/TypeScript/issues/59948 +type OptionalToUnionWithUndefined = { + [K in keyof T]: T extends Record ? T[K] : T[K] | undefined; +}; +type Intermediate/*1*/ = OptionalToUnionWithUndefined<{ a?: string }>; +type Literal/*2*/ = { a?: string | undefined }; +type Res1/*3*/ = Required; +type Res2/*4*/ = Required;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyQuickInfoAt(t, "1", "type Intermediate = {\n a?: string | undefined;\n}", "") + f.VerifyQuickInfoAt(t, "2", "type Literal = {\n a?: string | undefined;\n}", "") + f.VerifyQuickInfoAt(t, "3", "type Res1 = {\n a: string | undefined;\n}", "") + f.VerifyQuickInfoAt(t, "4", "type Res2 = {\n a: string | undefined;\n}", "") +} diff --git a/tsc/internal/fourslash/tests/quickInfoMappedPropertyUnionUndefined2_test.go b/tsc/internal/fourslash/tests/quickInfoMappedPropertyUnionUndefined2_test.go new file mode 100644 index 0000000000000..be0efdb0fad92 --- /dev/null +++ b/tsc/internal/fourslash/tests/quickInfoMappedPropertyUnionUndefined2_test.go @@ -0,0 +1,27 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/TypeScript/tsc/internal/fourslash" + "github.com/microsoft/TypeScript/tsc/internal/testutil" +) + +func TestQuickInfoMappedPropertyUnionUndefined2(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @strict: true +type OptionalToUnionWithUndefined = { + [K in keyof T]: T extends Record ? T[K] : T[K] | undefined; +}; +type Intermediate/*1*/ = OptionalToUnionWithUndefined<{ a?: string }>; +type Literal/*2*/ = { a?: string | undefined }; +type Res1/*3*/ = Required; +type Res2/*4*/ = Required;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyQuickInfoAt(t, "1", "type Intermediate = {\n a?: string | undefined;\n}", "") + f.VerifyQuickInfoAt(t, "2", "type Literal = {\n a?: string | undefined;\n}", "") + f.VerifyQuickInfoAt(t, "3", "type Res1 = {\n a: string;\n}", "") + f.VerifyQuickInfoAt(t, "4", "type Res2 = {\n a: string;\n}", "") +} diff --git a/tsc/internal/fourslash/tests/quickInfoMappedPropertyUnionUndefined3_test.go b/tsc/internal/fourslash/tests/quickInfoMappedPropertyUnionUndefined3_test.go new file mode 100644 index 0000000000000..36ffa636860d2 --- /dev/null +++ b/tsc/internal/fourslash/tests/quickInfoMappedPropertyUnionUndefined3_test.go @@ -0,0 +1,21 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/TypeScript/tsc/internal/fourslash" + "github.com/microsoft/TypeScript/tsc/internal/testutil" +) + +func TestQuickInfoMappedPropertyUnionUndefined3(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// https://github.com/microsoft/TypeScript/issues/60411 +// @strict: true +type UnsetUndefinedToOblivion = { [P in keyof T]-?: T[P] | undefined }; +type SetUndefined = { [P in keyof T]: T[P] | undefined }; +type TheWhat/**/ = SetUndefined>;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyQuickInfoAt(t, "", "type TheWhat = {\n a: 1 | undefined;\n}", "") +} diff --git a/tsc/internal/fourslash/tests/quickInfoMappedPropertyUnionUndefined4_test.go b/tsc/internal/fourslash/tests/quickInfoMappedPropertyUnionUndefined4_test.go new file mode 100644 index 0000000000000..008e6150b491d --- /dev/null +++ b/tsc/internal/fourslash/tests/quickInfoMappedPropertyUnionUndefined4_test.go @@ -0,0 +1,20 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/TypeScript/tsc/internal/fourslash" + "github.com/microsoft/TypeScript/tsc/internal/testutil" +) + +func TestQuickInfoMappedPropertyUnionUndefined4(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @strict: true +type A/*1*/ = { [K in keyof { a?: string }]-?: string }; +type B/*2*/ = { [K in keyof A]: string | undefined };` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyQuickInfoAt(t, "1", "type A = {\n a: string;\n}", "") + f.VerifyQuickInfoAt(t, "2", "type B = {\n a: string | undefined;\n}", "") +} diff --git a/tsc/internal/fourslash/tests/quickInfoMappedPropertyUnionUndefined5_test.go b/tsc/internal/fourslash/tests/quickInfoMappedPropertyUnionUndefined5_test.go new file mode 100644 index 0000000000000..0bb14b842c112 --- /dev/null +++ b/tsc/internal/fourslash/tests/quickInfoMappedPropertyUnionUndefined5_test.go @@ -0,0 +1,28 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/TypeScript/tsc/internal/fourslash" + "github.com/microsoft/TypeScript/tsc/internal/testutil" +) + +func TestQuickInfoMappedPropertyUnionUndefined5(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @strict: true +// https://github.com/microsoft/TypeScript/issues/62325 +type RequiredKeys = { + [K in keyof Required]: T[K]; +}; +type Foo = { + a?: string; + b?: number; + c: string; + d: boolean | undefined; +}; +type Bar/*1*/ = RequiredKeys;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyQuickInfoAt(t, "1", "type Bar = {\n a: string | undefined;\n b: number | undefined;\n c: string;\n d: boolean | undefined;\n}", "") +} diff --git a/tsc/internal/fourslash/tests/quickInfoMappedTypeOptionalPropertyExplicitUndefined_test.go b/tsc/internal/fourslash/tests/quickInfoMappedTypeOptionalPropertyExplicitUndefined_test.go new file mode 100644 index 0000000000000..e9d117fe21708 --- /dev/null +++ b/tsc/internal/fourslash/tests/quickInfoMappedTypeOptionalPropertyExplicitUndefined_test.go @@ -0,0 +1,19 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/TypeScript/tsc/internal/fourslash" + "github.com/microsoft/TypeScript/tsc/internal/testutil" +) + +func TestQuickInfoMappedTypeOptionalPropertyExplicitUndefined(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @strict: true +type X = { x?: number | undefined }; +type /*Y*/Y = { [K in keyof X]: X[K] };` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyQuickInfoAt(t, "Y", "type Y = {\n x?: number | undefined;\n}", "") +} From 21a355adf047350df2afa08d4d487661f5018af7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 30 Aug 2026 19:22:17 +0200 Subject: [PATCH 2/6] extra tests --- ...eOptionalPropertyExplicitUndefined_test.go | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tsc/internal/fourslash/tests/quickInfoMappedTypeOptionalPropertyExplicitUndefined_test.go b/tsc/internal/fourslash/tests/quickInfoMappedTypeOptionalPropertyExplicitUndefined_test.go index e9d117fe21708..f9dfbf993a359 100644 --- a/tsc/internal/fourslash/tests/quickInfoMappedTypeOptionalPropertyExplicitUndefined_test.go +++ b/tsc/internal/fourslash/tests/quickInfoMappedTypeOptionalPropertyExplicitUndefined_test.go @@ -17,3 +17,27 @@ type /*Y*/Y = { [K in keyof X]: X[K] };` defer done() f.VerifyQuickInfoAt(t, "Y", "type Y = {\n x?: number | undefined;\n}", "") } + +func TestQuickInfoMappedTypeOptionalPropertyExplicitUndefinedExactOptionalPropertyTypes(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @strict: true +// @exactOptionalPropertyTypes: true +type X = { x?: number | undefined }; +type /*Y*/Y = { [K in keyof X]: X[K] };` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyQuickInfoAt(t, "Y", "type Y = {\n x?: number | undefined;\n}", "") +} + +func TestQuickInfoMappedTypeRequiredPropertyExplicitUndefinedExactOptionalPropertyTypes(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @strict: true +// @exactOptionalPropertyTypes: true +type X = { x?: number | undefined }; +type /*Y*/Y = { [K in keyof X]-?: X[K] };` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyQuickInfoAt(t, "Y", "type Y = {\n x: number | undefined;\n}", "") +} From 1aebdeed8b7034990d1ddeb3ecf276648f5334a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 30 Aug 2026 20:10:33 +0200 Subject: [PATCH 3/6] Preserve reverse mapped undefined handling --- tsc/internal/checker/emitresolver.go | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tsc/internal/checker/emitresolver.go b/tsc/internal/checker/emitresolver.go index eaa72add36a92..4fe54a86f2cbb 100644 --- a/tsc/internal/checker/emitresolver.go +++ b/tsc/internal/checker/emitresolver.go @@ -595,9 +595,18 @@ func (r *EmitResolver) requiresAddingImplicitUndefined(declaration *ast.Node, sy if symbol == nil { symbol = r.checker.getSymbolOfDeclaration(declaration) } - if symbol.Flags&ast.SymbolFlagsProperty == 0 || symbol.CheckFlags&ast.CheckFlagsMapped == 0 { + isReverseMapped := r.checker.ReverseMappedSymbolLinks.Has(symbol) && r.checker.ReverseMappedSymbolLinks.Get(symbol).mappedType != nil + isMapped := symbol.CheckFlags&ast.CheckFlagsMapped != 0 + if symbol.Flags&ast.SymbolFlagsProperty == 0 || !isReverseMapped && !isMapped { return false } + if isMapped && symbol.Flags&ast.SymbolFlagsOptional != 0 { + mappedType := r.checker.valueSymbolLinks.Get(symbol).containingType + mappedType = core.OrElse(mappedType.AsMappedType().target, mappedType) + if getMappedTypeModifiers(mappedType)&MappedTypeModifiersIncludeOptional != 0 || !typeNodeContainsUndefined(mappedType.AsMappedType().declaration.Type) { + return false + } + } t := r.checker.getTypeOfSymbol(symbol) if !containsNonMissingUndefinedType(r.checker, t) { return false @@ -611,6 +620,16 @@ func (r *EmitResolver) requiresAddingImplicitUndefined(declaration *ast.Node, sy } } +func typeNodeContainsUndefined(node *ast.Node) bool { + if node == nil { + return false + } + if node.Kind == ast.KindUndefinedKeyword { + return true + } + return node.ForEachChild(typeNodeContainsUndefined) +} + func (r *EmitResolver) requiresAddingImplicitUndefinedWorker(parameter *ast.Node, enclosingDeclaration *ast.Node) bool { return (r.isRequiredInitializedParameter(parameter, enclosingDeclaration) || r.isOptionalUninitializedParameterProperty(parameter)) && !r.declaredParameterTypeContainsUndefined(parameter) } From 692fe99813074abb8719a437d1a26e683aad1ef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 30 Aug 2026 20:57:30 +0200 Subject: [PATCH 4/6] Handle inferred mapped properties --- tsc/internal/checker/emitresolver.go | 2 +- ...eOptionalPropertyExplicitUndefined_test.go | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/tsc/internal/checker/emitresolver.go b/tsc/internal/checker/emitresolver.go index 4fe54a86f2cbb..2d8173ab0bfbd 100644 --- a/tsc/internal/checker/emitresolver.go +++ b/tsc/internal/checker/emitresolver.go @@ -612,7 +612,7 @@ func (r *EmitResolver) requiresAddingImplicitUndefined(declaration *ast.Node, sy return false } declaredType := declaration.Type() - return declaredType != nil && !r.checker.containsUndefinedType(r.checker.getTypeFromTypeNode(declaredType)) + return declaredType == nil || !r.checker.containsUndefinedType(r.checker.getTypeFromTypeNode(declaredType)) case ast.KindParameter, ast.KindJSDocParameterTag: return r.requiresAddingImplicitUndefinedWorker(declaration, enclosingDeclaration) default: diff --git a/tsc/internal/fourslash/tests/quickInfoMappedTypeOptionalPropertyExplicitUndefined_test.go b/tsc/internal/fourslash/tests/quickInfoMappedTypeOptionalPropertyExplicitUndefined_test.go index f9dfbf993a359..d66134403be63 100644 --- a/tsc/internal/fourslash/tests/quickInfoMappedTypeOptionalPropertyExplicitUndefined_test.go +++ b/tsc/internal/fourslash/tests/quickInfoMappedTypeOptionalPropertyExplicitUndefined_test.go @@ -41,3 +41,28 @@ type /*Y*/Y = { [K in keyof X]-?: X[K] };` defer done() f.VerifyQuickInfoAt(t, "Y", "type Y = {\n x: number | undefined;\n}", "") } + +func TestQuickInfoMappedTypeOptionalInferredPropertyExplicitUndefined(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @strict: true +class C { x? = 1 as number } +type M = { [K in keyof T]: T[K] | undefined }; +type /*Y*/Y = M;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyQuickInfoAt(t, "Y", "type Y = {\n x?: number | undefined;\n}", "") +} + +func TestQuickInfoMappedTypeOptionalInferredPropertyExplicitUndefinedExactOptionalPropertyTypes(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @strict: true +// @exactOptionalPropertyTypes: true +class C { x? = 1 as number } +type M = { [K in keyof T]: T[K] | undefined }; +type /*Y*/Y = M;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyQuickInfoAt(t, "Y", "type Y = {\n x?: number | undefined;\n}", "") +} From cf3c4326d3dc165edcdebf104ac3734d04adc9cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 30 Aug 2026 21:30:16 +0200 Subject: [PATCH 5/6] Follow undefined through mapped templates --- tsc/internal/checker/emitresolver.go | 12 +------ tsc/internal/checker/utilities.go | 33 +++++++++++++++++++ ...eOptionalPropertyExplicitUndefined_test.go | 26 +++++++++++++++ 3 files changed, 60 insertions(+), 11 deletions(-) diff --git a/tsc/internal/checker/emitresolver.go b/tsc/internal/checker/emitresolver.go index 2d8173ab0bfbd..385c71c9c943c 100644 --- a/tsc/internal/checker/emitresolver.go +++ b/tsc/internal/checker/emitresolver.go @@ -603,7 +603,7 @@ func (r *EmitResolver) requiresAddingImplicitUndefined(declaration *ast.Node, sy if isMapped && symbol.Flags&ast.SymbolFlagsOptional != 0 { mappedType := r.checker.valueSymbolLinks.Get(symbol).containingType mappedType = core.OrElse(mappedType.AsMappedType().target, mappedType) - if getMappedTypeModifiers(mappedType)&MappedTypeModifiersIncludeOptional != 0 || !typeNodeContainsUndefined(mappedType.AsMappedType().declaration.Type) { + if getMappedTypeModifiers(mappedType)&MappedTypeModifiersIncludeOptional != 0 || !mappedTypeTemplateContainsNonMissingUndefined(r.checker, mappedType) { return false } } @@ -620,16 +620,6 @@ func (r *EmitResolver) requiresAddingImplicitUndefined(declaration *ast.Node, sy } } -func typeNodeContainsUndefined(node *ast.Node) bool { - if node == nil { - return false - } - if node.Kind == ast.KindUndefinedKeyword { - return true - } - return node.ForEachChild(typeNodeContainsUndefined) -} - func (r *EmitResolver) requiresAddingImplicitUndefinedWorker(parameter *ast.Node, enclosingDeclaration *ast.Node) bool { return (r.isRequiredInitializedParameter(parameter, enclosingDeclaration) || r.isOptionalUninitializedParameterProperty(parameter)) && !r.declaredParameterTypeContainsUndefined(parameter) } diff --git a/tsc/internal/checker/utilities.go b/tsc/internal/checker/utilities.go index 9c486a5bb90ab..8da34c0dbb822 100644 --- a/tsc/internal/checker/utilities.go +++ b/tsc/internal/checker/utilities.go @@ -1599,6 +1599,39 @@ func containsNonMissingUndefinedType(c *Checker, t *Type) bool { return candidate.flags&TypeFlagsUndefined != 0 && candidate != c.missingType } +func mappedTypeTemplateContainsNonMissingUndefined(c *Checker, mappedType *Type) bool { + seen := make(map[*Type]struct{}) + var visit func(t *Type) bool + visit = func(t *Type) bool { + if t == nil { + return false + } + if containsNonMissingUndefinedType(c, t) { + return true + } + if _, ok := seen[t]; ok { + return false + } + seen[t] = struct{}{} + switch { + case t.flags&TypeFlagsConditional != 0: + return visit(c.getTrueTypeFromConditionalType(t)) || visit(c.getFalseTypeFromConditionalType(t)) + case t.flags&TypeFlagsIndexedAccess != 0: + objectType := t.AsIndexedAccessType().ObjectType() + if objectType.flags&TypeFlagsObject != 0 && objectType.ObjectFlags()&ObjectFlagsMapped != 0 { + objectType = core.OrElse(objectType.AsMappedType().target, objectType) + return visit(c.getTemplateTypeFromMappedType(objectType)) + } + case t.flags&TypeFlagsObject != 0 && t.ObjectFlags()&ObjectFlagsMapped != 0: + t = core.OrElse(t.AsMappedType().target, t) + return visit(c.getTemplateTypeFromMappedType(t)) + } + return false + } + mappedType = core.OrElse(mappedType.AsMappedType().target, mappedType) + return visit(c.getTemplateTypeFromMappedType(mappedType)) +} + func getAnyImportSyntax(node *ast.Node) *ast.Node { var importNode *ast.Node switch node.Kind { diff --git a/tsc/internal/fourslash/tests/quickInfoMappedTypeOptionalPropertyExplicitUndefined_test.go b/tsc/internal/fourslash/tests/quickInfoMappedTypeOptionalPropertyExplicitUndefined_test.go index d66134403be63..9e96793a5902e 100644 --- a/tsc/internal/fourslash/tests/quickInfoMappedTypeOptionalPropertyExplicitUndefined_test.go +++ b/tsc/internal/fourslash/tests/quickInfoMappedTypeOptionalPropertyExplicitUndefined_test.go @@ -66,3 +66,29 @@ type /*Y*/Y = M;` defer done() f.VerifyQuickInfoAt(t, "Y", "type Y = {\n x?: number | undefined;\n}", "") } + +func TestQuickInfoMappedTypeOptionalInferredPropertyAliasedUndefined(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @strict: true +type Maybe = T | undefined; +class C { x? = 1 as number } +type M = { [K in keyof T]: Maybe }; +type /*Y*/Y = M;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyQuickInfoAt(t, "Y", "type Y = {\n x?: number | undefined;\n}", "") +} + +func TestQuickInfoMappedTypeOptionalInferredPropertyNestedMappedType(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @strict: true +class C { x? = 1 as number } +type Inner = { [K in keyof T]: T[K] | undefined }; +type Outer = { [K in keyof Inner]: Inner[K] }; +type /*Y*/Y = Outer;` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyQuickInfoAt(t, "Y", "type Y = {\n x?: number | undefined;\n}", "") +} From a6ea896a0a1b6e1db3878ad9c0c2811c07dbec26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 31 Aug 2026 07:22:13 +0200 Subject: [PATCH 6/6] Match mapped property undefined display behavior --- tsc/internal/checker/emitresolver.go | 9 +---- tsc/internal/checker/nodebuilderimpl.go | 12 +++++-- tsc/internal/checker/utilities.go | 33 ------------------- ...eused(exactoptionalpropertytypes=false).js | 2 +- ...ed(exactoptionalpropertytypes=false).types | 6 ++-- ...Reused(exactoptionalpropertytypes=true).js | 2 +- ...sed(exactoptionalpropertytypes=true).types | 6 ++-- ...itUsingAlternativeContainingModules1.types | 6 ++-- ...itUsingAlternativeContainingModules2.types | 8 ++--- .../identityAndDivergentNormalizedTypes.types | 2 +- .../conformance/mappedTypeErrors.types | 2 +- 11 files changed, 27 insertions(+), 61 deletions(-) diff --git a/tsc/internal/checker/emitresolver.go b/tsc/internal/checker/emitresolver.go index 385c71c9c943c..6afd0d0e3408e 100644 --- a/tsc/internal/checker/emitresolver.go +++ b/tsc/internal/checker/emitresolver.go @@ -600,19 +600,12 @@ func (r *EmitResolver) requiresAddingImplicitUndefined(declaration *ast.Node, sy if symbol.Flags&ast.SymbolFlagsProperty == 0 || !isReverseMapped && !isMapped { return false } - if isMapped && symbol.Flags&ast.SymbolFlagsOptional != 0 { - mappedType := r.checker.valueSymbolLinks.Get(symbol).containingType - mappedType = core.OrElse(mappedType.AsMappedType().target, mappedType) - if getMappedTypeModifiers(mappedType)&MappedTypeModifiersIncludeOptional != 0 || !mappedTypeTemplateContainsNonMissingUndefined(r.checker, mappedType) { - return false - } - } t := r.checker.getTypeOfSymbol(symbol) if !containsNonMissingUndefinedType(r.checker, t) { return false } declaredType := declaration.Type() - return declaredType == nil || !r.checker.containsUndefinedType(r.checker.getTypeFromTypeNode(declaredType)) + return declaredType != nil && !r.checker.containsUndefinedType(r.checker.getTypeFromTypeNode(declaredType)) case ast.KindParameter, ast.KindJSDocParameterTag: return r.requiresAddingImplicitUndefinedWorker(declaration, enclosingDeclaration) default: diff --git a/tsc/internal/checker/nodebuilderimpl.go b/tsc/internal/checker/nodebuilderimpl.go index 53007b500e8c6..bbc90ef409373 100644 --- a/tsc/internal/checker/nodebuilderimpl.go +++ b/tsc/internal/checker/nodebuilderimpl.go @@ -2246,11 +2246,17 @@ func (b *NodeBuilderImpl) serializeTypeForDeclaration(declaration *ast.Declarati } } reportErrors := !b.ctx.suppressReportInferenceFallback - if b.pseudoTypeEquivalentToType(pt, t, !requiresAddingUndefined && (ast.IsParameterDeclaration(declaration) || ast.IsPropertySignatureDeclaration(declaration) || ast.IsPropertyDeclaration(declaration)) && isOptionalDeclaration(declaration), reportErrors) { + isReverseMappedProperty := symbol != nil && b.ch.ReverseMappedSymbolLinks.Has(symbol) && b.ch.ReverseMappedSymbolLinks.Get(symbol).mappedType != nil + isMappedProperty := symbol != nil && (symbol.CheckFlags&ast.CheckFlagsMapped != 0 || isReverseMappedProperty) + // Strada only applies annotation reuse to an existing annotation. For an inferred mapped property, + // validate the pseudo-type with the computed non-missing undefined instead. + addUndefinedForInferredOptional := isMappedProperty && !hasTypeAnnotation(declaration) && (ast.IsPropertySignatureDeclaration(declaration) || ast.IsPropertyDeclaration(declaration)) && isOptionalDeclaration(declaration) && containsNonMissingUndefinedType(b.ch, t) + requiresAddingUndefinedForReuse := requiresAddingUndefined || addUndefinedForInferredOptional + if b.pseudoTypeEquivalentToType(pt, t, !requiresAddingUndefinedForReuse && (ast.IsParameterDeclaration(declaration) || ast.IsPropertySignatureDeclaration(declaration) || ast.IsPropertyDeclaration(declaration)) && isOptionalDeclaration(declaration), reportErrors) { // !!! TODO: If annotated type node is a reference with insufficient type arguments, we should still fall back to type serialization // see: canReuseTypeNodeAnnotation in strada for context ptt := b.pseudoTypeToType(pt) - if ptt != nil && requiresAddingUndefined && containsNonMissingUndefinedType(b.ch, t) && !containsNonMissingUndefinedType(b.ch, ptt) { + if ptt != nil && requiresAddingUndefinedForReuse && containsNonMissingUndefinedType(b.ch, t) && !containsNonMissingUndefinedType(b.ch, ptt) { pt = pseudochecker.NewPseudoTypeUnion([]*pseudochecker.PseudoType{pt, pseudochecker.PseudoTypeUndefined}) } result = b.pseudoTypeToNodeWithCheckerFallback(pt, t) @@ -2261,7 +2267,7 @@ func (b *NodeBuilderImpl) serializeTypeForDeclaration(declaration *ast.Declarati // pseudoTypeToNodeWithCheckerFallback provides). reportedInferenceFallback = reportErrors && pt.Kind == pseudochecker.PseudoTypeKindInferred && len(pt.AsPseudoTypeInferred().ErrorNodes) > 0 shouldAddUndefined := false - if requiresAddingUndefined { + if requiresAddingUndefinedForReuse { if ptt := b.pseudoTypeToType(pt); ptt != nil { shouldAddUndefined = !containsNonMissingUndefinedType(b.ch, ptt) } else { diff --git a/tsc/internal/checker/utilities.go b/tsc/internal/checker/utilities.go index 8da34c0dbb822..9c486a5bb90ab 100644 --- a/tsc/internal/checker/utilities.go +++ b/tsc/internal/checker/utilities.go @@ -1599,39 +1599,6 @@ func containsNonMissingUndefinedType(c *Checker, t *Type) bool { return candidate.flags&TypeFlagsUndefined != 0 && candidate != c.missingType } -func mappedTypeTemplateContainsNonMissingUndefined(c *Checker, mappedType *Type) bool { - seen := make(map[*Type]struct{}) - var visit func(t *Type) bool - visit = func(t *Type) bool { - if t == nil { - return false - } - if containsNonMissingUndefinedType(c, t) { - return true - } - if _, ok := seen[t]; ok { - return false - } - seen[t] = struct{}{} - switch { - case t.flags&TypeFlagsConditional != 0: - return visit(c.getTrueTypeFromConditionalType(t)) || visit(c.getFalseTypeFromConditionalType(t)) - case t.flags&TypeFlagsIndexedAccess != 0: - objectType := t.AsIndexedAccessType().ObjectType() - if objectType.flags&TypeFlagsObject != 0 && objectType.ObjectFlags()&ObjectFlagsMapped != 0 { - objectType = core.OrElse(objectType.AsMappedType().target, objectType) - return visit(c.getTemplateTypeFromMappedType(objectType)) - } - case t.flags&TypeFlagsObject != 0 && t.ObjectFlags()&ObjectFlagsMapped != 0: - t = core.OrElse(t.AsMappedType().target, t) - return visit(c.getTemplateTypeFromMappedType(t)) - } - return false - } - mappedType = core.OrElse(mappedType.AsMappedType().target, mappedType) - return visit(c.getTemplateTypeFromMappedType(mappedType)) -} - func getAnyImportSyntax(node *ast.Node) *ast.Node { var importNode *ast.Node switch node.Kind { diff --git a/tsc/testdata/baselines/reference/compiler/declarationEmitExactOptionalPropertyTypesNodeNotReused(exactoptionalpropertytypes=false).js b/tsc/testdata/baselines/reference/compiler/declarationEmitExactOptionalPropertyTypesNodeNotReused(exactoptionalpropertytypes=false).js index 35723374eebe3..d2be47f74dd3d 100644 --- a/tsc/testdata/baselines/reference/compiler/declarationEmitExactOptionalPropertyTypesNodeNotReused(exactoptionalpropertytypes=false).js +++ b/tsc/testdata/baselines/reference/compiler/declarationEmitExactOptionalPropertyTypesNodeNotReused(exactoptionalpropertytypes=false).js @@ -32,7 +32,7 @@ exports.baddts = foo(); //// [declarationEmitExactOptionalPropertyTypesNodeNotReused.d.ts] export declare const baddts: (x: { - foo?: string; + foo?: string | undefined; baz?: undefined; } & { bar: number; diff --git a/tsc/testdata/baselines/reference/compiler/declarationEmitExactOptionalPropertyTypesNodeNotReused(exactoptionalpropertytypes=false).types b/tsc/testdata/baselines/reference/compiler/declarationEmitExactOptionalPropertyTypesNodeNotReused(exactoptionalpropertytypes=false).types index 1024779328cab..f48c527718b32 100644 --- a/tsc/testdata/baselines/reference/compiler/declarationEmitExactOptionalPropertyTypesNodeNotReused(exactoptionalpropertytypes=false).types +++ b/tsc/testdata/baselines/reference/compiler/declarationEmitExactOptionalPropertyTypesNodeNotReused(exactoptionalpropertytypes=false).types @@ -31,10 +31,10 @@ const foo = () => (x: Out & A) => null >foo : () => (x: Out & A) => null >() => (x: Out & A) => null : () => (x: Out & A) => null >(x: Out & A) => null : (x: Out & A) => null ->x : { foo?: string; baz?: undefined; } & { bar: number; } & A +>x : { foo?: string | undefined; baz?: undefined; } & { bar: number; } & A export const baddts = foo() ->baddts : (x: { foo?: string; baz?: undefined; } & { bar: number; }) => null ->foo() : (x: { foo?: string; baz?: undefined; } & { bar: number; }) => null +>baddts : (x: { foo?: string | undefined; baz?: undefined; } & { bar: number; }) => null +>foo() : (x: { foo?: string | undefined; baz?: undefined; } & { bar: number; }) => null >foo : () => (x: Out & A) => null diff --git a/tsc/testdata/baselines/reference/compiler/declarationEmitExactOptionalPropertyTypesNodeNotReused(exactoptionalpropertytypes=true).js b/tsc/testdata/baselines/reference/compiler/declarationEmitExactOptionalPropertyTypesNodeNotReused(exactoptionalpropertytypes=true).js index 35723374eebe3..d2be47f74dd3d 100644 --- a/tsc/testdata/baselines/reference/compiler/declarationEmitExactOptionalPropertyTypesNodeNotReused(exactoptionalpropertytypes=true).js +++ b/tsc/testdata/baselines/reference/compiler/declarationEmitExactOptionalPropertyTypesNodeNotReused(exactoptionalpropertytypes=true).js @@ -32,7 +32,7 @@ exports.baddts = foo(); //// [declarationEmitExactOptionalPropertyTypesNodeNotReused.d.ts] export declare const baddts: (x: { - foo?: string; + foo?: string | undefined; baz?: undefined; } & { bar: number; diff --git a/tsc/testdata/baselines/reference/compiler/declarationEmitExactOptionalPropertyTypesNodeNotReused(exactoptionalpropertytypes=true).types b/tsc/testdata/baselines/reference/compiler/declarationEmitExactOptionalPropertyTypesNodeNotReused(exactoptionalpropertytypes=true).types index 1024779328cab..f48c527718b32 100644 --- a/tsc/testdata/baselines/reference/compiler/declarationEmitExactOptionalPropertyTypesNodeNotReused(exactoptionalpropertytypes=true).types +++ b/tsc/testdata/baselines/reference/compiler/declarationEmitExactOptionalPropertyTypesNodeNotReused(exactoptionalpropertytypes=true).types @@ -31,10 +31,10 @@ const foo = () => (x: Out & A) => null >foo : () => (x: Out & A) => null >() => (x: Out & A) => null : () => (x: Out & A) => null >(x: Out & A) => null : (x: Out & A) => null ->x : { foo?: string; baz?: undefined; } & { bar: number; } & A +>x : { foo?: string | undefined; baz?: undefined; } & { bar: number; } & A export const baddts = foo() ->baddts : (x: { foo?: string; baz?: undefined; } & { bar: number; }) => null ->foo() : (x: { foo?: string; baz?: undefined; } & { bar: number; }) => null +>baddts : (x: { foo?: string | undefined; baz?: undefined; } & { bar: number; }) => null +>foo() : (x: { foo?: string | undefined; baz?: undefined; } & { bar: number; }) => null >foo : () => (x: Out & A) => null diff --git a/tsc/testdata/baselines/reference/compiler/declarationEmitUsingAlternativeContainingModules1.types b/tsc/testdata/baselines/reference/compiler/declarationEmitUsingAlternativeContainingModules1.types index 73749e3e83bd8..ad5e5e5989de6 100644 --- a/tsc/testdata/baselines/reference/compiler/declarationEmitUsingAlternativeContainingModules1.types +++ b/tsc/testdata/baselines/reference/compiler/declarationEmitUsingAlternativeContainingModules1.types @@ -301,11 +301,11 @@ export { type UseQueryReturnType, useQuery }; === node_modules/@tanstack/vue-query/build/modern/index.d.ts === export { UseQueryReturnType, useQuery } from './useQuery-CPqkvEsh.js'; >UseQueryReturnType : any ->useQuery : (options: { retry?: (number | boolean | ((failureCount: number, error: TError) => boolean)) | undefined; queryFn?: ((context: { queryKey: TQueryKey; }) => TQueryFnData | Promise) | undefined; queryKey?: TQueryKey | undefined; initialData?: TQueryFnData | undefined; initialDataUpdatedAt?: number | (() => number | undefined); enabled?: boolean; refetchInterval?: number; select?: ((data: TQueryFnData) => TData) | undefined; } & { initialData?: undefined; }) => import("./useQuery-CPqkvEsh.js").UseQueryReturnType +>useQuery : (options: { retry?: (number | boolean | ((failureCount: number, error: TError) => boolean)) | undefined; queryFn?: ((context: { queryKey: TQueryKey; }) => TQueryFnData | Promise) | undefined; queryKey?: TQueryKey | undefined; initialData?: TQueryFnData | undefined; initialDataUpdatedAt?: number | (() => number | undefined) | undefined; enabled?: boolean | undefined; refetchInterval?: number | undefined; select?: ((data: TQueryFnData) => TData) | undefined; } & { initialData?: undefined; }) => import("./useQuery-CPqkvEsh.js").UseQueryReturnType === src/index.mts === import { useQuery } from '@tanstack/vue-query' ->useQuery : (options: { retry?: (number | boolean | ((failureCount: number, error: TError) => boolean)) | undefined; queryFn?: ((context: { queryKey: TQueryKey; }) => TQueryFnData | Promise) | undefined; queryKey?: TQueryKey | undefined; initialData?: TQueryFnData | undefined; initialDataUpdatedAt?: number | (() => number | undefined); enabled?: boolean; refetchInterval?: number; select?: ((data: TQueryFnData) => TData) | undefined; } & { initialData?: undefined; }) => import("@tanstack/vue-query").UseQueryReturnType +>useQuery : (options: { retry?: (number | boolean | ((failureCount: number, error: TError) => boolean)) | undefined; queryFn?: ((context: { queryKey: TQueryKey; }) => TQueryFnData | Promise) | undefined; queryKey?: TQueryKey | undefined; initialData?: TQueryFnData | undefined; initialDataUpdatedAt?: number | (() => number | undefined) | undefined; enabled?: boolean | undefined; refetchInterval?: number | undefined; select?: ((data: TQueryFnData) => TData) | undefined; } & { initialData?: undefined; }) => import("@tanstack/vue-query").UseQueryReturnType const baseUrl = 'https://api.publicapis.org/' >baseUrl : "https://api.publicapis.org/" @@ -412,7 +412,7 @@ export const useEntries = () => { return useQuery({ >useQuery({ queryKey: entryKeys.list(), queryFn: testApi.getEntries, select: (data) => data.slice(0, 10) }) : import("@tanstack/vue-query").UseQueryReturnType ->useQuery : (options: { retry?: (number | boolean | ((failureCount: number, error: TError) => boolean)) | undefined; queryFn?: ((context: { queryKey: TQueryKey; }) => TQueryFnData | Promise) | undefined; queryKey?: TQueryKey | undefined; initialData?: TQueryFnData | undefined; initialDataUpdatedAt?: number | (() => number | undefined); enabled?: boolean; refetchInterval?: number; select?: ((data: TQueryFnData) => TData) | undefined; } & { initialData?: undefined; }) => import("@tanstack/vue-query").UseQueryReturnType +>useQuery : (options: { retry?: (number | boolean | ((failureCount: number, error: TError) => boolean)) | undefined; queryFn?: ((context: { queryKey: TQueryKey; }) => TQueryFnData | Promise) | undefined; queryKey?: TQueryKey | undefined; initialData?: TQueryFnData | undefined; initialDataUpdatedAt?: number | (() => number | undefined) | undefined; enabled?: boolean | undefined; refetchInterval?: number | undefined; select?: ((data: TQueryFnData) => TData) | undefined; } & { initialData?: undefined; }) => import("@tanstack/vue-query").UseQueryReturnType >{ queryKey: entryKeys.list(), queryFn: testApi.getEntries, select: (data) => data.slice(0, 10) } : { queryKey: readonly ["entries", "list"]; queryFn: () => Promise; select: (data: IEntry[]) => IEntry[]; } queryKey: entryKeys.list(), diff --git a/tsc/testdata/baselines/reference/compiler/declarationEmitUsingAlternativeContainingModules2.types b/tsc/testdata/baselines/reference/compiler/declarationEmitUsingAlternativeContainingModules2.types index 71598939a38cb..b51744c610eaa 100644 --- a/tsc/testdata/baselines/reference/compiler/declarationEmitUsingAlternativeContainingModules2.types +++ b/tsc/testdata/baselines/reference/compiler/declarationEmitUsingAlternativeContainingModules2.types @@ -304,12 +304,12 @@ export { type UseQueryReturnType as b, useQuery as u }; export { b as UseQueryReturnType, u as useQuery } from './useQuery-CPqkvEsh.js'; >b : any >UseQueryReturnType : any ->u : (options: { retry?: (number | boolean | ((failureCount: number, error: TError) => boolean)) | undefined; queryFn?: ((context: { queryKey: TQueryKey; }) => TQueryFnData | Promise) | undefined; queryKey?: TQueryKey | undefined; initialData?: TQueryFnData | undefined; initialDataUpdatedAt?: number | (() => number | undefined); enabled?: boolean; refetchInterval?: number; select?: ((data: TQueryFnData) => TData) | undefined; } & { initialData?: undefined; }) => import("./useQuery-CPqkvEsh.js").b ->useQuery : (options: { retry?: (number | boolean | ((failureCount: number, error: TError) => boolean)) | undefined; queryFn?: ((context: { queryKey: TQueryKey; }) => TQueryFnData | Promise) | undefined; queryKey?: TQueryKey | undefined; initialData?: TQueryFnData | undefined; initialDataUpdatedAt?: number | (() => number | undefined); enabled?: boolean; refetchInterval?: number; select?: ((data: TQueryFnData) => TData) | undefined; } & { initialData?: undefined; }) => import("./useQuery-CPqkvEsh.js").b +>u : (options: { retry?: (number | boolean | ((failureCount: number, error: TError) => boolean)) | undefined; queryFn?: ((context: { queryKey: TQueryKey; }) => TQueryFnData | Promise) | undefined; queryKey?: TQueryKey | undefined; initialData?: TQueryFnData | undefined; initialDataUpdatedAt?: number | (() => number | undefined) | undefined; enabled?: boolean | undefined; refetchInterval?: number | undefined; select?: ((data: TQueryFnData) => TData) | undefined; } & { initialData?: undefined; }) => import("./useQuery-CPqkvEsh.js").b +>useQuery : (options: { retry?: (number | boolean | ((failureCount: number, error: TError) => boolean)) | undefined; queryFn?: ((context: { queryKey: TQueryKey; }) => TQueryFnData | Promise) | undefined; queryKey?: TQueryKey | undefined; initialData?: TQueryFnData | undefined; initialDataUpdatedAt?: number | (() => number | undefined) | undefined; enabled?: boolean | undefined; refetchInterval?: number | undefined; select?: ((data: TQueryFnData) => TData) | undefined; } & { initialData?: undefined; }) => import("./useQuery-CPqkvEsh.js").b === src/index.mts === import { useQuery } from '@tanstack/vue-query' ->useQuery : (options: { retry?: (number | boolean | ((failureCount: number, error: TError) => boolean)) | undefined; queryFn?: ((context: { queryKey: TQueryKey; }) => TQueryFnData | Promise) | undefined; queryKey?: TQueryKey | undefined; initialData?: TQueryFnData | undefined; initialDataUpdatedAt?: number | (() => number | undefined); enabled?: boolean; refetchInterval?: number; select?: ((data: TQueryFnData) => TData) | undefined; } & { initialData?: undefined; }) => import("@tanstack/vue-query").UseQueryReturnType +>useQuery : (options: { retry?: (number | boolean | ((failureCount: number, error: TError) => boolean)) | undefined; queryFn?: ((context: { queryKey: TQueryKey; }) => TQueryFnData | Promise) | undefined; queryKey?: TQueryKey | undefined; initialData?: TQueryFnData | undefined; initialDataUpdatedAt?: number | (() => number | undefined) | undefined; enabled?: boolean | undefined; refetchInterval?: number | undefined; select?: ((data: TQueryFnData) => TData) | undefined; } & { initialData?: undefined; }) => import("@tanstack/vue-query").UseQueryReturnType const baseUrl = 'https://api.publicapis.org/' >baseUrl : "https://api.publicapis.org/" @@ -416,7 +416,7 @@ export const useEntries = () => { return useQuery({ >useQuery({ queryKey: entryKeys.list(), queryFn: testApi.getEntries, select: (data) => data.slice(0, 10) }) : import("@tanstack/vue-query").UseQueryReturnType ->useQuery : (options: { retry?: (number | boolean | ((failureCount: number, error: TError) => boolean)) | undefined; queryFn?: ((context: { queryKey: TQueryKey; }) => TQueryFnData | Promise) | undefined; queryKey?: TQueryKey | undefined; initialData?: TQueryFnData | undefined; initialDataUpdatedAt?: number | (() => number | undefined); enabled?: boolean; refetchInterval?: number; select?: ((data: TQueryFnData) => TData) | undefined; } & { initialData?: undefined; }) => import("@tanstack/vue-query").UseQueryReturnType +>useQuery : (options: { retry?: (number | boolean | ((failureCount: number, error: TError) => boolean)) | undefined; queryFn?: ((context: { queryKey: TQueryKey; }) => TQueryFnData | Promise) | undefined; queryKey?: TQueryKey | undefined; initialData?: TQueryFnData | undefined; initialDataUpdatedAt?: number | (() => number | undefined) | undefined; enabled?: boolean | undefined; refetchInterval?: number | undefined; select?: ((data: TQueryFnData) => TData) | undefined; } & { initialData?: undefined; }) => import("@tanstack/vue-query").UseQueryReturnType >{ queryKey: entryKeys.list(), queryFn: testApi.getEntries, select: (data) => data.slice(0, 10) } : { queryKey: readonly ["entries", "list"]; queryFn: () => Promise; select: (data: IEntry[]) => IEntry[]; } queryKey: entryKeys.list(), diff --git a/tsc/testdata/baselines/reference/compiler/identityAndDivergentNormalizedTypes.types b/tsc/testdata/baselines/reference/compiler/identityAndDivergentNormalizedTypes.types index 19b16a9a6021b..b1cfd9b04a7a3 100644 --- a/tsc/testdata/baselines/reference/compiler/identityAndDivergentNormalizedTypes.types +++ b/tsc/testdata/baselines/reference/compiler/identityAndDivergentNormalizedTypes.types @@ -38,7 +38,7 @@ const post = ( {body, ...options}: Omit & {body: PostBody} >body : PostBody ->options : { cache?: RequestCache; credentials?: RequestCredentials; headers?: HeadersInit; integrity?: string; keepalive?: boolean; method?: string; mode?: RequestMode; priority?: RequestPriority; redirect?: RequestRedirect; referrer?: string; referrerPolicy?: ReferrerPolicy; signal?: AbortSignal | null; window?: null; } +>options : { cache?: RequestCache | undefined; credentials?: RequestCredentials | undefined; headers?: HeadersInit | undefined; integrity?: string | undefined; keepalive?: boolean | undefined; method?: string | undefined; mode?: RequestMode | undefined; priority?: RequestPriority | undefined; redirect?: RequestRedirect | undefined; referrer?: string | undefined; referrerPolicy?: ReferrerPolicy | undefined; signal?: AbortSignal | null | undefined; window?: null | undefined; } >body : PostBody ) => { diff --git a/tsc/testdata/baselines/reference/conformance/mappedTypeErrors.types b/tsc/testdata/baselines/reference/conformance/mappedTypeErrors.types index fd1533220f569..8e770368fafc2 100644 --- a/tsc/testdata/baselines/reference/conformance/mappedTypeErrors.types +++ b/tsc/testdata/baselines/reference/conformance/mappedTypeErrors.types @@ -468,7 +468,7 @@ let x2: Partial = { a: 'no' }; // Error >'no' : "no" let x3: { [P in keyof T2]: T2[P]} = { a: 'no' }; // Error ->x3 : { [x: string]: any; a?: number; } +>x3 : { [x: string]: any; a?: number | undefined; } >{ a: 'no' } : { a: string; } >a : string >'no' : "no"