.claude/skills/typescript-monorepo/SKILL.md
Configure TypeScript in a Bun/npm workspaces monorepo with shared base config, package-specific overrides, path aliases, and cross-package type sharing. Use when setting up tsconfig files, configuring path aliases, resolving module errors, or sharing types between packages.
npx skillsauth add ftc8569/ftcmetrics typescript-monorepoInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This guide covers TypeScript configuration patterns for monorepos using Bun/npm workspaces, with examples from the FTC Metrics project structure.
ftcmetrics-v2/
tsconfig.base.json # Shared compiler options
package.json # Workspaces: ["packages/*"]
packages/
web/ # Next.js frontend
tsconfig.json # Extends base, adds JSX/DOM
api/ # Hono API server
tsconfig.json # Extends base, adds Node types
db/ # Prisma database package
tsconfig.json # Extends base
shared/ # Shared types and utilities
tsconfig.json # Extends base
src/
index.ts # Re-exports all types
types.ts # Shared type definitions
The tsconfig.base.json at the workspace root defines shared compiler options:
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022"],
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"declaration": true,
"declarationMap": true
}
}
| Option | Value | Purpose |
|--------|-------|---------|
| target | ES2022 | Modern JS output with top-level await, class fields |
| module | ESNext | Native ESM with dynamic imports |
| moduleResolution | bundler | For bundlers (Bun, Vite, Next.js) |
| strict | true | Enables all strict type checks |
| isolatedModules | true | Required for bundlers/transpilers |
| skipLibCheck | true | Faster builds, skip .d.ts checking |
| declaration | true | Generate .d.ts for package consumers |
| declarationMap | true | Source maps for .d.ts files |
packages/web/tsconfig.json:
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"lib": ["dom", "dom.iterable", "ES2022"],
"jsx": "preserve",
"module": "ESNext",
"moduleResolution": "bundler",
"plugins": [{ "name": "next" }],
"paths": {
"@/*": ["./src/*"]
},
"incremental": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
Additions:
lib: ["dom", "dom.iterable"] - Browser APIsjsx: "preserve" - Let Next.js handle JSX transformationpaths - Local import aliases (@/components/...)plugins - Next.js TypeScript plugin for route typingpackages/api/tsconfig.json:
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src",
"types": ["node"]
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
Additions:
types: ["node"] - Node.js type definitionsoutDir/rootDir - Build output configurationpackages/shared/tsconfig.json:
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
For imports within the same package, use paths in tsconfig:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@/lib/*": ["./src/lib/*"],
"@/components/*": ["./src/components/*"]
}
}
}
Usage:
import { Button } from "@/components/Button";
import { fetchApi } from "@/lib/api";
For importing from other packages, use workspace dependencies in package.json:
{
"dependencies": {
"@ftcmetrics/shared": "workspace:*",
"@ftcmetrics/db": "workspace:*"
}
}
Usage:
import { Team, ApiResponse } from "@ftcmetrics/shared";
import { prisma } from "@ftcmetrics/db";
packages/shared/package.json:
{
"name": "@ftcmetrics/shared",
"main": "./src/index.ts",
"types": "./src/index.ts"
}
packages/shared/src/index.ts:
// Re-export all types
export * from './types';
export * from './constants';
export * from './utils';
packages/shared/src/types.ts:
// Domain types
export type TeamRole = 'mentor' | 'member';
export type SharingLevel = 'private' | 'event' | 'public';
export interface Team {
id: string;
teamNumber: number;
name: string;
sharingLevel: SharingLevel;
createdAt: Date;
}
// API response wrapper
export interface ApiResponse<T> {
success: boolean;
data?: T;
error?: string;
}
// In packages/api/src/routes/teams.ts
import type { Team, ApiResponse } from "@ftcmetrics/shared";
function getTeam(id: string): Promise<ApiResponse<Team>> {
// ...
}
Extend third-party types using declaration files:
packages/web/src/types/next-auth.d.ts:
import { DefaultSession } from "next-auth";
declare module "next-auth" {
interface Session {
user: {
id: string;
} & DefaultSession["user"];
}
}
The strict: true flag enables these checks:
| Flag | What It Catches |
|------|-----------------|
| strictNullChecks | Null/undefined access errors |
| strictFunctionTypes | Incorrect callback parameter types |
| strictBindCallApply | Wrong arguments to bind/call/apply |
| strictPropertyInitialization | Uninitialized class properties |
| noImplicitAny | Missing type annotations |
| noImplicitThis | Ambiguous this context |
| useUnknownInCatchVariables | Catch variables typed as unknown |
| alwaysStrict | Emits "use strict" in JS output |
Error: Cannot find module '@ftcmetrics/shared'
Fix: Ensure workspace dependency is added:
bun add @ftcmetrics/shared@workspace:*
Error: Cannot find module '@/lib/api'
Fix: Ensure baseUrl is set when using paths:
{
"compilerOptions": {
"baseUrl": ".",
"paths": { "@/*": ["./src/*"] }
}
}
Error: Type 'import("pkg-a").Team' is not assignable to type 'import("pkg-b").Team'
Fix: Import from the shared package, not duplicate definitions:
// Wrong: duplicate type
interface Team { ... }
// Right: import from shared
import type { Team } from "@ftcmetrics/shared";
Error: Types not available to consumers
Fix: Enable declarations in tsconfig:
{
"compilerOptions": {
"declaration": true,
"declarationMap": true
}
}
Error: Catch clause variable is of type 'unknown'
Fix: Type-narrow the error:
try {
// ...
} catch (error) {
if (error instanceof Error) {
console.error(error.message);
}
}
Error: Cannot find name 'fetch'
Fix: Add to lib or use node-fetch:
{
"compilerOptions": {
"lib": ["ES2022", "DOM"]
}
}
Or with Node 18+:
{
"compilerOptions": {
"types": ["node"]
}
}
Error: Cannot find module './config.json'
Fix: Enable JSON imports:
{
"compilerOptions": {
"resolveJsonModule": true
}
}
# Type check all packages
bun run typecheck
# Type check specific package
bun run --filter @ftcmetrics/web typecheck
# Type check with verbose output
tsc --noEmit --pretty
@ftcmetrics/sharedtype Imports: Prefer import type { } for type-only imports"incremental": true for faster rebuildsnode_modules, dist, .nextsrc/ folderpackage.json with workspace nametsconfig.json extending base:{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
{
"scripts": {
"typecheck": "tsc --noEmit"
}
}
{
"dependencies": {
"@ftcmetrics/shared": "workspace:*"
}
}
development
Tailwind CSS styling for FTC Metrics with official FIRST colors and component patterns. Use when styling React components, creating responsive layouts, or implementing dark mode.
development
Configure and integrate Soketi WebSocket server with FTC Metrics for real-time updates. Use when setting up WebSocket connections, broadcasting scouting data changes, implementing presence channels for team collaboration, or debugging real-time features.
development
Create, structure, and optimize skills for the FTC Metrics project. Use when creating a new skill, improving an existing skill, or needing guidance on skill design patterns, triggers, frontmatter, and progressive disclosure.
data-ai
Configure and use Prisma 7 ORM with PostgreSQL driver adapters in the FTC Metrics project. Use when setting up database schemas, running migrations, troubleshooting Prisma configuration, or working with the packages/db package.