From 7852ab1fdb45ca0f035a57625a11861ae21c8b05 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Sun, 18 Oct 2026 03:26:13 -0700 Subject: [PATCH 1/2] Don't resolve mapped type members to find their signatures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mapped types never have call or construct signatures, but asking for their signatures resolved all of their properties. Signature checks in relations ask for them first, so every mapped type that reached a relation had its properties built, even when nothing else needed them. In MUI, components accept Partial<...> of each intrinsic element's props, so this built hundreds of properties for each of thousands of such types, and their combined base properties too. Measured with --checkers 4 (n=6): │ old.txt │ new.txt │ │ sec/op │ sec/op vs base │ Tsc/bluesky 2.459 ± 3% 2.458 ± 3% ~ (p=0.818 n=6) Tsc/sentry 10.21 ± 4% 10.27 ± 3% ~ (p=0.937 n=6) Tsc/t3code-server 8.097 ± 3% 8.085 ± 1% ~ (p=0.937 n=6) Tsc/mui-docs 6.423 ± 4% 5.902 ± 4% -8.10% (p=0.002 n=6) geomean 6.011 5.892 -1.98% │ old.txt │ new.txt │ │ rss-B │ rss-B vs base │ Tsc/bluesky 1.184Gi ± 1% 1.176Gi ± 3% ~ (p=0.699 n=6) Tsc/sentry 3.415Gi ± 5% 3.273Gi ± 5% ~ (p=0.240 n=6) Tsc/t3code-server 2.875Gi ± 6% 2.913Gi ± 8% ~ (p=0.699 n=6) Tsc/mui-docs 2.323Gi ± 7% 2.203Gi ± 5% ~ (p=0.240 n=6) geomean 2.280Gi 2.229Gi -2.21% │ old.txt │ new.txt │ │ heap-B │ heap-B vs base │ Tsc/bluesky 915.1Mi ± 0% 914.7Mi ± 0% ~ (p=0.132 n=6) Tsc/sentry 2.483Gi ± 0% 2.481Gi ± 0% ~ (p=0.065 n=6) Tsc/t3code-server 2.179Gi ± 0% 2.179Gi ± 0% ~ (p=0.589 n=6) Tsc/mui-docs 1.722Gi ± 0% 1.634Gi ± 0% -5.16% (p=0.002 n=6) geomean 1.699Gi 1.676Gi -1.35% vscode is unaffected (n=12): │ old │ new │ │ sec/op │ sec/op vs base │ Tsc/vscode 11.71 ± 1% 11.67 ± 2% ~ (p=0.899 n=12) │ old │ new │ │ rss-B │ rss-B vs base │ Tsc/vscode 4.765Gi ± 1% 4.787Gi ± 1% ~ (p=0.443 n=12) │ old │ new │ │ heap-B │ heap-B vs base │ Tsc/vscode 3.977Gi ± 0% 3.976Gi ± 0% ~ (p=1.000 n=12) --- tsc/internal/checker/checker.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index 4c57dd37910f2..e2eb80604a4c9 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -19429,7 +19429,7 @@ func (c *Checker) getSignaturesOfType(t *Type, kind SignatureKind) []*Signature } func (c *Checker) getSignaturesOfStructuredType(t *Type, kind SignatureKind) []*Signature { - if t.flags&TypeFlagsStructuredType == 0 { + if t.flags&TypeFlagsStructuredType == 0 || isUnresolvedMappedType(t) { return nil } resolved := c.resolveStructuredTypeMembers(t) @@ -19557,6 +19557,13 @@ func (c *Checker) resolveStructuredTypeMembers(t *Type) *StructuredType { return t.AsStructuredType() } +// Reports whether t is a mapped type whose members resolveMappedTypeMembers hasn't yet resolved. +// Mapped types never have signatures, so those needn't be resolved to be known. +func isUnresolvedMappedType(t *Type) bool { + return t.flags&TypeFlagsObject != 0 && + t.objectFlags&(ObjectFlagsReference|ObjectFlagsClassOrInterface|ObjectFlagsReverseMapped|ObjectFlagsAnonymous|ObjectFlagsMapped|ObjectFlagsMembersResolved) == ObjectFlagsMapped +} + func (c *Checker) resolveObjectTypeMembers(t *Type) { var mapper *TypeMapper var typeParameters []*Type From 470f122d13decb60eebb8a77e36d32a8d22cb5a8 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Fri, 23 Oct 2026 16:09:15 -0700 Subject: [PATCH 2/2] Skip signatures for all mapped types Mapped and reverse mapped types never have call or construct signatures, whether or not their members have been resolved, so the flags alone are enough to answer the question. --- tsc/internal/checker/checker.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index e2eb80604a4c9..148cf5fde47dd 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -19429,7 +19429,7 @@ func (c *Checker) getSignaturesOfType(t *Type, kind SignatureKind) []*Signature } func (c *Checker) getSignaturesOfStructuredType(t *Type, kind SignatureKind) []*Signature { - if t.flags&TypeFlagsStructuredType == 0 || isUnresolvedMappedType(t) { + if t.flags&TypeFlagsStructuredType == 0 || t.objectFlags&(ObjectFlagsMapped|ObjectFlagsReverseMapped) != 0 { return nil } resolved := c.resolveStructuredTypeMembers(t) @@ -19557,13 +19557,6 @@ func (c *Checker) resolveStructuredTypeMembers(t *Type) *StructuredType { return t.AsStructuredType() } -// Reports whether t is a mapped type whose members resolveMappedTypeMembers hasn't yet resolved. -// Mapped types never have signatures, so those needn't be resolved to be known. -func isUnresolvedMappedType(t *Type) bool { - return t.flags&TypeFlagsObject != 0 && - t.objectFlags&(ObjectFlagsReference|ObjectFlagsClassOrInterface|ObjectFlagsReverseMapped|ObjectFlagsAnonymous|ObjectFlagsMapped|ObjectFlagsMembersResolved) == ObjectFlagsMapped -} - func (c *Checker) resolveObjectTypeMembers(t *Type) { var mapper *TypeMapper var typeParameters []*Type