type-fest review
type-fest 5.8.0 is a declaration-only set of TypeScript utility types. It covers stricter object omission, deep transforms, tagged values, JSON-safe shapes, path types, exclusive properties, string manipulation, package.json, and tsconfig data. Nothing in the package runs after compilation. Version 5.8.0 adds `StringToArray`, `StringLength`, `StringToNumber`, and `ExtractExactly`, extends `StringRepeat`, and fixes optional tuple handling plus Schema fields containing `any` or `unknown`. The README requires TypeScript 5.9 or later, ESM conventions, and strict mode.
type-fest 5.8.0 took 0.4 seconds and 2 MB to install in our sandbox, but both Node import forms and the browser bundle failed because the package provides types with no runtime entry point. Add it as a type-only dependency for strict TypeScript 5.9 projects, and leave it out when built-in utilities or a plain domain interface are easier to maintain.
We installed it
| Install | ✓ · 0.4s | 2 packages on disk · 2 MB |
| Import | ✗ | ESM import fails · require() fails · ESM package with exports map |
| Browser | n/a | could not be bundled for the browser (Node-only code, most likely) |
| Types | ✓ | TypeScript types bundled |
| Known vulns | 0 | 0 critical · 0 high · 0 moderate · 0 low (npm audit) |
Answers from our run
Does type-fest install cleanly?
Yes. In a fresh container with an empty cache, npm install type-fest finished in 0.4s, leaving 2 packages and 2 MB on disk. npm audit reported no known vulnerabilities.
Can type-fest run in a browser?
Not directly: esbuild could not bundle it for the browser in our run, which normally means it depends on Node built-ins. Use it on the server, or find a browser-targeted alternative.
Does type-fest work with both ESM and CommonJS?
Neither plain import nor require succeeded in our sandbox, so it needs a bundler or extra setup.
Does type-fest include TypeScript types?
Yes, type declarations ship inside the package, so no @types install is needed.
type-fest or ts-toolbelt: which should you use?
ts-toolbelt: Use it when its larger object, tuple, union, and function type modules better match the type-level work. type-fest 5.8.0 took 0.4 seconds and 2 MB to install in our sandbox, but both Node import forms and the browser bundle failed because the package provides types with no runtime entry point.
When should you not use type-fest?
The compiler is older than TypeScript 5.9, strict mode is disabled, or the project cannot follow the package's ESM requirement.
Discussed on
Use it if
- A strict TypeScript 5.9 project repeatedly needs deep, conditional, branded, or mutually exclusive type transformations.
- A public API benefits from JSON-compatible types, tagged identifiers, or package.json and tsconfig declarations.
- The team wants a reviewed conditional type instead of maintaining the same difficult definition in several packages.
- Intersections and mapped types need `Simplify` so editor hovers show the resulting object shape.
- The compiler is older than TypeScript 5.9, strict mode is disabled, or the project cannot follow the package's ESM requirement.
- You need a parser, validator, conversion, or other runtime function. This package exports declarations and no JavaScript implementation.
- Built-in `Partial`, `Pick`, `Omit`, `Awaited`, `Record`, and explicit interfaces already express the design clearly.
- Type checking is slow or error output is already hard to follow. Recursive deep and path utilities can add instantiation work and noisy diagnostics.
- A library would expose these complex types in its public API and force every consumer onto type-fest's compiler floor and conditional behavior.
Setup reality
We installed type-fest 5.8.0 in a fresh Node 22 Bookworm sandbox. npm completed in 0.4 seconds and left two packages using 2 MB. The package declares one direct dependency, zero peer dependencies, Node 20 or later, and (MIT OR CC0-1.0) licensing. Our measured package reported 1,108 KB unpacked and bundled TypeScript declarations. npm audit found zero vulnerabilities at every severity.
The package is marked ESM and has an exports map containing type declarations only. Under Node 22.23.2, both require('type-fest') and dynamic ESM import('type-fest') failed in our sandbox. An esbuild browser bundle failed too, so there is no browser size to report. These outcomes match a types-only dependency: there is no JavaScript entry point for Node or a browser to execute. Use import type and keep it out of runtime code paths.
The README requires TypeScript 5.9 or later and strict: true. An older compiler can fail inside declaration files even when application code did not change, so align the type-fest pin with the compiler used in CI. Begin with TypeScript's built-in utilities. Apply deep, path, exactness, and union transforms at narrow boundaries, then inspect tsc --extendedDiagnostics if a widely instantiated generic slows editor or build checking.
Every type disappears from emitted JavaScript. Tagged does not check an ID prefix, ReadonlyDeep does not freeze an object, and PackageJson does not validate parsed JSON. Add runtime checks where data crosses a trust boundary. Conditional assignability also changes with inference and compiler releases, so keep positive assignments and @ts-expect-error rejections in type tests before upgrading from 5.8.0.
Patterns
Remove only known object keys strict-omit
import type {Except} from 'type-fest';
type Post = {
id: string;
title: string;
draft: boolean;
};
type PublishedPost = Except<Post, 'draft'>;`Except` can enforce known omitted keys more strictly than a casually widened key union. It changes only static assignability.
Model later object properties winning merge-types
import type {Merge} from 'type-fest';
type Defaults = {
timeout: number;
retries: number;
};
type Overrides = {timeout?: string};
type Config = Merge<Defaults, Overrides>;`Merge` models override precedence. Application code must still perform the actual object spread or merge at runtime.
Describe nested configuration patches partial-deep
import type {PartialDeep} from 'type-fest';
type Settings = {
server: {host: string; port: number};
features: {darkMode: boolean};
};
function applyPatch(patch: PartialDeep<Settings>) {
return mergeSettings(patch);
}Deep optionality can cost more compiler work on large recursive models. Prefer a small explicit patch interface when the accepted fields are known.
Reject nested writes during checking readonly-deep
import type {ReadonlyDeep} from 'type-fest';
type State = {
user: {name: string};
tags: string[];
};
const state: ReadonlyDeep<State> = {
user: {name: 'Ada'},
tags: ['admin'],
};`ReadonlyDeep` does not call Object.freeze. JavaScript can still mutate the value through untyped or cast code.
Change optionality for selected keys selected-optionality
import type {SetOptional, SetRequired} from 'type-fest';
type User = {
id: string;
email: string;
nickname?: string;
};
type NewUser = SetOptional<User, 'id'>;
type CompleteUser = SetRequired<User, 'nickname'>;These helpers preserve every unselected property and state the changed keys directly, which is clearer than stacked mapped intersections.
Flatten an intersection for editor display simplify-intersection
import type {Simplify} from 'type-fest';
type Base = {id: string};
type Named = {name: string};
type User = Simplify<Base & Named>;`Simplify` improves hover presentation and some assignability views. It creates no object and changes no emitted JavaScript.
Separate identifiers with static tags tag-identifiers
import type {Tagged} from 'type-fest';
type UserId = Tagged<string, 'UserId'>;
type OrderId = Tagged<string, 'OrderId'>;
function loadUser(id: UserId) {
return users.get(id);
}
const userId = parseUserId('usr_42');
loadUser(userId);The parser or constructor must validate the string before tagging it. A type assertion can forge either ID with no runtime check.
Restrict a boundary to JSON values json-values
import type {JsonValue} from 'type-fest';
function writePayload(value: JsonValue): string {
return JSON.stringify(value);
}
writePayload({ok: true, items: [1, 2, 3]});`JsonValue` checks static inputs but cannot inspect an `any` value or data received after compilation. Validate untrusted payloads.
Type package.json after validation package-json-type
import type {PackageJson} from 'type-fest';
import {readFile} from 'node:fs/promises';
const raw: unknown = JSON.parse(
await readFile('package.json', 'utf8')
);
const pkg: PackageJson = validatePackageJson(raw);
console.log(pkg.dependencies ?? {});The validation function matters. Casting JSON directly to `PackageJson` would only silence the compiler.
Require exactly one credential form exclusive-properties
import type {MergeExclusive} from 'type-fest';
type ApiKeyAuth = {apiKey: string};
type TokenAuth = {token: string};
type Auth = MergeExclusive<ApiKeyAuth, TokenAuth>;
function connect(auth: Auth) {
// one credential form is allowed
}The type prevents callers from supplying both keys during checking. Runtime input still needs the same exclusivity validation.
Constrain dotted object paths typed-paths
import type {Get, Paths} from 'type-fest';
type Config = {
server: {host: string; port: number};
flags: {darkMode: boolean};
};
function readPath<P extends Paths<Config>>(
value: Config,
path: P,
): Get<Config, P> {
return runtimeGet(value, path) as Get<Config, P>;
}`Paths` and `Get` can be expensive on large recursive shapes. The runtime path walker must match the same dotted-path semantics.
Measure a string literal type string-literal-length
import type {StringLength, StringToArray} from 'type-fest';
type Code = 'ABC42';
type CodeLength = StringLength<Code>;
type CodeCharacters = StringToArray<Code>;
const length: CodeLength = 5;`StringLength` and `StringToArray` are new in 5.8.0. General `string` values remain runtime strings rather than fixed compile-time literals.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| ts-toolbelt | npm | Use it when its larger object, tuple, union, and function type modules better match the type-level work. |
| utility-types | npm | Choose it for an older, smaller collection spanning TypeScript and legacy Flow utility aliases. |
| type-plus | npm | Compare it when you want a different maintained collection of type-level helpers and assertions. |
More utils guides
lru-cache · ajv · p-limit · find-up · js-yaml · zod · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

