build-free-types
Enables type safety in vanilla JavaScript using JSDoc, eliminating the need for a separate build or compilation step.
Install
mkdir -p .claude/skills/build-free-types && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/2302" && unzip -o skill.zip -d .claude/skills/build-free-types && rm skill.zipInstalls to .claude/skills/build-free-types
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Use when the user asks to "set up types without a build step", "use vanilla JS with types", "configure erasable syntax", or mentions "JSDoc type checking". It provides instructions for modern type safety using JSDoc in browsers and native TypeScript execution in Node.js.Key capabilities
- →Configure JSDoc type checking for browser code
- →Enable native TypeScript execution in Node.js
- →Enforce erasable syntax for build-free projects
- →Manage type checking via a single root tsconfig.json
How it works
It configures the TypeScript compiler to check JavaScript files using JSDoc and enables native execution of TypeScript files in Node.js by enforcing erasable syntax.
Inputs & outputs
When to use build-free-types
- →Set up types without a build step
- →Enable JSDoc type checking in VS Code
- →Configure vanilla JS for type safety
About this skill
Modern Type Checking (No Build Step)
Configure projects for type safety without a compilation step (tsc/build) by leveraging JSDoc for browser code and Erasable Syntax for Node.js.
Core Philosophy
- Browser (Client-side): Use pure
.jsfiles with JSDoc annotations. This ensures the code runs directly in the browser while maintaining full IDE type support and error checking. - Node.js (Server-side/Tooling): Use
.tsfiles with Erasable Syntax. This allows Node.js (v24.11.0+) to execute TypeScript files directly without a build step, provided they don't use non-erasable features like enums or namespaces.
Configuration Standards
Apply these settings to enable seamless type checking.
1. package.json
Ensure the project is an ES Module and specifies a modern Node.js version.
{
"type": "module",
"engines": {
"node": ">=24.11.0"
},
"scripts": {
"typecheck": "tsc --noEmit"
}
}
2. tsconfig.json
Configure the TypeScript compiler to check JavaScript files and enforce erasable syntax.
{
"compilerOptions": {
"target": "esnext",
"module": "nodenext",
/* Node.js - Native TS Execution Flags */
"erasableSyntaxOnly": true, /* Prevents using unsupported TypeScript features. */
"verbatimModuleSyntax": true, /* Enforces explicit type imports: https://nodejs.org/api/typescript.html#importing-types-without-type-keyword */
"allowImportingTsExtensions": true, /* Allows 'import x from "./file.ts"' */
"rewriteRelativeImportExtensions": true, /* Handle the import adjustment if compiling to JS */
/* Type Checking Strategy */
"noEmit": true,
"allowJs": true,
"checkJs": true,
"strict": true,
"skipLibCheck": true
}
}
[!WARNING] Anti-Pattern: Avoid explicit
includefields Do NOT add anincludearray orfilesblock to thetsconfig.jsonunless previously requested or strictly required to isolate specific directories. Explicitincludefields are an anti-pattern because they override the default behavior (which natively scans all project files), leading to missing coverage when new files or extensions (like.mjs) are added later.
[!WARNING] Anti-Pattern: Avoid fragmented sub-package TSConfigs Just because a monorepo workspace has multiple child
package.jsonfiles (e.g., for publishing or dependency isolation), do NOT assume they each require their own localizedtsconfig.json. It is fundamentally best practice to manage all typechecking via a Single Unified Roottsconfig.jsonthat covers the entire repository. This prevents cross-package path resolution friction and avoids massive script redundancy when running full-repo checks.
Coding Rules
Follow these rules to maintain a build-free environment.
Browser Rules (.js files)
- Use JSDoc for all types: Define variable types, function signatures, and complex objects using JSDoc comments.
- Avoid TS-specific syntax: Do not use
interface,typealiases, or other TypeScript-only syntax in.jsfiles. - Import types correctly: Do NOT use the legacy typedef import (
/** @typedef {import('./types.js').User} User */). Use the modern TS 5.5+ style:/** @import {User} from './types.js' */.
Node.js Rules (.ts files)
- Strictly use Erasable Syntax: Avoid features that require transformation.
- ❌ No
enum - ❌ No
namespaces - ❌ No parameter properties in constructors
- ❌ No
experimentalDecorators
- ❌ No
- Include file extensions: Always include the
.tsextension in import paths:import { x } from './utils.ts'. - Use
import type: Explicitly mark type-only imports to satisfyverbatimModuleSyntax. - Once implemented, add to project docs/guidelines that agents should NOT use
npx tsxorts-nodeto run node scripts; instead, just run them directly:node script.ts.
Programmatic Type Stripping API
Node.js (v22.6.0+) exposes its internal TypeScript type stripping engine programmatically via node:module. This is useful for tool builders and runtime scripts that need to transpile TypeScript code programmatically.
import { stripTypeScriptTypes } from 'node:module';
const tsCode = 'const user: string = "Alice"; console.log(user);';
// 1. Default mode ('strip'): preserves spacing/offsets, throws error if sourceMap: true is set
const jsCodeStripped = stripTypeScriptTypes(tsCode);
// "const user = \"Alice\"; console.log(user);"
// 2. Transform mode ('transform'): removes extra whitespace, supports inline source maps
const jsCodeTransformed = stripTypeScriptTypes(tsCode, {
mode: 'transform',
sourceMap: true,
sourceUrl: 'index.ts'
});
Type Design & Analysis Principles
When working with types (whether in TS or via JSDoc), apply these principles to ensure high-quality type design:
Analysis Framework
Evaluate types across these dimensions:
- Encapsulation: Hide implementation details. Don't let invariants be violated from outside.
- Invariant Expression: Express constraints clearly in the type structure. Make illegal states unrepresentable.
- Invariant Usefulness: Ensure invariants prevent real bugs and model the domain accurately.
- Invariant Enforcement: Enforce constraints at construction or via type guards. Prefer compile-time guarantees over runtime checks.
Key Practices for Buildless Types
- Discriminated Unions: Use them over enums (especially in TS where enums are non-erasable).
- Modern JSDoc Imports: Use
@importto bring in strong types from.d.tsor external packages. - Pragmatism: Value pragmatism over perfection. Use types to prevent bugs, not just to satisfy the compiler.
Example Files
examples/tsconfig.json- A complete type-checking configuration.
When not to use it
- →Projects requiring non-erasable features like enums or namespaces
- →Projects where explicit include fields are strictly required for directory isolation
Prerequisites
Limitations
- →Cannot use non-erasable TypeScript features like enums
- →Requires strict adherence to file extension rules in imports
How it compares
Unlike traditional setups that require a build step like tsc, this approach uses native runtime execution and IDE-based type checking.
Compared to similar skills
build-free-types side by side with the closest alternatives in the catalog.
Try saying
Example prompts that trigger this skill in your AI assistant.
More by paulirish
View all by paulirish →You might also like
nia-docs
parcadei
Search library documentation and code examples via Nia
zustand
lobehub
Zustand state management guide. Use when working with store code (src/store/**), implementing actions, managing state, or creating slices. Triggers on Zustand store development, state management questions, or action implementation.
turborepo
vercel
Turborepo monorepo build system guidance. Triggers on: turbo.json, task pipelines, dependsOn, caching, remote cache, the "turbo" CLI, --filter, --affected, CI optimization, environment variables, internal packages, monorepo structure/best practices, and boundaries. Use when user: configures tasks/workflows/pipelines, creates packages, sets up monorepo, shares code between apps, runs changed/affected packages, debugs cache, or has apps/packages directories.
vitest
antfu
Vitest fast unit testing framework powered by Vite with Jest-compatible API. Use when writing tests, mocking, configuring coverage, or working with test filtering and fixtures.
typescript-write
metabase
Write TypeScript and JavaScript code following Metabase coding standards and best practices. Use when developing or refactoring TypeScript/JavaScript code.
react
lobehub
React component development guide. Use when working with React components (.tsx files), creating UI, using @lobehub/ui components, implementing routing, or building frontend features. Triggers on React component creation, modification, layout implementation, or navigation tasks.