@biggora/claude-plugins 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -4
- package/package.json +1 -1
- package/registry/registry.json +334 -244
- package/specs/coding.md +30 -0
- package/specs/pod.md +2 -0
- package/src/commands/skills/add.js +63 -7
- package/src/commands/skills/list.js +23 -52
- package/src/commands/skills/remove.js +26 -27
- package/src/commands/skills/resolve.js +155 -0
- package/src/commands/skills/update.js +58 -74
- package/src/skills/captcha/README.md +221 -0
- package/src/skills/captcha/SKILL.md +355 -0
- package/src/skills/captcha/references/captcha-types.md +254 -0
- package/src/skills/captcha/references/services.md +172 -0
- package/src/skills/captcha/references/stealth.md +238 -0
- package/src/skills/captcha/scripts/solve_captcha.py +323 -0
- package/src/skills/captcha/scripts/solve_image_grid.py +350 -0
- package/src/skills/google-merchant-api/SKILL.md +581 -0
- package/src/skills/google-merchant-api/references/accounts.md +247 -0
- package/src/skills/google-merchant-api/references/content-api-legacy.md +216 -0
- package/src/skills/google-merchant-api/references/datasources.md +233 -0
- package/src/skills/google-merchant-api/references/inventories.md +201 -0
- package/src/skills/google-merchant-api/references/migration.md +267 -0
- package/src/skills/google-merchant-api/references/products.md +316 -0
- package/src/skills/google-merchant-api/references/promotions.md +201 -0
- package/src/skills/google-merchant-api/references/reports.md +240 -0
- package/src/skills/lv-aggregators-api/SKILL.md +113 -0
- package/src/skills/lv-aggregators-api/references/integration-guide.md +368 -0
- package/src/skills/lv-aggregators-api/references/kurpirkt.md +103 -0
- package/src/skills/lv-aggregators-api/references/salidzini.md +122 -0
- package/src/skills/nest-best-practices/SKILL.md +251 -0
- package/src/skills/nest-best-practices/references/best-practices-request-lifecycle.md +158 -0
- package/src/skills/nest-best-practices/references/cli-monorepo.md +106 -0
- package/src/skills/nest-best-practices/references/cli-overview.md +157 -0
- package/src/skills/nest-best-practices/references/core-controllers.md +165 -0
- package/src/skills/nest-best-practices/references/core-dependency-injection.md +179 -0
- package/src/skills/nest-best-practices/references/core-middleware.md +139 -0
- package/src/skills/nest-best-practices/references/core-modules.md +138 -0
- package/src/skills/nest-best-practices/references/core-providers.md +188 -0
- package/src/skills/nest-best-practices/references/faq-raw-body-hybrid.md +122 -0
- package/src/skills/nest-best-practices/references/fundamentals-circular-dependency.md +89 -0
- package/src/skills/nest-best-practices/references/fundamentals-custom-decorators.md +107 -0
- package/src/skills/nest-best-practices/references/fundamentals-dynamic-modules.md +125 -0
- package/src/skills/nest-best-practices/references/fundamentals-exception-filters.md +202 -0
- package/src/skills/nest-best-practices/references/fundamentals-execution-context.md +107 -0
- package/src/skills/nest-best-practices/references/fundamentals-guards.md +136 -0
- package/src/skills/nest-best-practices/references/fundamentals-interceptors.md +187 -0
- package/src/skills/nest-best-practices/references/fundamentals-lazy-loading.md +89 -0
- package/src/skills/nest-best-practices/references/fundamentals-lifecycle-events.md +87 -0
- package/src/skills/nest-best-practices/references/fundamentals-module-reference.md +107 -0
- package/src/skills/nest-best-practices/references/fundamentals-pipes.md +197 -0
- package/src/skills/nest-best-practices/references/fundamentals-provider-scopes.md +92 -0
- package/src/skills/nest-best-practices/references/fundamentals-testing.md +142 -0
- package/src/skills/nest-best-practices/references/graphql-overview.md +233 -0
- package/src/skills/nest-best-practices/references/graphql-resolvers-mutations.md +199 -0
- package/src/skills/nest-best-practices/references/graphql-scalars-unions-enums.md +180 -0
- package/src/skills/nest-best-practices/references/graphql-subscriptions.md +228 -0
- package/src/skills/nest-best-practices/references/microservices-grpc.md +175 -0
- package/src/skills/nest-best-practices/references/microservices-overview.md +221 -0
- package/src/skills/nest-best-practices/references/microservices-transports.md +119 -0
- package/src/skills/nest-best-practices/references/openapi-swagger.md +207 -0
- package/src/skills/nest-best-practices/references/recipes-authentication.md +97 -0
- package/src/skills/nest-best-practices/references/recipes-cqrs.md +176 -0
- package/src/skills/nest-best-practices/references/recipes-crud-generator.md +87 -0
- package/src/skills/nest-best-practices/references/recipes-documentation.md +93 -0
- package/src/skills/nest-best-practices/references/recipes-mongoose.md +153 -0
- package/src/skills/nest-best-practices/references/recipes-prisma.md +98 -0
- package/src/skills/nest-best-practices/references/recipes-terminus.md +148 -0
- package/src/skills/nest-best-practices/references/recipes-typeorm.md +122 -0
- package/src/skills/nest-best-practices/references/security-authorization.md +196 -0
- package/src/skills/nest-best-practices/references/security-cors-helmet-rate-limiting.md +204 -0
- package/src/skills/nest-best-practices/references/security-encryption-hashing.md +93 -0
- package/src/skills/nest-best-practices/references/techniques-caching.md +142 -0
- package/src/skills/nest-best-practices/references/techniques-compression-streaming-sse.md +194 -0
- package/src/skills/nest-best-practices/references/techniques-configuration.md +132 -0
- package/src/skills/nest-best-practices/references/techniques-database.md +153 -0
- package/src/skills/nest-best-practices/references/techniques-events.md +163 -0
- package/src/skills/nest-best-practices/references/techniques-fastify.md +137 -0
- package/src/skills/nest-best-practices/references/techniques-file-upload.md +140 -0
- package/src/skills/nest-best-practices/references/techniques-http-module.md +176 -0
- package/src/skills/nest-best-practices/references/techniques-logging.md +146 -0
- package/src/skills/nest-best-practices/references/techniques-mvc-serve-static.md +132 -0
- package/src/skills/nest-best-practices/references/techniques-queues.md +162 -0
- package/src/skills/nest-best-practices/references/techniques-serialization.md +158 -0
- package/src/skills/nest-best-practices/references/techniques-sessions-cookies.md +167 -0
- package/src/skills/nest-best-practices/references/techniques-task-scheduling.md +166 -0
- package/src/skills/nest-best-practices/references/techniques-validation.md +126 -0
- package/src/skills/nest-best-practices/references/techniques-versioning.md +153 -0
- package/src/skills/nest-best-practices/references/websockets-advanced.md +96 -0
- package/src/skills/nest-best-practices/references/websockets-gateways.md +215 -0
- package/src/skills/tailwindcss-best-practices/SKILL.md +180 -0
- package/src/skills/tailwindcss-best-practices/references/best-practices-utility-patterns.md +87 -0
- package/src/skills/tailwindcss-best-practices/references/core-installation.md +109 -0
- package/src/skills/tailwindcss-best-practices/references/core-preflight.md +200 -0
- package/src/skills/tailwindcss-best-practices/references/core-responsive.md +163 -0
- package/src/skills/tailwindcss-best-practices/references/core-source-detection.md +114 -0
- package/src/skills/tailwindcss-best-practices/references/core-theme.md +108 -0
- package/src/skills/tailwindcss-best-practices/references/core-utility-classes.md +59 -0
- package/src/skills/tailwindcss-best-practices/references/core-variants.md +204 -0
- package/src/skills/tailwindcss-best-practices/references/effects-form-controls.md +76 -0
- package/src/skills/tailwindcss-best-practices/references/effects-mask.md +91 -0
- package/src/skills/tailwindcss-best-practices/references/effects-scroll-snap.md +59 -0
- package/src/skills/tailwindcss-best-practices/references/effects-text-shadow.md +78 -0
- package/src/skills/tailwindcss-best-practices/references/effects-transition-animation.md +80 -0
- package/src/skills/tailwindcss-best-practices/references/effects-visibility-interactivity.md +82 -0
- package/src/skills/tailwindcss-best-practices/references/features-content-detection.md +175 -0
- package/src/skills/tailwindcss-best-practices/references/features-custom-styles.md +203 -0
- package/src/skills/tailwindcss-best-practices/references/features-dark-mode.md +137 -0
- package/src/skills/tailwindcss-best-practices/references/features-functions-directives.md +241 -0
- package/src/skills/tailwindcss-best-practices/references/features-upgrade.md +160 -0
- package/src/skills/tailwindcss-best-practices/references/layout-aspect-ratio.md +39 -0
- package/src/skills/tailwindcss-best-practices/references/layout-columns.md +80 -0
- package/src/skills/tailwindcss-best-practices/references/layout-display.md +110 -0
- package/src/skills/tailwindcss-best-practices/references/layout-flexbox.md +112 -0
- package/src/skills/tailwindcss-best-practices/references/layout-grid.md +87 -0
- package/src/skills/tailwindcss-best-practices/references/layout-height.md +97 -0
- package/src/skills/tailwindcss-best-practices/references/layout-inset.md +103 -0
- package/src/skills/tailwindcss-best-practices/references/layout-logical-properties.md +92 -0
- package/src/skills/tailwindcss-best-practices/references/layout-margin.md +126 -0
- package/src/skills/tailwindcss-best-practices/references/layout-min-max-sizing.md +63 -0
- package/src/skills/tailwindcss-best-practices/references/layout-object-fit-position.md +64 -0
- package/src/skills/tailwindcss-best-practices/references/layout-overflow.md +57 -0
- package/src/skills/tailwindcss-best-practices/references/layout-padding.md +77 -0
- package/src/skills/tailwindcss-best-practices/references/layout-position.md +85 -0
- package/src/skills/tailwindcss-best-practices/references/layout-tables.md +67 -0
- package/src/skills/tailwindcss-best-practices/references/layout-width.md +102 -0
- package/src/skills/tailwindcss-best-practices/references/transform-base.md +68 -0
- package/src/skills/tailwindcss-best-practices/references/transform-rotate.md +70 -0
- package/src/skills/tailwindcss-best-practices/references/transform-scale.md +83 -0
- package/src/skills/tailwindcss-best-practices/references/transform-skew.md +62 -0
- package/src/skills/tailwindcss-best-practices/references/transform-translate.md +77 -0
- package/src/skills/tailwindcss-best-practices/references/typography-font-text.md +142 -0
- package/src/skills/tailwindcss-best-practices/references/typography-list-style.md +65 -0
- package/src/skills/tailwindcss-best-practices/references/typography-text-align.md +60 -0
- package/src/skills/tailwindcss-best-practices/references/visual-background.md +76 -0
- package/src/skills/tailwindcss-best-practices/references/visual-border.md +108 -0
- package/src/skills/tailwindcss-best-practices/references/visual-effects.md +111 -0
- package/src/skills/tailwindcss-best-practices/references/visual-svg.md +82 -0
- package/src/skills/test-mobile-app/SKILL.md +11 -6
- package/src/skills/test-mobile-app/scripts/analyze_apk.py +15 -4
- package/src/skills/test-mobile-app/scripts/check_environment.py +5 -5
- package/src/skills/test-mobile-app/scripts/run_tests.py +1 -1
- package/src/skills/test-web-ui/SKILL.md +264 -84
- package/src/skills/test-web-ui/scripts/discover.py +25 -12
- package/src/skills/test-web-ui/scripts/run_tests.py +3 -2
- package/src/skills/typescript-expert/SKILL.md +145 -0
- package/src/skills/typescript-expert/commands/typescript-fix.md +65 -0
- package/src/skills/typescript-expert/references/advanced-conditional-types.md +190 -0
- package/src/skills/typescript-expert/references/advanced-decorators.md +243 -0
- package/src/skills/typescript-expert/references/advanced-mapped-types.md +223 -0
- package/src/skills/typescript-expert/references/advanced-template-literals.md +209 -0
- package/src/skills/typescript-expert/references/advanced-type-guards.md +308 -0
- package/src/skills/typescript-expert/references/best-practices-patterns.md +313 -0
- package/src/skills/typescript-expert/references/best-practices-performance.md +185 -0
- package/src/skills/typescript-expert/references/best-practices-tsconfig.md +242 -0
- package/src/skills/typescript-expert/references/core-generics.md +246 -0
- package/src/skills/typescript-expert/references/core-interfaces-types.md +231 -0
- package/src/skills/typescript-expert/references/core-type-system.md +261 -0
- package/src/skills/typescript-expert/references/core-utility-types.md +235 -0
- package/src/skills/typescript-expert/references/features-ts5x.md +370 -0
- package/src/skills/vite-best-practices/SKILL.md +115 -0
- package/src/skills/vite-best-practices/references/build-and-ssr.md +255 -0
- package/src/skills/vite-best-practices/references/core-config.md +231 -0
- package/src/skills/vite-best-practices/references/core-features.md +222 -0
- package/src/skills/vite-best-practices/references/core-plugin-api.md +294 -0
- package/src/skills/vite-best-practices/references/environment-api.md +108 -0
- package/src/skills/vite-best-practices/references/rolldown-migration.md +242 -0
- package/codex-cli-workspace/iteration-1/benchmark.json +0 -122
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/eval_metadata.json +0 -13
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/with_skill/grading.json +0 -52
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/with_skill/outputs/response.md +0 -163
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/with_skill/timing.json +0 -5
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/without_skill/grading.json +0 -58
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/without_skill/outputs/response.md +0 -151
- package/codex-cli-workspace/iteration-1/eval-1-ci-integration/without_skill/timing.json +0 -5
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/eval_metadata.json +0 -13
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/grading.json +0 -52
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/outputs/response.md +0 -86
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/timing.json +0 -5
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/grading.json +0 -58
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/outputs/response.md +0 -164
- package/codex-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/timing.json +0 -5
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/eval_metadata.json +0 -13
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/with_skill/grading.json +0 -52
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/with_skill/outputs/response.md +0 -130
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/with_skill/timing.json +0 -5
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/without_skill/grading.json +0 -64
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/without_skill/outputs/response.md +0 -209
- package/codex-cli-workspace/iteration-1/eval-3-profiles-troubleshooting/without_skill/timing.json +0 -5
- package/codex-cli-workspace/iteration-1/review.html +0 -1325
- package/gemini-cli-workspace/iteration-1/benchmark.json +0 -86
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/eval_metadata.json +0 -37
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/with_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/with_skill/outputs/response.md +0 -401
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/with_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/without_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/without_skill/outputs/response.md +0 -405
- package/gemini-cli-workspace/iteration-1/eval-1-cicd-setup/without_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/eval_metadata.json +0 -37
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/outputs/response.md +0 -212
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/with_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/outputs/response.md +0 -427
- package/gemini-cli-workspace/iteration-1/eval-2-mcp-server-config/without_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/eval_metadata.json +0 -32
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/with_skill/grading.json +0 -32
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/with_skill/outputs/response.md +0 -171
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/with_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/without_skill/grading.json +0 -32
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/without_skill/outputs/response.md +0 -199
- package/gemini-cli-workspace/iteration-1/eval-3-custom-slash-command/without_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-1/review.html +0 -1325
- package/gemini-cli-workspace/iteration-2/benchmark.json +0 -173
- package/gemini-cli-workspace/iteration-2/benchmark.md +0 -28
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/eval_metadata.json +0 -37
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/with_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/with_skill/outputs/response.md +0 -195
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/with_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/without_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/without_skill/outputs/response.md +0 -377
- package/gemini-cli-workspace/iteration-2/eval-1-cicd-setup/without_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/eval_metadata.json +0 -37
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/with_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/with_skill/outputs/response.md +0 -127
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/with_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/without_skill/grading.json +0 -37
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/without_skill/outputs/response.md +0 -164
- package/gemini-cli-workspace/iteration-2/eval-2-mcp-server-config/without_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/eval_metadata.json +0 -32
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/with_skill/grading.json +0 -32
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/with_skill/outputs/response.md +0 -91
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/with_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/without_skill/grading.json +0 -32
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/without_skill/outputs/response.md +0 -112
- package/gemini-cli-workspace/iteration-2/eval-3-custom-slash-command/without_skill/timing.json +0 -5
- package/gemini-cli-workspace/iteration-2/eval-viewer.html +0 -1325
- package/screen-recording-workspace/evals.json +0 -41
- package/screen-recording-workspace/iteration-1/benchmark.json +0 -102
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/eval_metadata.json +0 -31
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/with_skill/grading.json +0 -11
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/with_skill/outputs/demo.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/with_skill/timing.json +0 -5
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/without_skill/grading.json +0 -11
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/without_skill/outputs/demo.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-0-fullscreen/without_skill/timing.json +0 -5
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/eval_metadata.json +0 -31
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/with_skill/grading.json +0 -11
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/with_skill/outputs/region_capture.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/with_skill/timing.json +0 -5
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/without_skill/grading.json +0 -11
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/without_skill/outputs/region_capture.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-1-region-audio/without_skill/timing.json +0 -5
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/eval_metadata.json +0 -31
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/with_skill/grading.json +0 -11
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/with_skill/outputs/fallback_recording.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/with_skill/timing.json +0 -5
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/without_skill/grading.json +0 -11
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/without_skill/outputs/fallback_recording.mp4 +0 -0
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/without_skill/outputs/record_screen.py +0 -67
- package/screen-recording-workspace/iteration-1/eval-2-python-fallback/without_skill/timing.json +0 -5
- package/screen-recording-workspace/iteration-1/review.html +0 -1325
- package/src/skills/codex-cli/evals/evals.json +0 -47
- package/src/skills/gemini-cli/evals/evals.json +0 -46
- package/src/skills/tm-search/evals/evals.json +0 -23
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# Type-Level Performance
|
|
2
|
+
|
|
3
|
+
When TypeScript becomes slow, it's usually because complex types cause the compiler to do excessive work. This guide covers how to diagnose and fix type-level performance issues.
|
|
4
|
+
|
|
5
|
+
## Diagnosing Slow Types
|
|
6
|
+
|
|
7
|
+
### Compiler Flags for Profiling
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Generate a trace for analysis
|
|
11
|
+
tsc --generateTrace ./trace-output
|
|
12
|
+
|
|
13
|
+
# Show time spent on each file
|
|
14
|
+
tsc --extendedDiagnostics
|
|
15
|
+
|
|
16
|
+
# Show which types are being checked
|
|
17
|
+
tsc --listFiles
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The trace output can be loaded in Chrome DevTools (Performance tab) or `@typescript/analyze-trace`:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx @typescript/analyze-trace ./trace-output
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Common Symptoms
|
|
27
|
+
|
|
28
|
+
- IDE autocompletion is slow or laggy
|
|
29
|
+
- `tsc` takes significantly longer than expected
|
|
30
|
+
- Hover types show `...` (type too complex to display)
|
|
31
|
+
- "Type instantiation is excessively deep" errors
|
|
32
|
+
|
|
33
|
+
## Rules for Fast Types
|
|
34
|
+
|
|
35
|
+
### 1. Prefer Interfaces Over Intersections
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
// Slower — creates anonymous intersection each time
|
|
39
|
+
type User = BaseEntity & { name: string; email: string };
|
|
40
|
+
|
|
41
|
+
// Faster — interfaces are cached by name
|
|
42
|
+
interface User extends BaseEntity {
|
|
43
|
+
name: string;
|
|
44
|
+
email: string;
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Interfaces are cached by identity. Intersections create new anonymous types on every use.
|
|
49
|
+
|
|
50
|
+
### 2. Limit Union Size
|
|
51
|
+
|
|
52
|
+
Unions beyond ~25-50 members start impacting performance. Large unions from template literals are a common cause:
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// This creates a union of 10,000 members — very slow
|
|
56
|
+
type Color = `#${HexDigit}${HexDigit}${HexDigit}${HexDigit}${HexDigit}${HexDigit}`;
|
|
57
|
+
|
|
58
|
+
// Better: use a branded string
|
|
59
|
+
type Color = string & { readonly __brand: "Color" };
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 3. Avoid Deep Recursive Types
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
// Slow — recursion depth grows with path length
|
|
66
|
+
type DeepGet<T, Path extends string> =
|
|
67
|
+
Path extends `${infer Head}.${infer Tail}`
|
|
68
|
+
? Head extends keyof T
|
|
69
|
+
? DeepGet<T[Head], Tail>
|
|
70
|
+
: never
|
|
71
|
+
: Path extends keyof T
|
|
72
|
+
? T[Path]
|
|
73
|
+
: never;
|
|
74
|
+
|
|
75
|
+
// If this is slow, consider:
|
|
76
|
+
// 1. Limiting recursion depth with a counter
|
|
77
|
+
// 2. Using a simpler type and casting at the boundary
|
|
78
|
+
// 3. Moving the logic to runtime validation
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Tail-Call Optimization for Recursive Types
|
|
82
|
+
|
|
83
|
+
TypeScript optimizes tail-position conditional types. Structure recursion to be tail-recursive:
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
// Not tail-recursive — wraps result before returning
|
|
87
|
+
type BadReverse<T extends any[]> =
|
|
88
|
+
T extends [infer Head, ...infer Tail]
|
|
89
|
+
? [...BadReverse<Tail>, Head]
|
|
90
|
+
: [];
|
|
91
|
+
|
|
92
|
+
// Tail-recursive — accumulator pattern
|
|
93
|
+
type Reverse<T extends any[], Acc extends any[] = []> =
|
|
94
|
+
T extends [infer Head, ...infer Tail]
|
|
95
|
+
? Reverse<Tail, [Head, ...Acc]>
|
|
96
|
+
: Acc;
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 4. Use `skipLibCheck: true`
|
|
100
|
+
|
|
101
|
+
Skip type-checking `.d.ts` files from `node_modules`. This dramatically speeds up compilation:
|
|
102
|
+
|
|
103
|
+
```jsonc
|
|
104
|
+
{
|
|
105
|
+
"compilerOptions": {
|
|
106
|
+
"skipLibCheck": true
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 5. Use Project References for Monorepos
|
|
112
|
+
|
|
113
|
+
Break large codebases into smaller projects with `composite` and project references. This enables incremental compilation:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
tsc --build --incremental
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### 6. Avoid Conditional Types in Hot Paths
|
|
120
|
+
|
|
121
|
+
Conditional types that TypeScript can't resolve eagerly (because they involve generic parameters) stay deferred and get re-evaluated at every use site:
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
// This stays deferred inside generic functions — expensive
|
|
125
|
+
function process<T>(value: T): T extends string ? number : boolean {
|
|
126
|
+
// ...
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Better: use overloads for finite cases
|
|
130
|
+
function process(value: string): number;
|
|
131
|
+
function process(value: number): boolean;
|
|
132
|
+
function process(value: string | number): number | boolean {
|
|
133
|
+
// ...
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 7. Simplify Mapped Types
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
// Slow — maps, remaps, and conditionally transforms every key
|
|
141
|
+
type Complex<T> = {
|
|
142
|
+
[K in keyof T as T[K] extends Function
|
|
143
|
+
? `handle${Capitalize<string & K>}`
|
|
144
|
+
: K
|
|
145
|
+
]: T[K] extends Function
|
|
146
|
+
? (...args: Parameters<T[K]>) => Promise<ReturnType<T[K]>>
|
|
147
|
+
: Readonly<T[K]>;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// Faster — split into smaller, composable types
|
|
151
|
+
type Methods<T> = {
|
|
152
|
+
[K in keyof T as T[K] extends Function ? K : never]: T[K];
|
|
153
|
+
};
|
|
154
|
+
type Data<T> = {
|
|
155
|
+
[K in keyof T as T[K] extends Function ? never : K]: Readonly<T[K]>;
|
|
156
|
+
};
|
|
157
|
+
type AsyncMethods<T> = {
|
|
158
|
+
[K in keyof T]: T[K] extends (...args: infer A) => infer R
|
|
159
|
+
? (...args: A) => Promise<R>
|
|
160
|
+
: never;
|
|
161
|
+
};
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## When to Give Up on Types
|
|
165
|
+
|
|
166
|
+
Sometimes the cost of perfect types outweighs the benefit:
|
|
167
|
+
|
|
168
|
+
1. **Cast at the boundary**: Type complex external data at the edges and trust it internally
|
|
169
|
+
2. **Use `as` strategically**: A well-placed assertion is better than a deep recursive type
|
|
170
|
+
3. **Simplify to branded strings/numbers**: When template literal types create too many members
|
|
171
|
+
4. **Use `// @ts-expect-error`**: For known type system limitations (with a comment explaining why)
|
|
172
|
+
|
|
173
|
+
The goal is to catch real bugs, not to prove theorems. If a type takes 500ms to check and catches a bug once a year, simplify it.
|
|
174
|
+
|
|
175
|
+
## Quick Performance Checklist
|
|
176
|
+
|
|
177
|
+
- [ ] `strict: true` (catches bugs without complex types)
|
|
178
|
+
- [ ] `skipLibCheck: true` (skip `.d.ts` checking)
|
|
179
|
+
- [ ] `incremental: true` (cache between builds)
|
|
180
|
+
- [ ] Interfaces over intersections for object types
|
|
181
|
+
- [ ] Union types under ~50 members
|
|
182
|
+
- [ ] Recursive types use accumulator pattern
|
|
183
|
+
- [ ] No deeply nested conditional types in generic functions
|
|
184
|
+
- [ ] Project references for monorepos
|
|
185
|
+
- [ ] `--generateTrace` if still slow — find the hotspot
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
# tsconfig.json Configuration
|
|
2
|
+
|
|
3
|
+
## Recommended Base Configuration
|
|
4
|
+
|
|
5
|
+
```jsonc
|
|
6
|
+
{
|
|
7
|
+
"compilerOptions": {
|
|
8
|
+
// Type Checking — always enable strict
|
|
9
|
+
"strict": true,
|
|
10
|
+
"noUncheckedIndexedAccess": true,
|
|
11
|
+
"noFallthroughCasesInSwitch": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
|
|
14
|
+
// Modules
|
|
15
|
+
"module": "ESNext",
|
|
16
|
+
"moduleResolution": "bundler",
|
|
17
|
+
"resolveJsonModule": true,
|
|
18
|
+
"isolatedModules": true,
|
|
19
|
+
"verbatimModuleSyntax": true,
|
|
20
|
+
|
|
21
|
+
// Emit
|
|
22
|
+
"target": "ES2022",
|
|
23
|
+
"declaration": true,
|
|
24
|
+
"declarationMap": true,
|
|
25
|
+
"sourceMap": true,
|
|
26
|
+
"outDir": "./dist",
|
|
27
|
+
|
|
28
|
+
// Interop
|
|
29
|
+
"esModuleInterop": true,
|
|
30
|
+
"allowSyntheticDefaultImports": true,
|
|
31
|
+
"skipLibCheck": true
|
|
32
|
+
},
|
|
33
|
+
"include": ["src"],
|
|
34
|
+
"exclude": ["node_modules", "dist"]
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## What `strict` Enables
|
|
39
|
+
|
|
40
|
+
`"strict": true` is a shorthand for all of these:
|
|
41
|
+
|
|
42
|
+
| Flag | What it does | Why it matters |
|
|
43
|
+
|------|-------------|----------------|
|
|
44
|
+
| `strictNullChecks` | `null`/`undefined` not assignable to other types | Prevents null reference errors |
|
|
45
|
+
| `noImplicitAny` | Error on inferred `any` | Prevents silent type safety holes |
|
|
46
|
+
| `strictFunctionTypes` | Strict function parameter checking | Catches unsound function assignments |
|
|
47
|
+
| `strictBindCallApply` | Type-check `bind`, `call`, `apply` | Prevents runtime argument mismatches |
|
|
48
|
+
| `strictPropertyInitialization` | Class properties must be initialized | Prevents undefined property access |
|
|
49
|
+
| `noImplicitThis` | Error on `this` with implicit `any` type | Prevents `this` context bugs |
|
|
50
|
+
| `alwaysStrict` | Emits `"use strict"` | JavaScript strict mode |
|
|
51
|
+
| `useUnknownInCatchVariables` | `catch(e)` gives `e: unknown` not `any` | Forces error type checking |
|
|
52
|
+
| `exactOptionalPropertyTypes` | `?:` means "may be missing", not "may be undefined" | More precise optional semantics |
|
|
53
|
+
|
|
54
|
+
## Module Resolution Strategies
|
|
55
|
+
|
|
56
|
+
### `"moduleResolution": "bundler"` (Recommended for apps)
|
|
57
|
+
|
|
58
|
+
Use when a bundler (Vite, webpack, esbuild, Turbopack) handles module resolution. Supports:
|
|
59
|
+
- Extensionless imports (`import "./utils"` resolves to `./utils.ts`)
|
|
60
|
+
- `package.json` `exports` field
|
|
61
|
+
- Conditional `imports`
|
|
62
|
+
|
|
63
|
+
### `"moduleResolution": "node16"` / `"nodenext"` (For libraries/Node.js)
|
|
64
|
+
|
|
65
|
+
Use when targeting Node.js directly or publishing a library. Requires:
|
|
66
|
+
- File extensions in relative imports (`import "./utils.js"`)
|
|
67
|
+
- `.mts`/`.cts` for ESM/CJS files
|
|
68
|
+
- Correct `package.json` `type` and `exports`
|
|
69
|
+
|
|
70
|
+
### `"moduleResolution": "node"` (Legacy)
|
|
71
|
+
|
|
72
|
+
The old Node.js resolution. Doesn't understand `exports` or conditional imports. Avoid for new projects.
|
|
73
|
+
|
|
74
|
+
## `verbatimModuleSyntax` (TS 5.0+)
|
|
75
|
+
|
|
76
|
+
Replaces the older `importsNotUsedAsValues` and `preserveValueImports`. Forces you to be explicit about type-only imports:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
// With verbatimModuleSyntax: true
|
|
80
|
+
import type { User } from "./types"; // Erased at runtime
|
|
81
|
+
import { processUser } from "./utils"; // Kept at runtime
|
|
82
|
+
|
|
83
|
+
// Mixed import — type and value from same module
|
|
84
|
+
import { type User, processUser } from "./module";
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
This prevents accidentally including type-only imports in your runtime bundle.
|
|
88
|
+
|
|
89
|
+
## Common Configurations by Project Type
|
|
90
|
+
|
|
91
|
+
### Next.js App
|
|
92
|
+
|
|
93
|
+
```jsonc
|
|
94
|
+
{
|
|
95
|
+
"compilerOptions": {
|
|
96
|
+
"target": "ES2017",
|
|
97
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
98
|
+
"module": "ESNext",
|
|
99
|
+
"moduleResolution": "bundler",
|
|
100
|
+
"jsx": "preserve",
|
|
101
|
+
"strict": true,
|
|
102
|
+
"noEmit": true,
|
|
103
|
+
"incremental": true,
|
|
104
|
+
"plugins": [{ "name": "next" }],
|
|
105
|
+
"paths": { "@/*": ["./src/*"] }
|
|
106
|
+
},
|
|
107
|
+
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
|
108
|
+
"exclude": ["node_modules"]
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Node.js Library (ESM)
|
|
113
|
+
|
|
114
|
+
```jsonc
|
|
115
|
+
{
|
|
116
|
+
"compilerOptions": {
|
|
117
|
+
"target": "ES2022",
|
|
118
|
+
"module": "NodeNext",
|
|
119
|
+
"moduleResolution": "nodenext",
|
|
120
|
+
"strict": true,
|
|
121
|
+
"declaration": true,
|
|
122
|
+
"declarationMap": true,
|
|
123
|
+
"sourceMap": true,
|
|
124
|
+
"outDir": "./dist",
|
|
125
|
+
"rootDir": "./src"
|
|
126
|
+
},
|
|
127
|
+
"include": ["src"]
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### React SPA (Vite)
|
|
132
|
+
|
|
133
|
+
```jsonc
|
|
134
|
+
{
|
|
135
|
+
"compilerOptions": {
|
|
136
|
+
"target": "ES2020",
|
|
137
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
138
|
+
"module": "ESNext",
|
|
139
|
+
"moduleResolution": "bundler",
|
|
140
|
+
"jsx": "react-jsx",
|
|
141
|
+
"strict": true,
|
|
142
|
+
"noEmit": true,
|
|
143
|
+
"skipLibCheck": true
|
|
144
|
+
},
|
|
145
|
+
"include": ["src"]
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### NestJS Backend
|
|
150
|
+
|
|
151
|
+
```jsonc
|
|
152
|
+
{
|
|
153
|
+
"compilerOptions": {
|
|
154
|
+
"module": "commonjs",
|
|
155
|
+
"declaration": true,
|
|
156
|
+
"removeComments": true,
|
|
157
|
+
"emitDecoratorMetadata": true,
|
|
158
|
+
"experimentalDecorators": true,
|
|
159
|
+
"target": "ES2021",
|
|
160
|
+
"sourceMap": true,
|
|
161
|
+
"outDir": "./dist",
|
|
162
|
+
"baseUrl": "./",
|
|
163
|
+
"incremental": true,
|
|
164
|
+
"strict": true,
|
|
165
|
+
"strictNullChecks": true,
|
|
166
|
+
"noImplicitAny": true,
|
|
167
|
+
"strictBindCallApply": true,
|
|
168
|
+
"forceConsistentCasingInFileNames": true,
|
|
169
|
+
"noFallthroughCasesInSwitch": true
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Path Aliases
|
|
175
|
+
|
|
176
|
+
```jsonc
|
|
177
|
+
{
|
|
178
|
+
"compilerOptions": {
|
|
179
|
+
"baseUrl": ".",
|
|
180
|
+
"paths": {
|
|
181
|
+
"@/*": ["./src/*"],
|
|
182
|
+
"@components/*": ["./src/components/*"],
|
|
183
|
+
"@utils/*": ["./src/utils/*"]
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Note: Path aliases require bundler support (Vite, webpack) or a runtime resolver (`tsconfig-paths`). TypeScript only resolves types — it doesn't rewrite paths in emitted JS.
|
|
190
|
+
|
|
191
|
+
## Project References (Monorepos)
|
|
192
|
+
|
|
193
|
+
For monorepos with multiple packages:
|
|
194
|
+
|
|
195
|
+
```jsonc
|
|
196
|
+
// Root tsconfig.json
|
|
197
|
+
{
|
|
198
|
+
"files": [],
|
|
199
|
+
"references": [
|
|
200
|
+
{ "path": "./packages/core" },
|
|
201
|
+
{ "path": "./packages/api" },
|
|
202
|
+
{ "path": "./packages/web" }
|
|
203
|
+
]
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// packages/core/tsconfig.json
|
|
207
|
+
{
|
|
208
|
+
"compilerOptions": {
|
|
209
|
+
"composite": true,
|
|
210
|
+
"outDir": "./dist",
|
|
211
|
+
"rootDir": "./src"
|
|
212
|
+
},
|
|
213
|
+
"include": ["src"]
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// packages/api/tsconfig.json
|
|
217
|
+
{
|
|
218
|
+
"compilerOptions": {
|
|
219
|
+
"composite": true,
|
|
220
|
+
"outDir": "./dist",
|
|
221
|
+
"rootDir": "./src"
|
|
222
|
+
},
|
|
223
|
+
"references": [{ "path": "../core" }],
|
|
224
|
+
"include": ["src"]
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Build with `tsc --build` for incremental compilation across packages.
|
|
229
|
+
|
|
230
|
+
## Key Flags Reference
|
|
231
|
+
|
|
232
|
+
| Flag | Purpose | Recommended |
|
|
233
|
+
|------|---------|-------------|
|
|
234
|
+
| `strict` | All strict checks | Always `true` |
|
|
235
|
+
| `noUncheckedIndexedAccess` | Index access returns `T \| undefined` | `true` for safety |
|
|
236
|
+
| `noEmit` | Don't emit JS (use external compiler) | `true` with bundlers |
|
|
237
|
+
| `skipLibCheck` | Skip type-checking `.d.ts` files | `true` (faster builds) |
|
|
238
|
+
| `isolatedModules` | Ensure each file can be transpiled alone | `true` (required by most bundlers) |
|
|
239
|
+
| `incremental` | Cache type-check results | `true` for faster rebuilds |
|
|
240
|
+
| `composite` | Enable project references | Required for monorepos |
|
|
241
|
+
| `declaration` | Emit `.d.ts` files | `true` for libraries |
|
|
242
|
+
| `erasableSyntaxOnly` | Only erasable TS syntax (5.8+) | `true` for Node `--strip-types` |
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# Generics
|
|
2
|
+
|
|
3
|
+
Generics enable writing reusable, type-safe code that works with multiple types while preserving type information through the call chain.
|
|
4
|
+
|
|
5
|
+
## Basic Generic Functions
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// Without generics — loses type information
|
|
9
|
+
function firstElement(arr: any[]): any {
|
|
10
|
+
return arr[0];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// With generics — preserves the type
|
|
14
|
+
function firstElement<T>(arr: T[]): T | undefined {
|
|
15
|
+
return arr[0];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const n = firstElement([1, 2, 3]); // number | undefined
|
|
19
|
+
const s = firstElement(["a", "b"]); // string | undefined
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
TypeScript infers the type argument from the argument you pass. You rarely need to specify it explicitly:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// Explicit (rarely needed)
|
|
26
|
+
firstElement<string>(["a", "b"]);
|
|
27
|
+
|
|
28
|
+
// Implicit (preferred — let inference work)
|
|
29
|
+
firstElement(["a", "b"]);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Multiple Type Parameters
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
function map<T, U>(arr: T[], fn: (item: T) => U): U[] {
|
|
36
|
+
return arr.map(fn);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const lengths = map(["hello", "world"], s => s.length);
|
|
40
|
+
// T = string, U = number, result: number[]
|
|
41
|
+
|
|
42
|
+
// Swapping
|
|
43
|
+
function swap<A, B>(pair: [A, B]): [B, A] {
|
|
44
|
+
return [pair[1], pair[0]];
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Generic Constraints
|
|
49
|
+
|
|
50
|
+
Use `extends` to constrain what types are accepted:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
// T must have a length property
|
|
54
|
+
function longest<T extends { length: number }>(a: T, b: T): T {
|
|
55
|
+
return a.length >= b.length ? a : b;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
longest("hello", "world"); // OK — string has length
|
|
59
|
+
longest([1, 2], [1, 2, 3]); // OK — array has length
|
|
60
|
+
longest(10, 20); // Error — number has no length
|
|
61
|
+
|
|
62
|
+
// Constraining to a key of another type
|
|
63
|
+
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
|
|
64
|
+
return obj[key];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const user = { name: "Alice", age: 30 };
|
|
68
|
+
getProperty(user, "name"); // string
|
|
69
|
+
getProperty(user, "age"); // number
|
|
70
|
+
getProperty(user, "email"); // Error — "email" is not a key of user
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Default Type Parameters
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
// Default to unknown if not specified
|
|
77
|
+
type Container<T = unknown> = { value: T };
|
|
78
|
+
|
|
79
|
+
const a: Container<string> = { value: "hello" };
|
|
80
|
+
const b: Container = { value: 42 }; // T defaults to unknown
|
|
81
|
+
|
|
82
|
+
// Defaults with constraints
|
|
83
|
+
interface Paginated<T, P extends number = 20> {
|
|
84
|
+
items: T[];
|
|
85
|
+
pageSize: P;
|
|
86
|
+
page: number;
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Generic Classes
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
class Stack<T> {
|
|
94
|
+
private items: T[] = [];
|
|
95
|
+
|
|
96
|
+
push(item: T): void {
|
|
97
|
+
this.items.push(item);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
pop(): T | undefined {
|
|
101
|
+
return this.items.pop();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
peek(): T | undefined {
|
|
105
|
+
return this.items[this.items.length - 1];
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const numStack = new Stack<number>();
|
|
110
|
+
numStack.push(1);
|
|
111
|
+
numStack.push("hello"); // Error!
|
|
112
|
+
|
|
113
|
+
// Static members cannot reference class type parameters
|
|
114
|
+
class Factory<T> {
|
|
115
|
+
// static defaultValue: T; // Error!
|
|
116
|
+
static create<U>(): Factory<U> { return new Factory<U>(); } // OK — own parameter
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Generic Interfaces
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
interface Repository<T> {
|
|
124
|
+
findById(id: string): Promise<T | null>;
|
|
125
|
+
save(entity: T): Promise<T>;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Implementing a generic interface
|
|
129
|
+
class UserRepo implements Repository<User> {
|
|
130
|
+
async findById(id: string): Promise<User | null> { ... }
|
|
131
|
+
async save(user: User): Promise<User> { ... }
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## `const` Type Parameters (TS 5.0+)
|
|
136
|
+
|
|
137
|
+
Adding `const` to a type parameter gives const-like inference without requiring `as const` at the call site:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
// Without const — infers broad types
|
|
141
|
+
function routes<T extends readonly { path: string; method: string }[]>(r: T): T {
|
|
142
|
+
return r;
|
|
143
|
+
}
|
|
144
|
+
const r1 = routes([{ path: "/api", method: "GET" }]);
|
|
145
|
+
// Type: { path: string; method: string }[]
|
|
146
|
+
|
|
147
|
+
// With const — infers literal types
|
|
148
|
+
function routes<const T extends readonly { path: string; method: string }[]>(r: T): T {
|
|
149
|
+
return r;
|
|
150
|
+
}
|
|
151
|
+
const r2 = routes([{ path: "/api", method: "GET" }]);
|
|
152
|
+
// Type: readonly [{ readonly path: "/api"; readonly method: "GET" }]
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Variance Annotations (TS 4.7+)
|
|
156
|
+
|
|
157
|
+
Explicit variance annotations help TypeScript check generic type compatibility more efficiently:
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
// out = covariant (produces T)
|
|
161
|
+
interface Producer<out T> {
|
|
162
|
+
get(): T;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// in = contravariant (consumes T)
|
|
166
|
+
interface Consumer<in T> {
|
|
167
|
+
accept(value: T): void;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// in out = invariant (both produces and consumes T)
|
|
171
|
+
interface Processor<in out T> {
|
|
172
|
+
process(value: T): T;
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Common Patterns
|
|
177
|
+
|
|
178
|
+
### Factory Pattern
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
function create<T>(ctor: new (...args: any[]) => T, ...args: any[]): T {
|
|
182
|
+
return new ctor(...args);
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Builder Pattern
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
class QueryBuilder<T extends Record<string, unknown>> {
|
|
190
|
+
private conditions: Partial<T> = {};
|
|
191
|
+
|
|
192
|
+
where<K extends keyof T>(key: K, value: T[K]): this {
|
|
193
|
+
this.conditions[key] = value;
|
|
194
|
+
return this;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
build(): Partial<T> {
|
|
198
|
+
return { ...this.conditions };
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const query = new QueryBuilder<User>()
|
|
203
|
+
.where("name", "Alice")
|
|
204
|
+
.where("age", 30)
|
|
205
|
+
.build();
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Constraining to Specific Shapes
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
// Accept any object with a specific method
|
|
212
|
+
function serialize<T extends { toJSON(): string }>(item: T): string {
|
|
213
|
+
return item.toJSON();
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Accept functions with specific signatures
|
|
217
|
+
function apply<T, R>(fn: (arg: T) => R, arg: T): R {
|
|
218
|
+
return fn(arg);
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Guidelines
|
|
223
|
+
|
|
224
|
+
1. **Don't use generics when a concrete type works** — generics add complexity. If a function only ever works with strings, use `string`, not `T extends string`.
|
|
225
|
+
|
|
226
|
+
2. **Type parameters should appear at least twice** — if `T` only appears once in a signature, you probably don't need it:
|
|
227
|
+
```typescript
|
|
228
|
+
// Bad — T is used only once
|
|
229
|
+
function greet<T extends string>(name: T): string { ... }
|
|
230
|
+
// Good — just use string
|
|
231
|
+
function greet(name: string): string { ... }
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
3. **Prefer constraints over manual narrowing** — let the type system enforce requirements:
|
|
235
|
+
```typescript
|
|
236
|
+
// Bad
|
|
237
|
+
function process<T>(item: T) {
|
|
238
|
+
if (typeof item !== "object") throw new Error("Must be object");
|
|
239
|
+
}
|
|
240
|
+
// Good
|
|
241
|
+
function process<T extends object>(item: T) { ... }
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
4. **Use descriptive names for complex generics** — `T` is fine for simple cases, but use `TKey`, `TValue`, `TInput`, `TOutput` for clarity in complex signatures.
|
|
245
|
+
|
|
246
|
+
5. **Avoid deep generic nesting** — if you have `Foo<Bar<Baz<T>>>`, consider simplifying with intermediate type aliases.
|