| name | ts-library |
| description | Use when authoring TypeScript libraries or npm packages - covers project setup, package.json exports, Rollup-first build tooling, API design patterns, type inference tricks, testing, and publishing to npm. Use when bundling, preserving published package contracts, configuring dual CJS/ESM output, or setting up release workflows. |
TypeScript Library Development
Patterns for authoring high-quality TypeScript libraries, extracted from studying unocss, shiki, unplugin, vite, vitest, vueuse, zod, trpc, drizzle-orm, and more.
When to Use
- Starting a new TypeScript library (single or monorepo)
- Setting up package.json exports for dual CJS/ESM
- Configuring tsconfig for library development
- Choosing build tools, especially Rollup for stable published packages
- Designing type-safe APIs (builder, factory, plugin patterns)
- Writing advanced TypeScript types
- Setting up vitest for library testing
- Configuring release workflow and CI
For Nuxt module development: use nuxt-modules skill
Quick Reference
Loading Files
Consider loading these reference files based on your task:
DO NOT load all files at once. Load only what's relevant to your current task.
Published Package Rule
- For an existing published library, inspect the current
package.json exports, npm pack output, and all documented subpaths before changing the builder.
- If exact filenames, flat subpaths, or legacy typings must remain stable, prefer Rollup over convention-driven builders.
- Treat changes to entry filenames, export-map ordering, or declaration layout as package-contract changes that must be verified from a packed consumer install.
New Library Workflow
- Create project structure → load .claude/skills/ts-library/references/project-setup.md
- For published packages, inspect the current export map and packed tarball before changing builders
- Configure
package.json exports → load .claude/skills/ts-library/references/package-exports.md
- Set up build with Rollup by default → load .claude/skills/ts-library/references/build-tooling.md
- Verify build:
pnpm build && npm pack --json --ignore-scripts — check output includes the exact expected .esm.js, .cjs.js, and .d.ts public entry points
- Add package-contract tests and clean-consumer checks → load .claude/skills/ts-library/references/testing.md
- Configure release → load .claude/skills/ts-library/references/release.md
Quick Start
{
"name": "my-lib",
"main": "./dist/index.cjs.js",
"module": "./dist/index.esm.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.esm.js",
"require": "./dist/index.cjs.js"
}
},
"files": ["dist"]
}
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from 'rollup-plugin-typescript2';
import dts from 'rollup-plugin-dts';
export default [
{
input: 'src/index.ts',
output: [
{ file: 'dist/index.cjs.js', format: 'cjs', exports: 'named' },
{ file: 'dist/index.esm.js', format: 'es' },
],
plugins: [
resolve({ mainFields: ['module', 'main'] }),
commonjs(),
typescript({
tsconfig: './tsconfig.build.json',
useTsconfigDeclarationDir: true,
}),
],
},
{
input: 'dist/types/index.d.ts',
output: { file: 'dist/index.d.ts', format: 'es' },
plugins: [dts()],
},
];
Key Principles
- Preserve existing published paths and typings unless the user explicitly wants a package-contract migration
- Dual format: always support both CJS and ESM consumers
- Prefer Rollup when exact filenames, flat subpaths, or multiple public entry points must stay stable
- Use a dedicated build tsconfig when declaration emit needs different compiler settings than local typechecking
- Smart defaults: detect environment, don't force config
- Verify from a packed tarball and a clean consumer install, not just from repo-local imports
- Tree-shakeable: lazy getters, proper
sideEffects: false
Token efficiency: Main skill ~300 tokens, each reference ~800-1200 tokens