@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,223 @@
|
|
|
1
|
+
# Mapped Types
|
|
2
|
+
|
|
3
|
+
Mapped types transform every property in an existing type, producing a new type. They iterate over keys and apply transformations.
|
|
4
|
+
|
|
5
|
+
## Basic Syntax
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
type Mapped<T> = {
|
|
9
|
+
[K in keyof T]: T[K];
|
|
10
|
+
};
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
This is the identity mapped type — it produces the same type. The power comes from modifying the value type or the key.
|
|
14
|
+
|
|
15
|
+
## Adding/Removing Modifiers
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
// Add readonly to all properties
|
|
19
|
+
type Readonly<T> = {
|
|
20
|
+
readonly [K in keyof T]: T[K];
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Remove readonly with -readonly
|
|
24
|
+
type Mutable<T> = {
|
|
25
|
+
-readonly [K in keyof T]: T[K];
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Make all properties optional
|
|
29
|
+
type Partial<T> = {
|
|
30
|
+
[K in keyof T]?: T[K];
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// Remove optionality with -?
|
|
34
|
+
type Required<T> = {
|
|
35
|
+
[K in keyof T]-?: T[K];
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// Combine: mutable and required
|
|
39
|
+
type Concrete<T> = {
|
|
40
|
+
-readonly [K in keyof T]-?: T[K];
|
|
41
|
+
};
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Key Remapping with `as` (TS 4.1+)
|
|
45
|
+
|
|
46
|
+
Remap keys during iteration using `as`:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
// Rename keys with a template literal
|
|
50
|
+
type Getters<T> = {
|
|
51
|
+
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
interface Person { name: string; age: number }
|
|
55
|
+
type PersonGetters = Getters<Person>;
|
|
56
|
+
// { getName: () => string; getAge: () => number }
|
|
57
|
+
|
|
58
|
+
// Filter keys by remapping to never
|
|
59
|
+
type RemoveFunctions<T> = {
|
|
60
|
+
[K in keyof T as T[K] extends Function ? never : K]: T[K];
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
interface Mixed {
|
|
64
|
+
name: string;
|
|
65
|
+
age: number;
|
|
66
|
+
greet(): void;
|
|
67
|
+
}
|
|
68
|
+
type DataOnly = RemoveFunctions<Mixed>;
|
|
69
|
+
// { name: string; age: number }
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Iterating Over Unions
|
|
73
|
+
|
|
74
|
+
Mapped types can iterate over any union of string literals, not just `keyof`:
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
type EventMap = {
|
|
78
|
+
[K in "click" | "hover" | "focus"]: (e: Event) => void;
|
|
79
|
+
};
|
|
80
|
+
// { click: (e: Event) => void; hover: (e: Event) => void; focus: (e: Event) => void }
|
|
81
|
+
|
|
82
|
+
// Using a union of string literals from an enum-like const
|
|
83
|
+
const EVENTS = ["click", "hover", "focus"] as const;
|
|
84
|
+
type EventHandlers = {
|
|
85
|
+
[K in (typeof EVENTS)[number] as `on${Capitalize<K>}`]: (e: Event) => void;
|
|
86
|
+
};
|
|
87
|
+
// { onClick: (e: Event) => void; onHover: (e: Event) => void; onFocus: (e: Event) => void }
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Practical Patterns
|
|
91
|
+
|
|
92
|
+
### Making Specific Properties Optional
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
type OptionalBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
|
96
|
+
|
|
97
|
+
interface User {
|
|
98
|
+
id: string;
|
|
99
|
+
name: string;
|
|
100
|
+
email: string;
|
|
101
|
+
}
|
|
102
|
+
type CreateUser = OptionalBy<User, "id">;
|
|
103
|
+
// { name: string; email: string; id?: string }
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Deep Partial
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
type DeepPartial<T> = {
|
|
110
|
+
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
interface Config {
|
|
114
|
+
server: { host: string; port: number };
|
|
115
|
+
db: { url: string; pool: { min: number; max: number } };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
type PartialConfig = DeepPartial<Config>;
|
|
119
|
+
// All nested properties are optional
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Deep Readonly
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
type DeepReadonly<T> = {
|
|
126
|
+
readonly [K in keyof T]: T[K] extends object
|
|
127
|
+
? T[K] extends Function
|
|
128
|
+
? T[K]
|
|
129
|
+
: DeepReadonly<T[K]>
|
|
130
|
+
: T[K];
|
|
131
|
+
};
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Nullable Properties
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
type Nullable<T> = {
|
|
138
|
+
[K in keyof T]: T[K] | null;
|
|
139
|
+
};
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Event Emitter Types
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
type EventEmitter<Events extends Record<string, any[]>> = {
|
|
146
|
+
on<K extends keyof Events>(event: K, handler: (...args: Events[K]) => void): void;
|
|
147
|
+
emit<K extends keyof Events>(event: K, ...args: Events[K]): void;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
interface MyEvents {
|
|
151
|
+
login: [user: User];
|
|
152
|
+
error: [code: number, message: string];
|
|
153
|
+
logout: [];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
declare const emitter: EventEmitter<MyEvents>;
|
|
157
|
+
emitter.on("login", (user) => { ... }); // user: User
|
|
158
|
+
emitter.on("error", (code, msg) => { ... }); // code: number, msg: string
|
|
159
|
+
emitter.emit("logout"); // no args
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### API Route Types
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
type ApiRoutes = {
|
|
166
|
+
"/users": { GET: User[]; POST: User };
|
|
167
|
+
"/users/:id": { GET: User; PUT: User; DELETE: void };
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
type RouteHandler<
|
|
171
|
+
Routes extends Record<string, Record<string, any>>,
|
|
172
|
+
Path extends keyof Routes,
|
|
173
|
+
Method extends keyof Routes[Path]
|
|
174
|
+
> = () => Promise<Routes[Path][Method]>;
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Record-Like with Constraints
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
// Like Record, but values depend on the key
|
|
181
|
+
type TypedRecord<K extends string, ValueFn extends Record<K, any>> = {
|
|
182
|
+
[P in K]: ValueFn[P];
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// Each validator returns the type it validates
|
|
186
|
+
type Validators = TypedRecord<
|
|
187
|
+
"name" | "age",
|
|
188
|
+
{ name: string; age: number }
|
|
189
|
+
>;
|
|
190
|
+
// { name: string; age: number }
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Combining with Conditional Types
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
// Make all function properties async
|
|
197
|
+
type Asyncify<T> = {
|
|
198
|
+
[K in keyof T]: T[K] extends (...args: infer A) => infer R
|
|
199
|
+
? (...args: A) => Promise<R>
|
|
200
|
+
: T[K];
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
interface Sync {
|
|
204
|
+
getData(): string;
|
|
205
|
+
count: number;
|
|
206
|
+
}
|
|
207
|
+
type Async = Asyncify<Sync>;
|
|
208
|
+
// { getData: () => Promise<string>; count: number }
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Homomorphic vs Non-Homomorphic
|
|
212
|
+
|
|
213
|
+
A mapped type is **homomorphic** when it maps over `keyof T` (preserving modifiers from the original):
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
// Homomorphic — preserves optional/readonly from T
|
|
217
|
+
type Clone<T> = { [K in keyof T]: T[K] };
|
|
218
|
+
|
|
219
|
+
// Non-homomorphic — uses an independent key set
|
|
220
|
+
type FromKeys<K extends string> = { [P in K]: unknown };
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Homomorphic mapped types automatically preserve `readonly` and `?` modifiers unless explicitly removed with `-readonly` or `-?`.
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# Template Literal Types
|
|
2
|
+
|
|
3
|
+
Template literal types build string types from other types using template literal syntax. They're TypeScript's most powerful tool for type-safe string manipulation.
|
|
4
|
+
|
|
5
|
+
## Basic Syntax
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
type Greeting = `Hello, ${string}`;
|
|
9
|
+
// Matches "Hello, Alice", "Hello, Bob", "Hello, " — any string after "Hello, "
|
|
10
|
+
|
|
11
|
+
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
|
|
12
|
+
type Endpoint = `/api/${string}`;
|
|
13
|
+
type ApiCall = `${HttpMethod} ${Endpoint}`;
|
|
14
|
+
// "GET /api/..." | "POST /api/..." | "PUT /api/..." | "DELETE /api/..."
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Union Expansion
|
|
18
|
+
|
|
19
|
+
When unions appear in template literal positions, the result is the cross product:
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
type Suit = "hearts" | "diamonds" | "clubs" | "spades";
|
|
23
|
+
type Rank = "A" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "J" | "Q" | "K";
|
|
24
|
+
type Card = `${Rank} of ${Suit}`;
|
|
25
|
+
// "A of hearts" | "A of diamonds" | ... | "K of spades" (52 members)
|
|
26
|
+
|
|
27
|
+
type Size = "sm" | "md" | "lg";
|
|
28
|
+
type Color = "red" | "blue" | "green";
|
|
29
|
+
type Variant = `${Size}-${Color}`;
|
|
30
|
+
// "sm-red" | "sm-blue" | "sm-green" | "md-red" | ... (9 members)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Intrinsic String Manipulation Types
|
|
34
|
+
|
|
35
|
+
TypeScript provides four built-in types that transform string literals:
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
type A = Uppercase<"hello">; // "HELLO"
|
|
39
|
+
type B = Lowercase<"HELLO">; // "hello"
|
|
40
|
+
type C = Capitalize<"hello">; // "Hello"
|
|
41
|
+
type D = Uncapitalize<"Hello">; // "hello"
|
|
42
|
+
|
|
43
|
+
// Combined with template literals
|
|
44
|
+
type EventHandler<T extends string> = `on${Capitalize<T>}`;
|
|
45
|
+
type Click = EventHandler<"click">; // "onClick"
|
|
46
|
+
type KeyDown = EventHandler<"keyDown">; // "onKeyDown"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Pattern Matching with `infer`
|
|
50
|
+
|
|
51
|
+
Template literals can extract parts of string types:
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
// Extract the event name from "on{Event}"
|
|
55
|
+
type ExtractEvent<T> = T extends `on${infer E}` ? Uncapitalize<E> : never;
|
|
56
|
+
type A = ExtractEvent<"onClick">; // "click"
|
|
57
|
+
type B = ExtractEvent<"onKeyDown">; // "keyDown"
|
|
58
|
+
type C = ExtractEvent<"submit">; // never
|
|
59
|
+
|
|
60
|
+
// Parse dot-separated paths
|
|
61
|
+
type FirstSegment<T extends string> = T extends `${infer Head}.${string}` ? Head : T;
|
|
62
|
+
type D = FirstSegment<"user.address.city">; // "user"
|
|
63
|
+
type E = FirstSegment<"name">; // "name"
|
|
64
|
+
|
|
65
|
+
// Split a string type
|
|
66
|
+
type Split<S extends string, D extends string> =
|
|
67
|
+
S extends `${infer Head}${D}${infer Tail}`
|
|
68
|
+
? [Head, ...Split<Tail, D>]
|
|
69
|
+
: [S];
|
|
70
|
+
|
|
71
|
+
type F = Split<"a.b.c", ".">; // ["a", "b", "c"]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Practical Patterns
|
|
75
|
+
|
|
76
|
+
### Type-Safe Event System
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
type EventMap = {
|
|
80
|
+
click: { x: number; y: number };
|
|
81
|
+
keydown: { key: string };
|
|
82
|
+
resize: { width: number; height: number };
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
type EventHandlerName<T extends string> = `on${Capitalize<T>}`;
|
|
86
|
+
|
|
87
|
+
type EventHandlers<E extends Record<string, any>> = {
|
|
88
|
+
[K in keyof E as EventHandlerName<string & K>]?: (event: E[K]) => void;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
type MyHandlers = EventHandlers<EventMap>;
|
|
92
|
+
// { onClick?: (event: { x: number; y: number }) => void;
|
|
93
|
+
// onKeydown?: (event: { key: string }) => void;
|
|
94
|
+
// onResize?: (event: { width: number; height: number }) => void; }
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Type-Safe CSS Properties
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
type CSSUnit = "px" | "em" | "rem" | "%" | "vh" | "vw";
|
|
101
|
+
type CSSValue = `${number}${CSSUnit}` | "auto" | "inherit";
|
|
102
|
+
|
|
103
|
+
function setWidth(el: HTMLElement, width: CSSValue) {
|
|
104
|
+
el.style.width = width;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
setWidth(el, "100px"); // OK
|
|
108
|
+
setWidth(el, "2.5rem"); // OK
|
|
109
|
+
setWidth(el, "auto"); // OK
|
|
110
|
+
setWidth(el, "100"); // Error — missing unit
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Route Parameter Extraction
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
type ExtractParams<T extends string> =
|
|
117
|
+
T extends `${string}:${infer Param}/${infer Rest}`
|
|
118
|
+
? Param | ExtractParams<`/${Rest}`>
|
|
119
|
+
: T extends `${string}:${infer Param}`
|
|
120
|
+
? Param
|
|
121
|
+
: never;
|
|
122
|
+
|
|
123
|
+
type Params = ExtractParams<"/users/:userId/posts/:postId">;
|
|
124
|
+
// "userId" | "postId"
|
|
125
|
+
|
|
126
|
+
type RouteParams<T extends string> = {
|
|
127
|
+
[K in ExtractParams<T>]: string;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
type UserPostParams = RouteParams<"/users/:userId/posts/:postId">;
|
|
131
|
+
// { userId: string; postId: string }
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### SQL Column Type Mapping
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
type SQLType = "TEXT" | "INTEGER" | "BOOLEAN" | "TIMESTAMP";
|
|
138
|
+
|
|
139
|
+
type TSTypeMap = {
|
|
140
|
+
TEXT: string;
|
|
141
|
+
INTEGER: number;
|
|
142
|
+
BOOLEAN: boolean;
|
|
143
|
+
TIMESTAMP: Date;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
type ColumnDef<Name extends string, Type extends SQLType> = `${Name} ${Type}`;
|
|
147
|
+
|
|
148
|
+
type ParseColumn<T> = T extends `${infer Name} ${infer Type extends SQLType}`
|
|
149
|
+
? { name: Name; type: TSTypeMap[Type] }
|
|
150
|
+
: never;
|
|
151
|
+
|
|
152
|
+
type Col = ParseColumn<"username TEXT">;
|
|
153
|
+
// { name: "username"; type: string }
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Deep Property Paths
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
type PropPath<T, Prefix extends string = ""> = {
|
|
160
|
+
[K in keyof T & string]: T[K] extends object
|
|
161
|
+
? PropPath<T[K], `${Prefix}${K}.`>
|
|
162
|
+
: `${Prefix}${K}`;
|
|
163
|
+
}[keyof T & string];
|
|
164
|
+
|
|
165
|
+
interface User {
|
|
166
|
+
name: string;
|
|
167
|
+
address: {
|
|
168
|
+
city: string;
|
|
169
|
+
zip: string;
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
type UserPaths = PropPath<User>;
|
|
174
|
+
// "name" | "address.city" | "address.zip"
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Template Literals as Discriminants (TS 4.5+)
|
|
178
|
+
|
|
179
|
+
Template literal types can serve as discriminants in unions:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
interface SuccessResponse {
|
|
183
|
+
type: `${string}Success`;
|
|
184
|
+
data: unknown;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
interface ErrorResponse {
|
|
188
|
+
type: `${string}Error`;
|
|
189
|
+
message: string;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function handle(r: SuccessResponse | ErrorResponse) {
|
|
193
|
+
if (r.type === "ApiSuccess") {
|
|
194
|
+
r.data; // SuccessResponse narrowed
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Performance Considerations
|
|
200
|
+
|
|
201
|
+
Template literal unions grow multiplicatively. A cross product of two unions with 10 members each creates 100 members. TypeScript limits union sizes (around 100,000 members), so avoid unbounded cross products:
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
// This is fine — 3 x 3 = 9 members
|
|
205
|
+
type Small = `${1 | 2 | 3}-${"a" | "b" | "c"}`;
|
|
206
|
+
|
|
207
|
+
// This would be problematic — string has infinite members
|
|
208
|
+
// type Bad = `${string}-${string}`; // Works but can't enumerate
|
|
209
|
+
```
|