sindresorhus/type-fest
A collection of essential TypeScript types
Healthy across the board
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 2w ago
- ✓17 active contributors
- ✓Distributed ownership (top contributor 45% of recent commits)
- ✓CC0-1.0 licensed
- ✓CI configured
- ✓Tests present
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the “Healthy” badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/sindresorhus/type-fest)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/sindresorhus/type-fest on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: sindresorhus/type-fest
Generated by RepoPilot · 2026-05-06 · Source
Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/sindresorhus/type-fest shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
Verdict
GO — Healthy across the board
- Last commit 2w ago
- 17 active contributors
- Distributed ownership (top contributor 45% of recent commits)
- CC0-1.0 licensed
- CI configured
- Tests present
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live sindresorhus/type-fest
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/sindresorhus/type-fest.
What it runs against: a local clone of sindresorhus/type-fest — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in sindresorhus/type-fest | Confirms the artifact applies here, not a fork |
| 2 | License is still CC0-1.0 | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 41 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of sindresorhus/type-fest. If you don't
# have one yet, run these first:
#
# git clone https://github.com/sindresorhus/type-fest.git
# cd type-fest
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of sindresorhus/type-fest and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "sindresorhus/type-fest(\\.git)?\\b" \\
&& ok "origin remote is sindresorhus/type-fest" \\
|| miss "origin remote is not sindresorhus/type-fest (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(CC0-1\\.0)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"CC0-1\\.0\"" package.json 2>/dev/null) \\
&& ok "license is CC0-1.0" \\
|| miss "license drift — was CC0-1.0 at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "index.d.ts" \\
&& ok "index.d.ts" \\
|| miss "missing critical file: index.d.ts"
test -f "source/internal/array.d.ts" \\
&& ok "source/internal/array.d.ts" \\
|| miss "missing critical file: source/internal/array.d.ts"
test -f "source/internal/characters.d.ts" \\
&& ok "source/internal/characters.d.ts" \\
|| miss "missing critical file: source/internal/characters.d.ts"
test -f "package.json" \\
&& ok "package.json" \\
|| miss "missing critical file: package.json"
test -f ".github/contributing.md" \\
&& ok ".github/contributing.md" \\
|| miss "missing critical file: .github/contributing.md"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 41 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~11d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/sindresorhus/type-fest"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
TL;DR
type-fest is a curated TypeScript utility type library that provides 100+ essential types (like Except, Merge, JsonValue, etc.) that solve common TypeScript problems without standard library equivalents. It exports from index.d.ts and source/*.d.ts as pure type definitions with zero runtime overhead, enabling developers to enforce stricter type safety across their applications. Single-module type library: source/ directory contains ~60+ individual .d.ts files for each type (absolute.d.ts, array-element.d.ts, etc.), all re-exported via index.d.ts. Dual licensing (MIT OR CC0-1.0) in license files. Custom ESLint infrastructure in lint-rules/ validates that types are exported, documented in README, and have valid JSDoc code examples.
Who it's for
TypeScript developers who need battle-tested, well-documented utility types for common patterns like omitting object properties, merging types, extracting union members, or transforming JSON structures. Maintainers of open-source packages who want to provide type-safe APIs without maintaining custom types.
Maturity & risk
Highly mature and production-ready. The project has 592KB of TypeScript code, comprehensive test coverage via tsd (test definition files), ESLint + custom lint processors, and documented CI workflows (main.yml, ts-canary.yml). Recent activity evident from v5.6.0 versioning and enforced strict TypeScript >=5.9 requirement. Sindre Sorhus maintains it with strong community backing.
Very low risk. Single maintainer (Sindre Sorhus) could be a concern, but the library has only 1 dependency (tagged-tag), strong test infrastructure, and types are stable (types don't break as often as runtime code). Main risk: TypeScript language changes could require updates, hence the ts-canary.yml workflow. No breaking changes visible in the mature versioning strategy.
Active areas of work
Active development: latest version v5.6.0, TypeScript 5.9.2 support confirmed. GitHub workflows include claude-code-review.yml and claude.yml (AI-assisted reviews), ts-canary.yml tests against TS nightly builds to catch breaking changes early. Contributing guidelines in .github/contributing.md indicate ongoing PRs for new types are welcome.
Get running
git clone https://github.com/sindresorhus/type-fest.git
cd type-fest
npm install
npm test
Daily commands:
This is a type-only library with no server or build step. Run tests: npm test (executes test:tsc, test:tsd, test:xo, test:linter in parallel via npm-run-all2). Individual test commands: npm run test:tsc (TypeScript compiler check), npm run test:tsd (type tests), npm run test:xo (linting).
Map of the codebase
index.d.ts— Main entry point exporting all public types; every contributor must understand what types are already exported and follow naming conventionssource/internal/array.d.ts— Core internal utility types for array manipulation; frequently reused across dozens of array-related type definitionssource/internal/characters.d.ts— Core internal utility types for string character manipulation; foundation for all case-conversion and string typespackage.json— Defines TypeScript version constraints, build commands, and export structure; critical for understanding build system and API surface.github/contributing.md— Contribution guidelines including type naming conventions and code style requirements for the projectlint-rules/require-exported-types.js— Enforces that all new types in source/ are exported from index.d.ts; prevents accidental API gapslint-rules/readme-jsdoc-sync.js— Validates that all exported types have JSDoc comments synced to README; ensures documentation completeness
How to make changes
Add a New Type Definition
- Create a new file in source/ with pattern source/my-type-name.d.ts containing the type definition with comprehensive JSDoc (
source/my-type-name.d.ts) - Add export statement to index.d.ts to re-export the new type (
index.d.ts) - Add JSDoc example usage in the source file; lint-rules/readme-jsdoc-sync.js will validate consistency (
source/my-type-name.d.ts) - Run lint rules to verify export is registered and JSDoc is valid (
lint-rules/require-exported-types.js)
Add a Case Conversion Type
- Define character transformation logic in source/internal/characters.d.ts for new case pattern (
source/internal/characters.d.ts) - Create source/my-case-format.d.ts that uses the character utilities from internal/characters.d.ts (
source/my-case-format.d.ts) - Create corresponding source/my-case-formatted-properties.d.ts to apply the transformation to object keys (
source/my-case-formatted-properties.d.ts) - Export both types from index.d.ts and verify with test:tsd (
index.d.ts)
Add a New Conditional Type Helper
- Create source/my-conditional.d.ts that extends the pattern from source/if.d.ts or similar conditional types (
source/my-conditional.d.ts) - Add comprehensive JSDoc with example usage covering both true and false branches (
source/my-conditional.d.ts) - Export from index.d.ts and run test:tsd to verify the conditional logic works correctly (
index.d.ts)
Add a New Array or Object Transformation Type
- Determine if helper logic belongs in source/internal/array.d.ts; add generic internal type if reusable (
source/internal/array.d.ts) - Create source/my-transform.d.ts using the internal utilities and conditional types (
source/my-transform.d.ts) - Export from index.d.ts and validate with test:tsc to ensure type checking works (
index.d.ts)
Why these technologies
- TypeScript Declaration Files (.d.ts) — Provides type-only definitions without runtime code; allows distribution as pure type definitions without compilation artifacts
- Custom ESLint Rules — Enforces consistency across 400+ type files (require-exported-types, readme-jsdoc-sync, import-path validation) without runtime overhead
- tsd (Type Definition Testing) — Tests that type definitions work correctly; validates JSDoc code examples compile and produce expected type assertions
- Conditional Types & Distributive Union — Core TypeScript feature enabling advanced type transformations (if, conditional-pick, exclude-exactly, etc.)
Trade-offs already made
-
Pure type-only package with no runtime code
- Why: Reduces package size and eliminates runtime dependencies; types are purely compile-time abstractions
- Consequence: Cannot provide runtime utilities or helpers; must be used only for type definitions
-
Centralized index.d.ts re-export model
- Why: Single source of truth for public API; simplifies discovery and prevents accidental private type exposure
- Consequence: Requires manual export management; lint rule catches missing exports but developer must add them
-
JSDoc as primary documentation with lint sync validation
- Why: Documentation lives in source files; lint-rules/readme-jsdoc-sync ensures README stays in sync with actual types
- Consequence: More maintenance burden but guarantees documentation accuracy as types evolve
-
Internal/ folder for reusable type utilities
- Why: Avoids duplication across 200+ type definitions; shared patterns like ArrayLength, TupleToUnion reduce complexity
- Consequence: Adds indirection and requires understanding internal type APIs; refactoring internal types affects many dependents
Non-goals (don't propose these)
- Does not provide runtime type checking or validation (pure compile-time types only)
- Does not include async utilities or Promise-based type transformations beyond AsyncReturnType
- Does not provide class decorators or metadata reflection utilities
- Does not handle browser APIs or DOM types (those are in lib.dom.d.ts)
- Does not provide GraphQL or REST API type generation utilities
Traps & gotchas
No runtime dependencies mean no lock-file vulnerabilities, but JSDoc examples in .d.ts files are validated by lint rules—malformed examples block the build. TypeScript >=5.9 strict mode is required (enforced in tsconfig); older versions will fail. The tsd test runner uses custom compilerOptions (noUnusedLocals: false) defined in package.json—be aware of this when debugging type tests. Custom Jest-like assertions via expect-type package, not standard TypeScript testing patterns.
Architecture
Concepts to learn
- Conditional Types — Core pattern used throughout type-fest (e.g., If<T extends U, Y, N>) to branch type logic and implement utility types like Extract and Exclude
- Mapped Types — Essential for transforming object keys/values in types like Pick, Omit, and Record; appears in ~40% of source files
- Type Inference with infer — Enables extraction of component types from complex signatures (e.g., ArrayElement infers T from Array<T>)
- Template Literal Types — Used for types that manipulate string literals (case conversion, path building); relevant for several newer types in source/
- Recursive Type Definitions — Required for deep utility types (DeepPartial, DeepReadonly) that need to traverse nested object structures
- Union Type Distribution — Conditional types distribute over union members (e.g., T extends U ? X : Y where T is A | B produces (A extends U ? X : Y) | (B extends U ? X : Y)), critical for correct utility type behavior
- Type Predicates and Guards — Used in types like IsPlainObject and JsonValue to determine type narrowing and assertion, core to runtime type-safety helpers
Related repos
sindresorhus/ts-extras— Companion library providing runtime functions corresponding to type-fest's types, extending this type library with actual implementationsmicrosoft/TypeScript— Upstream project; type-fest types often serve as proposals or workarounds for features requested in TypeScript's issue trackerpiotrwitek/utility-types— Alternative utility type collection with overlapping scope; type-fest is more curated and actively maintainedkrzkaczor/ts-essentials— Another utility types library with similar goal of providing commonly needed TypeScript helpers not in stdlibtotal-typescript/ts-reset— Related ecosystem project that provides global type improvements and augmentations that work alongside type-fest
PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive test coverage for lint-rules using tsd assertions
The lint-rules directory contains custom linting rules (import-path.js, readme-jsdoc-sync.js, require-export.js, etc.) with corresponding .test.js files, but they currently use basic Node.js test assertions. These rules validate TypeScript type exports and documentation sync - critical infrastructure for the repo. Converting these to use tsd's type assertion patterns would make tests more robust and serve as documentation for type validation patterns.
- [ ] Review existing lint-rules/*.test.js files to understand current test coverage gaps
- [ ] Add tsd-based type assertions in source/*.test.d.ts files for types validated by lint-rules/require-exported-types.js
- [ ] Create comprehensive test cases in lint-rules/require-export.test.js covering edge cases (namespaced exports, re-exports, conditionals)
- [ ] Document the test patterns in a new lint-rules/TEST-PATTERNS.md file to help future contributors
Add TypeScript canary test workflow enhancement with specific version matrix
The .github/workflows/ts-canary.yml exists but the repo targets TypeScript 5.9.2 with node >=20. The canary workflow should test against multiple TypeScript minor versions and document known compatibility issues. This prevents type breakages in minor TS releases and helps the community understand compatibility guarantees.
- [ ] Expand .github/workflows/ts-canary.yml to test against TS 5.8.x, 5.9.x, and 5.10.x (canary/next) with a version matrix
- [ ] Add a step that generates a compatibility matrix report and posts it to PR comments using workflow outputs
- [ ] Create docs/TYPESCRIPT-COMPATIBILITY.md documenting which type-fest versions support which TS versions
- [ ] Update .github/ISSUE_TEMPLATE/2 bug report.yml to require TypeScript version in bug reports
Create integration tests for deeply nested types in source/conditional-simplify-deep.d.ts and similar files
The repo has complex recursive types like conditional-simplify-deep, camel-cased-properties-deep, and conditional-pick-deep, but their test coverage appears minimal. These types are particularly error-prone with circular references and deep recursion limits. Adding integration tests would catch performance regressions and edge cases.
- [ ] Create source/integration-tests/deep-types.test.d.ts with type assertion tests for conditional-simplify-deep with 5+ nesting levels
- [ ] Add tests for camel-cased-properties-deep and delimiter-cased-properties-deep with circular object patterns
- [ ] Include performance/compile-time regression tests using tsd's performance benchmarking
- [ ] Document any known limitations (e.g., max nesting depth) in source/*/comments within each deep-type file
Good first issues
- Add comprehensive test cases in source/array-flatten.d.ts using @example JSDoc blocks and tsd assertions, as many types lack sufficient test coverage beyond basic compilation.
- Expand readme.md with a 'common patterns' section showing real-world usage of Merge + Except together, or document the differences between JsonValue and similar JSON-serialization types—this addresses docs gaps.
- Implement a new utility type like DeepRequired or DeepReadonly (proposed in TypeScript issues) with proper JSDoc examples, lint rule validation, and README integration to demonstrate the full contribution workflow.
Top contributors
- @som-sm — 45 commits
- @sindresorhus — 27 commits
- @taiyakihitotsu — 7 commits
- @derodero24 — 4 commits
- @benzaria — 3 commits
Recent commits
c46020d—ApplyDefaultOptions: Fix behavior with generic instantiations &anyvalues (#1411) (som-sm)9ea810b—ExtendsStrict: AdddistributiveUnions,strictNever&strictAnyoptions (#1408) (som-sm)60bfd3f—ApplyDefaultOptions: Fix behavior with explicitundefined(#1407) (som-sm)a549164— 5.6.0 (sindresorhus)5ca6564—CamelCase: AddpreserveLeadingUnderscoresoption (#1404) (obarcelonap)ac4861d—TsConfigJson: Add TypeScript 6.0 fields (#1406) (ntnyq)49142db— AddUnionLengthtype (#1402) (som-sm)651f7ea—UnionToTuple: Fix behavior with large unions (#1405) (som-sm)d0bbbbe— Add lint rule to validate type descriptions in README (#1396) (som-sm)1e8bd10— AddNonNullableDeeptype (#1401) (som-sm)
Security observations
The type-fest repository demonstrates a strong security posture with no critical or high-severity vulnerabilities detected. This is a TypeScript type definitions library with minimal runtime code and no input handling, reducing attack surface significantly. The codebase includes proper linting, testing infrastructure, and dependency management. Minor recommendations include: (1) implementing pinned dependency versions for better supply chain security, (2) establishing a formal security reporting process, and (3) setting upper bounds on Node.js engine requirements. The use of TypeScript and comprehensive testing (tsc, tsd, xo, and custom linters) provides good code quality controls.
- Low · Dependency: tagged-tag without version pinning —
package.json - dependencies. The dependency 'tagged-tag' is specified with a caret range (^1.0.0) rather than a pinned version. This allows minor and patch updates that could potentially introduce vulnerabilities or breaking changes. While this is common practice, it does increase the attack surface compared to pinned versions. Fix: Consider using pinned versions (exact semver) for critical dependencies, or implement lock file verification in CI/CD pipelines. Regularly audit dependencies using 'npm audit' and 'npm outdated'. - Low · No security policy defined —
.github/security.md (should also consider root SECURITY.md). While a security.md file exists in .github/, there is no explicit SECURITY.md at the repository root which is a standard practice for reporting security vulnerabilities. This may make it harder for security researchers to report issues responsibly. Fix: Create a SECURITY.md file at the repository root following the GitHub security policy template, clearly outlining how to report vulnerabilities privately. - Low · Node version requirement lacks upper bound —
package.json - engines.node. The package.json specifies 'engines.node >= 20' without an upper bound. While this allows forward compatibility, it could introduce issues if Node.js introduces breaking changes or security regressions in future major versions. Fix: Consider specifying a reasonable upper bound or regularly testing against the latest Node.js versions in CI/CD. Example: 'node: >=20,<24' for more controlled updates.
LLM-derived; treat as a starting point, not a security audit.
Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.