{"id":"61c3e7b7-0376-499b-bb2f-87e31e37a492","shortId":"bDGZ4J","kind":"skill","title":"typescript-project","tagline":"Modern TypeScript project architecture guide for 2025. Use when creating new TS projects, setting up configurations, or designing project structure. Covers tech stack selection, layered architecture, and best practices.","description":"# TypeScript Project Architecture\n\n## Core Principles\n\n- **Type safety first** — Strict mode, no `any`, Zod for runtime validation\n- **ESM native** — ES Modules by default, Node 22+ / Bun\n- **Layered architecture** — Separate lib/services/adapters\n- **200-line limit** — No file exceeds 200 lines (see elegant-architecture skill)\n- **Test reality** — Vitest/Bun test, minimal mocks\n- **No backwards compatibility** — Delete, don't deprecate. Change directly, no shims\n- **LiteLLM for LLM APIs** — Use LiteLLM proxy for all LLM integrations, unless specific SDK required\n\n---\n\n## No Backwards Compatibility\n\n> **Delete unused code. Change directly. No compatibility layers.**\n\n### Why\n\n- Dead code is tech debt\n- Compatibility shims add complexity\n- Old patterns spread through copy-paste\n- \"Temporary\" workarounds become permanent\n\n### Anti-Patterns to Avoid\n\n```typescript\n// ❌ BAD: Renaming but keeping old export\nexport { newName };\nexport { newName as oldName }; // \"for backwards compatibility\"\n\n// ❌ BAD: Unused parameter with underscore\nfunction process(_legacyParam: string, data: Data) { ... }\n\n// ❌ BAD: Deprecated comments instead of deletion\n/** @deprecated Use newMethod instead */\nexport function oldMethod() { ... }\n\n// ❌ BAD: Re-exporting removed functionality\nexport { removed } from './legacy'; // Keep for existing consumers\n\n// ❌ BAD: Feature flags for old behavior\nif (config.useLegacyMode) { ... }\n```\n\n### Correct Approach\n\n```typescript\n// ✅ GOOD: Just delete and update all usages\n// Old: export { fetchData as getData }\n// New: export { fetchData }\n// Then: Find & replace all getData → fetchData\n\n// ✅ GOOD: Remove unused parameters entirely\nfunction process(data: Data) { ... }\n\n// ✅ GOOD: Delete deprecated code, update callers\n// Don't mark as deprecated, just remove it\n\n// ✅ GOOD: Breaking changes are fine in active development\n// Semantic versioning handles this for libraries\n```\n\n### When Changing Interfaces\n\n```typescript\n// ❌ BAD: Adding optional fields \"for compatibility\"\ninterface User {\n  id: string;\n  name: string;\n  firstName?: string; // New field, name kept for compatibility\n  lastName?: string;\n}\n\n// ✅ GOOD: Clean break, update all usages\ninterface User {\n  id: string;\n  firstName: string;\n  lastName: string;\n}\n// Then update ALL code that uses User.name\n```\n\n### Migration Strategy\n\n1. **Find all usages** — `grep -r \"oldName\" src/`\n2. **Update all at once** — Single commit, no transition period\n3. **Delete old code** — No deprecation warnings, just remove\n4. **Run tests** — Ensure nothing breaks\n\n---\n\n## LiteLLM for LLM APIs\n\n> **Use LiteLLM proxy for all LLM integrations. Don't call provider APIs directly.**\n\n### Why LiteLLM\n\n- **Unified interface** — One API for 100+ LLM providers (OpenAI, Anthropic, Azure, Bedrock, etc.)\n- **Provider agnostic** — Switch models without code changes\n- **Cost tracking** — Built-in usage and cost monitoring\n- **Load balancing** — Automatic failover between providers\n- **Rate limiting** — Protect against quota exhaustion\n\n### Setup\n\n```bash\n# Run LiteLLM proxy (Docker)\ndocker run -p 4000:4000 ghcr.io/berriai/litellm:main-stable\n\n# Or install locally\npip install litellm[proxy]\nlitellm --model gpt-4o\n```\n\n### TypeScript Usage\n\n```typescript\n// adapters/llm.adapter.ts\nimport { OpenAI } from 'openai';\n\n// Connect to LiteLLM proxy using OpenAI SDK\nconst llm = new OpenAI({\n  baseURL: process.env.LITELLM_URL || 'http://localhost:4000',\n  apiKey: process.env.LITELLM_API_KEY || 'sk-1234', // Proxy API key\n});\n\nexport async function complete(prompt: string, model = 'gpt-4o'): Promise<string> {\n  const response = await llm.chat.completions.create({\n    model, // Can be any model: gpt-4o, claude-3-opus, gemini-pro, etc.\n    messages: [{ role: 'user', content: prompt }],\n  });\n  return response.choices[0]?.message?.content ?? '';\n}\n```\n\n### When NOT to Use LiteLLM\n\n- Streaming with provider-specific features (e.g., Anthropic's tool use streaming)\n- Provider-specific APIs not in OpenAI format (embeddings with metadata, etc.)\n- Direct SDK required for compliance/security reasons\n\n### Anti-Patterns\n\n```typescript\n// ❌ BAD: Direct provider SDKs everywhere\nimport Anthropic from '@anthropic-ai/sdk';\nimport OpenAI from 'openai';\nimport { GoogleGenerativeAI } from '@google/generative-ai';\n\n// ❌ BAD: Provider-specific code scattered across codebase\nif (provider === 'anthropic') { ... }\nelse if (provider === 'openai') { ... }\n\n// ✅ GOOD: Single LiteLLM adapter, switch models via config\nconst response = await llm.chat.completions.create({\n  model: config.llmModel, // \"gpt-4o\" or \"claude-3-opus\" or \"gemini-pro\"\n  messages,\n});\n```\n\n---\n\n## Quick Start\n\n### 1. Initialize Project\n\n```bash\n# Using Bun (recommended)\nbun init\nbun add zod\nbun add -d typescript @types/bun @biomejs/biome\n\n# Using Node.js\nnpm init -y\nnpm i zod\nnpm i -D typescript @types/node tsx @biomejs/biome\n```\n\n### 2. Apply Tech Stack\n\n| Layer | Recommendation |\n|-------|----------------|\n| Runtime | Bun / Node 22+ |\n| Language | TypeScript (latest) |\n| Validation | Zod (latest) |\n| Testing | Bun test / Vitest |\n| Build | bun build / tsup |\n| Linting | Biome (latest) |\n\n### Version Strategy\n\n> **Always use latest. Never pin versions in templates.**\n\n```json\n{\n  \"dependencies\": {\n    \"zod\": \"latest\"\n  },\n  \"devDependencies\": {\n    \"@biomejs/biome\": \"latest\",\n    \"typescript\": \"latest\"\n  }\n}\n```\n\n- `bun add` / `npm i` automatically fetches latest\n- Use `bun update --latest` to upgrade all dependencies\n- Lock files (`bun.lockb`, `package-lock.json`) ensure reproducible builds\n- Breaking changes are handled by reading changelogs, not by avoiding updates\n\n### 3. Use Standard Structure\n\n```\nproject/\n├── src/\n│   ├── index.ts           # Entry point\n│   ├── lib/               # Core utilities\n│   │   ├── config.ts      # Configuration management\n│   │   ├── errors.ts      # Custom error classes\n│   │   ├── logger.ts      # Logging infrastructure\n│   │   └── types.ts       # Shared type definitions\n│   ├── services/          # Business logic\n│   │   └── *.service.ts\n│   └── adapters/          # External integrations\n│       └── *.adapter.ts\n├── tests/                 # Test files\n│   └── *.test.ts\n├── tsconfig.json\n├── package.json\n└── biome.json             # or eslint.config.js\n```\n\n---\n\n## Architecture Layers\n\n### lib/ — Core Infrastructure\n\nFoundational code used across the entire application:\n\n```typescript\n// lib/types.ts — Shared type definitions\nexport interface Result<T, E = Error> {\n  ok: boolean;\n  data?: T;\n  error?: E;\n}\n\n// lib/errors.ts — Custom errors\nexport class AppError extends Error {\n  constructor(\n    message: string,\n    public code: string,\n    public statusCode: number = 500\n  ) {\n    super(message);\n    this.name = 'AppError';\n  }\n}\n\n// lib/config.ts — Configuration\nexport const config = {\n  env: process.env.NODE_ENV || 'development',\n  port: Number(process.env.PORT) || 3000,\n  db: {\n    url: process.env.DATABASE_URL!,\n  },\n} as const;\n\n// lib/logger.ts — Logging (see structured-logging skill)\n```\n\n### services/ — Business Logic\n\nPure business logic with injected dependencies:\n\n```typescript\n// services/user.service.ts\nexport class UserService {\n  constructor(private readonly userRepo: UserRepository) {}\n\n  async create(input: CreateUserInput): Promise<User> {\n    const existing = await this.userRepo.findByEmail(input.email);\n    if (existing) throw new AppError('Email exists', 'USER_EXISTS', 409);\n    return this.userRepo.save(User.create(input));\n  }\n}\n```\n\n### adapters/ — External Integrations\n\nInterface with external systems (DB, APIs, file system):\n\n```typescript\n// adapters/postgres.adapter.ts\nexport class PostgresUserRepository implements UserRepository {\n  constructor(private readonly db: Database) {}\n\n  async findByEmail(email: string): Promise<User | null> {\n    const row = await this.db.query('SELECT * FROM users WHERE email = $1', [email]);\n    return row ? User.fromRow(row) : null;\n  }\n}\n```\n\n---\n\n## Configuration Files\n\n### tsconfig.json (2025)\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"NodeNext\",\n    \"moduleResolution\": \"NodeNext\",\n    \"lib\": [\"ES2022\"],\n    \"outDir\": \"dist\",\n    \"rootDir\": \"src\",\n    \"strict\": true,\n    \"noUncheckedIndexedAccess\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"declaration\": true,\n    \"sourceMap\": true\n  },\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"node_modules\", \"dist\"]\n}\n```\n\n### package.json\n\n```json\n{\n  \"name\": \"my-project\",\n  \"version\": \"1.0.0\",\n  \"type\": \"module\",\n  \"main\": \"dist/index.js\",\n  \"scripts\": {\n    \"dev\": \"bun run --watch src/index.ts\",\n    \"build\": \"bun build src/index.ts --outdir dist --target bun\",\n    \"start\": \"bun dist/index.js\",\n    \"test\": \"bun test\",\n    \"typecheck\": \"tsc --noEmit\"\n  }\n}\n```\n\n---\n\n## Validation with Zod\n\n```typescript\nimport { z } from 'zod';\n\n// Define schemas\nexport const CreateUserSchema = z.object({\n  email: z.string().email(),\n  name: z.string().min(2).max(100),\n  age: z.number().int().positive().optional(),\n});\n\n// Infer types from schemas\nexport type CreateUserInput = z.infer<typeof CreateUserSchema>;\n\n// Validate at boundaries\nexport function validateInput<T>(schema: z.ZodType<T>, data: unknown): T {\n  return schema.parse(data);\n}\n```\n\n---\n\n## Error Handling Pattern\n\n```typescript\n// lib/errors.ts\nexport class AppError extends Error {\n  constructor(\n    message: string,\n    public readonly code: string,\n    public readonly statusCode: number = 500,\n    public readonly context?: Record<string, unknown>\n  ) {\n    super(message);\n    this.name = 'AppError';\n    Error.captureStackTrace(this, this.constructor);\n  }\n\n  static notFound(resource: string, id: string) {\n    return new AppError(`${resource} not found: ${id}`, 'NOT_FOUND', 404);\n  }\n\n  static validation(message: string, context?: Record<string, unknown>) {\n    return new AppError(message, 'VALIDATION_ERROR', 400, context);\n  }\n}\n\n// Usage\nthrow AppError.notFound('User', userId);\n```\n\n---\n\n## Testing Strategy\n\n```typescript\n// tests/user.service.test.ts\nimport { describe, it, expect, beforeEach } from 'bun:test';\nimport { UserService } from '../src/services/user.service';\nimport { InMemoryUserRepository } from './helpers/in-memory-repo';\n\ndescribe('UserService', () => {\n  let service: UserService;\n  let repo: InMemoryUserRepository;\n\n  beforeEach(() => {\n    repo = new InMemoryUserRepository();\n    service = new UserService(repo);\n  });\n\n  it('creates user with valid input', async () => {\n    const user = await service.create({\n      email: 'test@example.com',\n      name: 'Test User',\n    });\n\n    expect(user.email).toBe('test@example.com');\n    expect(await repo.findByEmail('test@example.com')).toEqual(user);\n  });\n\n  it('rejects duplicate email', async () => {\n    await service.create({ email: 'test@example.com', name: 'User 1' });\n\n    expect(\n      service.create({ email: 'test@example.com', name: 'User 2' })\n    ).rejects.toThrow('Email exists');\n  });\n});\n```\n\n---\n\n## Checklist\n\n```markdown\n## Project Setup\n- [ ] TypeScript strict mode enabled\n- [ ] ESM modules configured\n- [ ] Biome/ESLint configured\n- [ ] Testing framework ready\n\n## Architecture\n- [ ] lib/ for core utilities\n- [ ] services/ for business logic\n- [ ] adapters/ for external integrations\n- [ ] Clear module boundaries\n\n## Quality\n- [ ] Zod schemas for validation\n- [ ] Custom error classes\n- [ ] Structured logging\n- [ ] Tests for critical paths\n\n## Build\n- [ ] Build script configured\n- [ ] Type checking in CI\n- [ ] Tests in CI\n```\n\n---\n\n## See Also\n\n- [reference/architecture.md](reference/architecture.md) — Detailed architecture patterns\n- [reference/tech-stack.md](reference/tech-stack.md) — Tech stack comparison\n- [reference/patterns.md](reference/patterns.md) — Design patterns\n- [elegant-architecture skill](../elegant-architecture.SKILL.md) — 200-line file limit\n- [structured-logging skill](../structured-logging.SKILL.md) — Logging setup","tags":["typescript","project","claude","arsenal","majiayu000","agent-skills","ai-agents","ai-coding-assistant","automation","claude-code","code-review","developer-tools"],"capabilities":["skill","source-majiayu000","skill-typescript-project","topic-agent-skills","topic-ai-agents","topic-ai-coding-assistant","topic-automation","topic-claude","topic-claude-code","topic-code-review","topic-developer-tools","topic-devops","topic-productivity","topic-prompt-engineering","topic-python"],"categories":["claude-arsenal"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/majiayu000/claude-arsenal/typescript-project","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add majiayu000/claude-arsenal","source_repo":"https://github.com/majiayu000/claude-arsenal","install_from":"skills.sh"}},"qualityScore":"0.464","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 29 github stars · SKILL.md body (11,995 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-01T07:01:17.298Z","embedding":null,"createdAt":"2026-04-18T22:24:33.695Z","updatedAt":"2026-05-01T07:01:17.298Z","lastSeenAt":"2026-05-01T07:01:17.298Z","tsv":"'-1234':464 '-3':492,601 '/berriai/litellm:main-stable':422 '/elegant-architecture.skill.md':1289 '/helpers/in-memory-repo':1147 '/legacy':193 '/sdk':558 '/src/services/user.service':1143 '/structured-logging.skill.md':1298 '0':505 '1':316,610,924,1201 '1.0.0':978 '100':373,1028 '2':324,643,1026,1208 '200':62,68,1290 '2025':10,934 '22':56,652 '3':334,722 '3000':828 '4':343 '400':1121 '4000':418,419,458 '404':1106 '409':880 '4o':434,477,490,598 '500':811,1077 'across':573,773 'activ':259 'ad':272 'adapt':585,752,885,1237 'adapter.ts':755 'adapters/llm.adapter.ts':438 'adapters/postgres.adapter.ts':897 'add':126,620,623,690 'age':1029 'agnost':382 'ai':557 'also':1270 'alway':672 'anthrop':377,520,553,556,577 'anthropic-ai':555 'anti':140,544 'anti-pattern':139,543 'api':95,352,364,371,461,466,528,893 'apikey':459 'apperror':799,815,875,1063,1087,1099,1117 'apperror.notfound':1125 'appli':644 'applic':776 'approach':207 'architectur':7,29,35,59,73,765,1228,1274,1287 'async':469,861,908,1170,1194 'automat':399,693 'avoid':143,720 'await':481,592,868,917,1173,1185,1195 'azur':378 'backward':82,108,158 'bad':145,160,171,184,198,271,547,567 'balanc':398 'baseurl':454 'bash':410,613 'becom':137 'bedrock':379 'beforeeach':1136,1156 'behavior':203 'best':31 'biom':668 'biome.json':762 'biome/eslint':1223 'biomejs/biome':627,642,685 'boolean':789 'boundari':1044,1243 'break':254,295,348,711 'build':663,665,710,989,991,1258,1259 'built':391 'built-in':390 'bun':57,615,617,619,622,650,660,664,689,697,985,990,996,998,1001,1138 'bun.lockb':706 'busi':749,843,846,1235 'call':362 'caller':244 'chang':88,113,255,268,387,712 'changelog':717 'check':1263 'checklist':1212 'ci':1265,1268 'class':740,798,854,899,1062,1251 'claud':491,600 'clean':294 'clear':1241 'code':112,120,242,310,337,386,571,771,806,1071 'codebas':574 'comment':173 'commit':330 'comparison':1280 'compat':83,109,116,124,159,276,290 'compileropt':936 'complet':471 'complex':127 'compliance/security':541 'config':589,820 'config.llmmodel':595 'config.ts':734 'config.uselegacymode':205 'configur':19,735,817,931,1222,1224,1261 'connect':443 'const':450,479,590,819,834,866,915,1017,1171 'constructor':802,856,903,1066 'consum':197 'content':501,507 'context':1080,1111,1122 'copi':133 'copy-past':132 'core':36,732,768,1231 'correct':206 'cost':388,395 'cover':24 'creat':13,862,1165 'createuserinput':864,1040 'createuserschema':1018 'critic':1256 'custom':738,795,1249 'd':624,638 'data':169,170,237,238,790,1050,1055 'databas':907 'db':829,892,906 'dead':119 'debt':123 'declar':961 'default':54 'defin':1014 'definit':747,781 'delet':84,110,176,211,240,335 'depend':681,703,850 'deprec':87,172,177,241,249,339 'describ':1133,1148 'design':21,1283 'detail':1273 'dev':984 'devdepend':684 'develop':260,824 'direct':89,114,365,537,548 'dist':946,970,994 'dist/index.js':982,999 'docker':414,415 'duplic':1192 'e':786,793 'e.g':519 'eleg':72,1286 'elegant-architectur':71,1285 'els':578 'email':876,910,923,925,1020,1022,1175,1193,1197,1204,1210 'embed':533 'enabl':1219 'ensur':346,708 'entir':234,775 'entri':729 'env':821,823 'error':739,787,792,796,801,1056,1065,1120,1250 'error.capturestacktrace':1088 'errors.ts':737 'es':51 'es2022':938,944 'eslint.config.js':764 'esm':49,1220 'esmoduleinterop':957 'etc':380,497,536 'everywher':551 'exceed':67 'exclud':967 'exhaust':408 'exist':196,867,872,877,879,1211 'expect':1135,1180,1184,1202 'export':150,151,153,181,187,190,217,222,468,782,797,818,853,898,1016,1038,1045,1061 'extend':800,1064 'extern':753,886,890,1239 'failov':400 'featur':199,518 'fetch':694 'fetchdata':218,223,229 'field':274,286 'file':66,705,758,894,932,1292 'find':225,317 'findbyemail':909 'fine':257 'first':40 'firstnam':283,303 'flag':200 'format':532 'found':1102,1105 'foundat':770 'framework':1226 'function':165,182,189,235,470,1046 'gemini':495,605 'gemini-pro':494,604 'getdata':220,228 'ghcr.io':421 'ghcr.io/berriai/litellm:main-stable':420 'good':209,230,239,253,293,582 'google/generative-ai':566 'googlegenerativeai':564 'gpt':433,476,489,597 'gpt-4o':432,475,488,596 'grep':320 'guid':8 'handl':263,714,1057 'id':279,301,1095,1103 'implement':901 'import':439,552,559,563,1010,1132,1140,1144 'includ':965 'index.ts':728 'infer':1034 'infrastructur':743,769 'init':618,631 'initi':611 'inject':849 'inmemoryuserrepositori':1145,1155,1159 'input':863,884,1169 'input.email':870 'instal':424,427 'instead':174,180 'int':1031 'integr':102,359,754,887,1240 'interfac':269,277,299,369,783,888 'json':680,935,972 'keep':148,194 'kept':288 'key':462,467 'languag':653 'lastnam':291,305 'latest':655,658,669,674,683,686,688,695,699 'layer':28,58,117,647,766 'legacyparam':167 'let':1150,1153 'lib':731,767,943,1229 'lib/config.ts':816 'lib/errors.ts':794,1060 'lib/logger.ts':835 'lib/services/adapters':61 'lib/types.ts':778 'librari':266 'limit':64,404,1293 'line':63,69,1291 'lint':667 'litellm':92,97,349,354,367,412,428,430,445,512,584 'llm':94,101,351,358,374,451 'llm.chat.completions.create':482,593 'load':397 'local':425 'localhost':457 'lock':704 'log':742,836,840,1253,1296,1299 'logger.ts':741 'logic':750,844,847,1236 'main':981 'manag':736 'mark':247 'markdown':1213 'max':1027 'messag':498,506,607,803,813,1067,1085,1109,1118 'metadata':535 'migrat':314 'min':1025 'minim':79 'mock':80 'mode':42,1218 'model':384,431,474,483,487,587,594 'modern':4 'modul':52,939,969,980,1221,1242 'moduleresolut':941 'monitor':396 'my-project':974 'name':281,287,973,1023,1177,1199,1206 'nativ':50 'never':675 'new':14,221,285,452,874,1098,1116,1158,1161 'newmethod':179 'newnam':152,154 'node':55,651,968 'node.js':629 'nodenext':940,942 'noemit':1005 'notfound':1092 'noth':347 'nouncheckedindexedaccess':951 'nounusedloc':953 'nounusedparamet':955 'npm':630,633,636,691 'null':914,930 'number':810,826,1076 'ok':788 'old':128,149,202,216,336 'oldmethod':183 'oldnam':156,322 'one':370 'openai':376,440,442,448,453,531,560,562,581 'option':273,1033 'opus':493,602 'outdir':945,993 'p':417 'package-lock.json':707 'package.json':761,971 'paramet':162,233 'past':134 'path':1257 'pattern':129,141,545,1058,1275,1284 'period':333 'perman':138 'pin':676 'pip':426 'point':730 'port':825 'posit':1032 'postgresuserrepositori':900 'practic':32 'principl':37 'privat':857,904 'pro':496,606 'process':166,236 'process.env.database':831 'process.env.litellm':455,460 'process.env.node':822 'process.env.port':827 'project':3,6,16,22,34,612,726,976,1214 'promis':478,865,912 'prompt':472,502 'protect':405 'provid':363,375,381,402,516,526,549,569,576,580 'provider-specif':515,525,568 'proxi':98,355,413,429,446,465 'public':805,808,1069,1073,1078 'pure':845 'qualiti':1244 'quick':608 'quota':407 'r':321 'rate':403 're':186 're-export':185 'read':716 'readi':1227 'readon':858,905,1070,1074,1079 'realiti':76 'reason':542 'recommend':616,648 'record':1081,1112 'reference/architecture.md':1271,1272 'reference/patterns.md':1281,1282 'reference/tech-stack.md':1276,1277 'reject':1191 'rejects.tothrow':1209 'remov':188,191,231,251,342 'renam':146 'replac':226 'repo':1154,1157,1163 'repo.findbyemail':1186 'reproduc':709 'requir':106,539 'resourc':1093,1100 'respons':480,591 'response.choices':504 'result':784 'return':503,881,926,1053,1097,1115 'role':499 'rootdir':947 'row':916,927,929 'run':344,411,416,986 'runtim':47,649 'safeti':39 'scatter':572 'schema':1015,1037,1048,1246 'schema.parse':1054 'script':983,1260 'sdk':105,449,538 'sdks':550 'see':70,837,1269 'select':27,919 'semant':261 'separ':60 'servic':748,842,1151,1160,1233 'service.create':1174,1196,1203 'service.ts':751 'services/user.service.ts':852 'set':17 'setup':409,1215,1300 'share':745,779 'shim':91,125 'singl':329,583 'sk':463 'skill':74,841,1288,1297 'skill-typescript-project' 'skiplibcheck':959 'source-majiayu000' 'sourcemap':963 'specif':104,517,527,570 'spread':130 'src':323,727,948,966 'src/index.ts':988,992 'stack':26,646,1279 'standard':724 'start':609,997 'static':1091,1107 'statuscod':809,1075 'strategi':315,671,1129 'stream':513,524 'strict':41,949,1217 'string':168,280,282,284,292,302,304,306,473,804,807,911,1068,1072,1082,1094,1096,1110,1113 'structur':23,725,839,1252,1295 'structured-log':838,1294 'super':812,1084 'switch':383,586 'system':891,895 'target':937,995 'tech':25,122,645,1278 'templat':679 'temporari':135 'test':75,78,345,659,661,756,757,1000,1002,1128,1139,1178,1225,1254,1266 'test.ts':759 'test@example.com':1176,1183,1187,1198,1205 'tests/user.service.test.ts':1131 'this.constructor':1090 'this.db.query':918 'this.name':814,1086 'this.userrepo.findbyemail':869 'this.userrepo.save':882 'throw':873,1124 'tobe':1182 'toequal':1188 'tool':522 'topic-agent-skills' 'topic-ai-agents' 'topic-ai-coding-assistant' 'topic-automation' 'topic-claude' 'topic-claude-code' 'topic-code-review' 'topic-developer-tools' 'topic-devops' 'topic-productivity' 'topic-prompt-engineering' 'topic-python' 'track':389 'transit':332 'true':950,952,954,956,958,960,962,964 'ts':15 'tsc':1004 'tsconfig.json':760,933 'tsup':666 'tsx':641 'type':38,746,780,979,1035,1039,1262 'typecheck':1003 'types.ts':744 'types/bun':626 'types/node':640 'typescript':2,5,33,144,208,270,435,437,546,625,639,654,687,777,851,896,1009,1059,1130,1216 'typescript-project':1 'underscor':164 'unifi':368 'unknown':1051,1083,1114 'unless':103 'unus':111,161,232 'updat':213,243,296,308,325,698,721 'upgrad':701 'url':456,830,832 'usag':215,298,319,393,436,1123 'use':11,96,178,312,353,447,511,523,614,628,673,696,723,772 'user':278,300,500,878,913,921,1126,1166,1172,1179,1189,1200,1207 'user.create':883 'user.email':1181 'user.fromrow':928 'user.name':313 'userid':1127 'userrepo':859 'userrepositori':860,902 'userservic':855,1141,1149,1152,1162 'util':733,1232 'valid':48,656,1006,1042,1108,1119,1168,1248 'validateinput':1047 'version':262,670,677,977 'via':588 'vitest':662 'vitest/bun':77 'warn':340 'watch':987 'without':385 'workaround':136 'y':632 'z':1011 'z.infer':1041 'z.number':1030 'z.object':1019 'z.string':1021,1024 'z.zodtype':1049 'zod':45,621,635,657,682,1008,1013,1245","prices":[{"id":"1e0ab459-93f8-4087-9012-892857574b66","listingId":"61c3e7b7-0376-499b-bb2f-87e31e37a492","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"majiayu000","category":"claude-arsenal","install_from":"skills.sh"},"createdAt":"2026-04-18T22:24:33.695Z"}],"sources":[{"listingId":"61c3e7b7-0376-499b-bb2f-87e31e37a492","source":"github","sourceId":"majiayu000/claude-arsenal/typescript-project","sourceUrl":"https://github.com/majiayu000/claude-arsenal/tree/main/skills/typescript-project","isPrimary":false,"firstSeenAt":"2026-04-18T22:24:33.695Z","lastSeenAt":"2026-05-01T07:01:17.298Z"}],"details":{"listingId":"61c3e7b7-0376-499b-bb2f-87e31e37a492","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"majiayu000","slug":"typescript-project","github":{"repo":"majiayu000/claude-arsenal","stars":29,"topics":["agent-skills","ai-agents","ai-coding-assistant","automation","claude","claude-code","code-review","developer-tools","devops","productivity","prompt-engineering","python","software-development","typescript","workflows"],"license":"mit","html_url":"https://github.com/majiayu000/claude-arsenal","pushed_at":"2026-04-29T04:12:22Z","description":"52 production-ready Claude Code skills and 7 specialized agents for software development, DevOps, product workflows, and automation.","skill_md_sha":"17a6bdc1b3bab617923fb93843c7c2c5acb514b7","skill_md_path":"skills/typescript-project/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/majiayu000/claude-arsenal/tree/main/skills/typescript-project"},"layout":"multi","source":"github","category":"claude-arsenal","frontmatter":{"name":"typescript-project","description":"Modern TypeScript project architecture guide for 2025. Use when creating new TS projects, setting up configurations, or designing project structure. Covers tech stack selection, layered architecture, and best practices."},"skills_sh_url":"https://skills.sh/majiayu000/claude-arsenal/typescript-project"},"updatedAt":"2026-05-01T07:01:17.298Z"}}