mcpField
T
type-fest

type-fest

github.com/izidorome开发0151 次安装40 周前更新
代码仓库

关于 type-fest

type-fest 是面向 TypeScript 开发者的编译期工具类型集合,提供 180 多种类型操作且不产生运行时开销。它适用于内置工具类型不足以表达复杂转换或严格约束的场景。

主要功能

  1. 01提供 180 多种编译期工具类型
  2. 02支持深层可选与只读转换
  3. 03支持对象合并和严格键筛选
  4. 04提供 JSON 与命名格式转换
  5. 05支持路径和异步返回类型提取

适用场景

  1. 01转换 API 请求与响应类型
  2. 02定义嵌套配置更新类型
  3. 03为不可变状态添加深层只读约束
  4. 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 → string
  • Map、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(无自动补全)
解包 PromiseAsyncReturnType<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

资源

评论

支持 Markdown