{"slug": "making-my-typescript-types-15-7x-faster", "title": "Making my TypeScript types 15.7x faster", "summary": "A developer optimized TypeScript type inference in the Sury schema validation library, achieving up to 15.7x faster type extraction by reading a pre-resolved type field instead of matching the entire schema type. The fix reduced type instantiations for extracting S.Output from 7,842 to 501, and similar gains were seen across other operations. The optimization was guided by type instantiation benchmarks using @ark/attest and validated with type tests.", "body_md": "If you opened this article, you probably already agree with me: sometimes TypeScript compiles *painfully* slowly.\n\nThe same thing happened to [@_chenglou](https://x.com/_chenglou) — an amazing dev who inspires me (he worked on React, Messenger, ReasonML and ReScript, and currently Midjourney, Pretext).\n\nHe's also a user of [Sury](https://github.com/DZakh/sury) — the fastest schema validation library, which I maintain — and the author of this issue: [\"Large TS types cause type inference slowdown\"](https://github.com/DZakh/sury/issues/166).\n\nThat's... not nice. But I knew [ArkType](https://arktype.io) exists, and that people have built wild things in TS's type system (Doom included). So the slowness was clearly solvable, not fundamental. Here's the recipe I used. You can apply it to your own library.\n\nBefore we begin, here are the results. These are type-instantiation counts, measured with [ @ark/attest](https://github.com/arktypeio/arktype/tree/main/ark/attest):\n\n| Operation | Before | After | Faster |\n|---|---|---|---|\n| Define a 10-field object | 1409 | 343 | 4.1× |\n| Define a 5-field object (mixed optional) | 17916 | 10557 | 1.7× |\n| Define a 3-level nested object | 31013 | 20419 | 1.5× |\n| Define a union of 5 objects | 67580 | 53173 | 1.3× |\nExtract `S.Output` (5-field object) |\n7842 | 501 | 15.7× |\nExtract `S.Input` (5-field object) |\n6767 | 501 | 13.5× |\nExtract `S.Output` (nested object) |\n7732 | 501 | 15.4× |\nDefine + extract (10-field object) |\n9446 | 844 | 11.2× |\n| Merge + extract output | 13651 | 7039 | 1.9× |\n\nThe title comes from that **15.7×** on `S.Output`\n\n. Extraction is the operation you hit most often: every `type X = S.Output<typeof schema>`\n\nin your code pays for it.\n\nLet's begin. The recipe is three steps.\n\nIf you want to change something, you first need a way to know you didn't break it. For a library like this, that means **tests for types**:\n\n``` js\nimport { expectTypeOf } from \"vitest\";\nimport * as S from \"sury\";\n\nconst user = S.schema({ id: S.string, age: S.number });\n\n// Pin the inferred type. If it drifts, the test fails.\nexpectTypeOf<S.Output<typeof user>>().toEqualTypeOf<{\n  id: string;\n  age: number;\n}>();\n```\n\nI used to use [ ts-expect](https://github.com/TypeStrong/ts-expect) for this, but I migrated to\n\n`expectTypeOf`\n\n, above) to drop a dependency. Either way, I already had the tests, and I'll admit they really earned their keep. A type optimization can quietly turn `{ a: string }`\n\ninto `{ a?: string }`\n\nand nothing throws. The tests are what catch that.If you want to *improve* something, you have to **measure it first**, or you can't actually tell whether you improved anything.\n\nFor this I used ** Attest** (\n\n`@ark/attest`\n\n) from the It counts the type instantiations an expression costs and pins them as a baseline:\n\n``` js\nimport { bench } from \"@ark/attest\";\nimport * as S from \"sury\";\n\nbench(\"define a user schema\", () => {\n  return S.schema({ id: S.string, age: S.number });\n}).types([230, \"instantiations\"]);\n```\n\nBonus: bake those baselines into CI, and any future regression will fail the build.\n\nThe third step was the easy one: I asked Claude to find the most impactful type-instantiation optimizations.\n\nThe fix turned out to be small. To read a schema's type back out, `S.Output`\n\n/ `S.Input`\n\nmatched against the *entire* `Schema<…>`\n\ntype. That type is huge: a big object with several `with`\n\noverloads, intersected with a union of every schema variant. So TypeScript had to expand all of it on every extraction, and the cost grew with the schema:\n\n```\n// Before: match the whole Schema<…> shape just to read Output back out\ntype Output<T> = T extends Schema<infer Output, unknown> ? Output : never;\n```\n\nBut every Sury schema already carries a `~standard`\n\nfield (the [Standard Schema](https://standardschema.dev) marker) that holds the resolved types. So the fix is to read that one slot directly, instead of re-deriving it from the whole shape:\n\n```\n// After: match only the one field that already holds the type\ntype Output<T> = T extends { \"~standard\": { types?: { output: infer Output } } }\n  ? Output\n  : never;\n```\n\nNow extraction costs the same no matter how big the schema is. That one change is most of the 11–16× you see above.\n\nIt depends (my favorite answer). But feedback loop speed matters more and more as AI iterates on your code. If your codebase's TS compilation is slow, you can use the same approach to identify the slow parts and optimize them.\n\nOne caveat: 15.7× is the drop in type *instantiations*, not seconds. I didn't time the actual compile. But instantiations are the work `tsc`\n\ndoes while type-checking, so fewer of them is a fair proxy for what you feel in the editor. 🙂\n\nHope this was useful. Check out [Sury](https://dev.to/dzakh/welcome-sury-the-fastest-schema-with-next-gen-dx-5gl4) — the most powerful schema library in the TS ecosystem. Follow me on X at [@dzakh_dev](https://x.com/dzakh_dev), and ask your questions in the comments!", "url": "https://wpnews.pro/news/making-my-typescript-types-15-7x-faster", "canonical_source": "https://dev.to/dzakh/making-my-typescript-types-157x-faster-4gcg", "published_at": "2026-06-17 07:54:00+00:00", "updated_at": "2026-06-17 08:21:54.715131+00:00", "lang": "en", "topics": ["developer-tools", "large-language-models"], "entities": ["Sury", "ArkType", "@ark/attest", "TypeScript", "Claude", "Standard Schema", "vitest", "DZakh"], "alternates": {"html": "https://wpnews.pro/news/making-my-typescript-types-15-7x-faster", "markdown": "https://wpnews.pro/news/making-my-typescript-types-15-7x-faster.md", "text": "https://wpnews.pro/news/making-my-typescript-types-15-7x-faster.txt", "jsonld": "https://wpnews.pro/news/making-my-typescript-types-15-7x-faster.jsonld"}}