关于 type-fest
type-fest 是面向 TypeScript 开发者的编译期工具类型集合,提供 180 多种类型操作且不产生运行时开销。它适用于内置工具类型不足以表达复杂转换或严格约束的场景。
主要功能
- 01提供 180 多种编译期工具类型
- 02支持深层可选与只读转换
- 03支持对象合并和严格键筛选
- 04提供 JSON 与命名格式转换
- 05支持路径和异步返回类型提取
适用场景
- 01转换 API 请求与响应类型
- 02定义嵌套配置更新类型
- 03为不可变状态添加深层只读约束
- 04为 JSON 序列化结果提供类型
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ izidorome/ skills --skill type-fest安装后在 Claude Code 中输入/type-fest确认已加载。
详细介绍
type-fest:高级 TypeScript 工具类型
type-fest 为生产环境中的 TypeScript 应用提供 180 多种编译时工具类型,运行时开销为零。当 TypeScript 内置工具无法满足严格的类型操作、深层转换或复杂的类型级编程需求时,可以使用它。
何时使用此技能
适用于:
- API 响应/请求类型转换(snake_case ↔ camelCase)
- 深层配置合并和部分更新
- 通过只读保证实现不可变状态管理
- JSON 序列化类型安全(Date → string 等)
- 严格检查对象属性的移除/选择
- 类型安全的路径访问和属性选择
- 提取异步函数的返回类型
- 条件类型操作
不适用于:
- 运行时验证(使用 zod/yup/io-ts;type-fest 仅用于编译时)
- 可由内置
Partial、Pick、Omit满足的简单场景 - 运行时类型守卫(将 type-fest 与运行时检查结合使用)
安装
npm install type-fest
为获得最佳的 tree-shaking 效果,请按需导入:
import type {Except, Merge, PartialDeep, Jsonify} from 'type-fest';
核心工具类型
Except<T, K> - 严格移除属性
适用场景: 在编译时验证的同时从对象中移除键。
相比 Omit 的优势: 可以捕获拼写错误;要求要移除的键确实存在。
import type {Except} from 'type-fest';
interface User {
id: number;
email: string;
password: string;
role: string;
}
// Remove sensitive fields for public API
type PublicUser = Except<User, 'password'>;
// Result: { id: number; email: string; role: string }
// Catches typos
type Bad = Except<User, 'pasword'>; // ✗ Error: 'pasword' doesn't exist
// Strict mode prevents re-adding omitted props
type StrictPublic = Except<User, 'password', {requireExactProps: true}>;
Merge<T, U> - 类型安全的对象合并
适用场景: 合并类型,其中第二个类型的属性会覆盖第一个类型的属性。
import type {Merge} from 'type-fest';
interface BaseConfig {
host: string;
port: number;
timeout: number;
}
interface ProdOverrides {
port: 3306; // Literal type
ssl: boolean;
poolSize: number;
}
type ProdConfig = Merge<BaseConfig, ProdOverrides>;
// Result: { host: string; port: 3306; timeout: number; ssl: boolean; poolSize: number }
PartialDeep<T> - 递归可选属性
适用场景: 深层配置对象或嵌套的部分更新。
import type {PartialDeep} from 'type-fest';
interface AppSettings {
theme: {
colors: {
primary: string;
secondary: string;
};
fontSize: number;
};
features: {
autoSave: boolean;
};
}
// User can override any nested property
function updateSettings(updates: PartialDeep<AppSettings>) {
// updates.theme?.colors?.primary is allowed
}
// Valid calls
updateSettings({theme: {colors: {primary: '#ff0000'}}});
updateSettings({features: {autoSave: false}});
updateSettings({theme: {fontSize: 16}});
Jsonify<T> - JSON 序列化类型
适用场景: 为经过 JSON 序列化的 API 响应/请求添加类型。
功能:
Date→stringMap、Set→{}- 函数、
undefined→ 移除 - 递归转换嵌套类型
import type {Jsonify} from 'type-fest';
interface Activity {
userId: number;
timestamp: Date;
metadata: Map<string, string>;
handler: () => void;
}
type ApiActivity = Jsonify<Activity>;
// Result: { userId: number; timestamp: string; metadata: {} }
// (handler and Map removed, Date → string)
async function fetchActivity(id: string): Promise<Activity> {
const response = await fetch(`/api/activity/${id}`);
const json: ApiActivity = await response.json();
// Reconstruct proper types
return {
userId: json.userId,
timestamp: new Date(json.timestamp), // string → Date
metadata: new Map(),
handler: () => console.log('loaded')
};
}
ReadonlyDeep<T> - 深层不可变性
适用场景: 在状态管理和配置对象中强制实现不可变性。
import type {ReadonlyDeep} from 'type-fest';
interface State {
users: Array<{
id: number;
profile: {name: string};
}>;
}
type ImmutableState = ReadonlyDeep<State>;
const state: ImmutableState = {users: [{id: 1, profile: {name: 'John'}}]};
// All modification attempts cause errors
state.users.push(...); // ✗ Error
state.users[0].profile.name = 'Jane'; // ✗ Error
CamelCase<T> - 大小写转换
适用场景: 将 API/数据库命名转换为 JavaScript 约定的格式。
import type {CamelCase} from 'type-fest';
interface DbUser {
'user-id': number;
'email_address': string;
'created_at': string;
}
type AppUser = {
[K in keyof DbUser as CamelCase<K>]: DbUser[K]
};
// Result: { userId: number; emailAddress: string; createdAt: string }
// Also available: SnakeCase, KebabCase, PascalCase
LiteralUnion<T, U> - 保留自动补全的联合类型
适用场景: 创建可扩展的字符串枚举,同时保留 IDE 自动补全。
解决的问题: 'red' | 'blue' | string 会导致 'red' 和 'blue' 无法自动补全。
import type {LiteralUnion} from 'type-fest';
// Without LiteralUnion - no autocomplete
type BadColor = 'red' | 'blue' | 'green' | string;
// With LiteralUnion - IDE autocompletes known values
type Color = LiteralUnion<'red' | 'blue' | 'green', string>;
function setTheme(color: Color) {
// IDE suggests 'red', 'blue', 'green'
// But also accepts '#FF5733', 'custom-color', etc.
}
AsyncReturnType<T> - 解开 Promise 类型
适用场景: 无需手动解开 Promise,即可为异步函数结果添加类型。
import type {AsyncReturnType} from 'type-fest';
async function fetchUser(id: number) {
const res = await fetch(`/api/users/${id}`);
const data = await res.json();
return {
id,
name: data.name,
email: data.email,
roles: data.roles as string[]
};
}
type User = AsyncReturnType<typeof fetchUser>;
// Result: { id: number; name: any; email: any; roles: string[] }
// Use in callbacks
function processUsers(users: User[]) {
users.forEach(u => console.log(u.name));
}
RequireAtLeastOne<T, K> - 条件必填属性
适用场景: 强制要求“这些字段中至少有一个必须存在”。
import type {RequireAtLeastOne} from 'type-fest';
interface SearchParams {
query?: string;
userId?: number;
email?: string;
tags?: string[];
}
type ValidSearch = RequireAtLeastOne<SearchParams, 'query' | 'userId' | 'email'>;
function search(params: ValidSearch) {
// At least one of: query, userId, or email is guaranteed
}
search({query: 'test'}); // ✓
search({userId: 123, tags: ['tag']}); // ✓
search({tags: ['tag']}); // ✗ Error: need query, userId, or email
ConditionalPick<T, Condition> - 按类型选择
适用场景: 提取与特定类型匹配的属性。
import type {ConditionalPick} from 'type-fest';
interface Endpoint {
path: string;
method: 'GET' | 'POST';
timeout: number;
retries: number;
handler: (req: any) => Promise<any>;
validate: (data: any) => boolean;
}
// Extract only functions
type EndpointFns = ConditionalPick<Endpoint, Function>;
// Result: { handler: ...; validate: ... }
// Extract only numbers
type EndpointNums = ConditionalPick<Endpoint, number>;
// Result: { timeout: number; retries: number }
Paths<T> - 类型安全的属性路径
适用场景: 构建类似 lodash 的类型安全 get/set 工具。
import type {Paths} from 'type-fest';
interface Config {
database: {
host: string;
credentials: {
user: string;
password: string;
};
};
api: {endpoint: string};
}
type ConfigPath = Paths<Config>;
// Union: 'database' | 'database.host' | 'database.credentials' |
// 'database.credentials.user' | 'database.credentials.password' |
// 'api' | 'api.endpoint'
function get<P extends ConfigPath>(config: Config, path: P): any {
return path.split('.').reduce((obj: any, key) => obj?.[key], config);
}
get(config, 'database.credentials.user'); // ✓ Autocompletes
get(config, 'invalid.path'); // ✗ Type error
Simplify<T> - 展平交叉类型
适用场景: 改进组合类型在 IDE 中的提示和类型可赋值性。
import type {Simplify} from 'type-fest';
type Position = {x: number; y: number};
type Size = {width: number; height: number};
type Styles = {color: string; opacity: number};
// Without Simplify - IDE shows: Position & Size & Styles
type Complex = Position & Size & Styles;
// With Simplify - IDE shows flat object
type Simple = Simplify<Position & Size & Styles>;
// Result: { x: number; y: number; width: number; height: number; color: string; opacity: number }
常见模式
带类型转换的 API 客户端
import type {Except, Jsonify, CamelCase, AsyncReturnType, ReadonlyDeep} from 'type-fest';
// External API (snake_case)
interface ApiUser {
user_id: number;
email_address: string;
created_at: string;
}
// Internal app (camelCase)
type AppUser = {
[K in keyof ApiUser as CamelCase<K>]: ApiUser[K]
};
// Public user (no sensitive data)
type PublicUser = Except<AppUser, 'emailAddress'>;
// Immutable state
type UserState = ReadonlyDeep<AppUser>;
class UserService {
async getUser(id: number): Promise<AppUser> {
const res = await fetch(`/api/users/${id}`);
const data: Jsonify<ApiUser> = await res.json();
return {
userId: data.user_id,
emailAddress: data.email_address,
createdAt: data.created_at
};
}
}
type User = AsyncReturnType<UserService['getUser']>;
配置管理
import type {PartialDeep, Merge, Simplify} from 'type-fest';
interface BaseConfig {
database: {host: string; port: number};
api: {timeout: number};
}
interface EnvOverrides {
database: {port: 3306};
api: {retries: number};
}
// Merge and flatten
type FinalConfig = Simplify<Merge<BaseConfig, EnvOverrides>>;
function loadConfig(
defaults: BaseConfig,
overrides: PartialDeep<EnvOverrides>
): FinalConfig {
// Deep merge logic
return {...defaults, ...overrides} as FinalConfig;
}
类型安全的构建器
import type {RequireAtLeastOne, Merge} from 'type-fest';
interface BaseRequest {
timeout?: number;
headers?: Record<string, string>;
}
interface RequiredFields {
url: string;
}
type HttpRequest = RequireAtLeastOne<
Merge<RequiredFields, BaseRequest>,
'url'
>;
class HttpClient {
request(config: HttpRequest) {
// config.url guaranteed to exist
fetch(config.url, {
method: 'GET',
headers: config.headers
});
}
}
组合策略
组合使用工具类型,实现强大的类型转换:
import type {Merge, Simplify, PartialDeep, Except} from 'type-fest';
// Base + overrides + flatten
type CleanMerge<T, U> = Simplify<Merge<T, U>>;
// Remove sensitive + deep partial
type SafePartial<T> = PartialDeep<Except<T, 'password' | 'secret'>>;
// Chain multiple operations
type ComplexType = Simplify<
Merge<
Merge<BaseType, OverrideType>,
FinalType
>
>;
重要注意事项
1. 运行时与编译时
关键: type-fest 类型不会在运行时进行验证。
// DON'T assume runtime safety
function process(data: Jsonify<MyType>) {
const date = new Date(data.timestamp); // Could fail if data is malformed
}
// DO add runtime validation
function process(data: Jsonify<MyType>) {
if (typeof data.timestamp !== 'string') {
throw new Error('Invalid timestamp');
}
const date = new Date(data.timestamp);
}
2. 深层类型嵌套限制
避免过度嵌套 PartialDeep/ReadonlyDeep(最多 3–4 层):
// DON'T
type Bad = PartialDeep<PartialDeep<DeepType>>;
// DO
type Good = PartialDeep<DeepType>;
3. 仅导入所需内容
按需导入时,tree-shaking 效果最佳:
// DO
import type {Except, Merge} from 'type-fest';
// DON'T
import type * as TypeFest from 'type-fest';
4. LiteralUnion 的适用范围
不要将它用于已经收窄的类型:
// DON'T
type Bad = LiteralUnion<'active', 'active' | 'inactive'>;
// DO
type Good = LiteralUnion<'active' | 'inactive', string>;
快速参考
| 需求 | type-fest 工具类型 | 替代方案 |
|---|---|---|
| 移除键(严格) | Except<T, K> | Omit<T, K>(宽松) |
| 合并对象 | Merge<T, U> | T & U(交叉类型) |
| 深层可选 | PartialDeep<T> | Partial<T>(浅层) |
| 深层只读 | ReadonlyDeep<T> | Readonly<T>(浅层) |
| JSON 安全类型 | Jsonify<T> | 手动转换 |
| 大小写转换 | CamelCase<T> | 手动映射 |
| 可扩展枚举 | LiteralUnion<T, U> | T | U(无自动补全) |
| 解包 Promise | AsyncReturnType<T> | 手动提取 |
| 要求至少包含部分键 | RequireAtLeastOne<T, K> | 自定义条件类型 |
| 按类型选取 | ConditionalPick<T, C> | 自定义映射类型 |
| 类型路径 | Paths<T> | 字符串字面量 |
| 展平类型 | Simplify<T> | 交叉类型 |
其他工具类型
另有 180 多种工具类型:
RequireExactlyOne- 必须且只能包含一个键SetRequired、SetOptional- 修改单个属性SnakeCase、KebabCase、PascalCase- 其他大小写转换IsEqual<T, U>- 检查类型相等性Get<T, Path>- 类型安全的属性访问Opaque<T>- 品牌类型PromiseValue<T>- 提取 Promise 值- 以及 170 多种其他专用工具类型
浏览完整列表:https://github.com/sindresorhus/type-fest
资源
- GitHub: https://github.com/sindresorhus/type-fest
- 文档: https://sindresorhus.com/type-fest
- 完整类型列表: 浏览
/source目录 - 示例: 查看测试文件中的用法示例
- 大模型指南: https://context7.com/sindresorhus/type-fest/llms.txt