1.0.9 • Published 1 year ago

@kiko-yd/easyts v1.0.9

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

EasyTs

一个为 TypeScript 项目设计的智能类型生成工具,适用于 Vue3 + vite 项目,可以自动拦截 API 响应并生成对应的 TypeScript 接口定义,极大提升开发效率。

✨ 特性

  • 🚀 自动拦截 API 响应并生成 TypeScript 接口定义
  • 📁 智能的类型文件管理系统
  • 🔄 智能命名转换和类型推导
  • 🔌 零侵入性集成
  • 💪 完全类型安全
  • 🎯 支持多种类型生成方式

📦 安装

npm install @kiko-yd/easyts

⚙️ Vite 插件配置

vite.config.ts 中添加插件:

import { defineConfig } from "vite";
import { vitePluginEasyTs } from "@kiko-yd/easyts/vite-plugin-easyts";

export default defineConfig({
  plugins: [
    // ... 其他插件
    vitePluginEasyTs(),
  ],
});

🔨 环境区分

EasyTs 针对不同环境提供了智能的功能区分。这种区分的目的是:

  1. 优化生产环境性能

    • 在生产环境中,类型生成和文件操作是完全不必要的,因为 TypeScript 类型仅在开发和编译时使用
    • 禁用这些功能可以减少不必要的文件 I/O 操作和内存使用
    • 避免在生产环境中生成大量临时文件
  2. 保持代码整洁

    • 类型定义文件应该在开发阶段生成并提交到版本控制
    • 避免在生产环境中出现重复或冗余的类型文件
    • 保持项目结构的清晰和可维护性
  3. 类型工具不受影响

    • ModifyFieldsExtendField 这样的类型工具在编译时使用
    • 这些工具不会产生运行时开销,因此在所有环境中都可用
    • 确保在生产环境中仍然可以使用类型扩展和重写功能

开发环境

在开发环境中,EasyTs 提供完整功能:

  • ✅ 自动类型生成
  • ✅ 类型文件管理
  • ✅ 类型工具使用
  • ✅ API 响应拦截
import { createEasyTs } from "@kiko-yd/easyts";

// 开发环境下默认启用所有功能
const easyTs = createEasyTs();
easyTs.start();

// 或者显式启用
const easyTs = createEasyTs({
  enableTypeGeneration: true,
  outputDir: "types/api",
});

生产环境

在生产环境中,EasyTs 自动禁用类型生成相关功能,只保留类型工具:

  • ❌ 自动类型生成(禁用)
  • ❌ 类型文件管理(禁用)
  • ✅ 类型工具使用(可用)
  • ✅ API 响应拦截(可用)
import { createEasyTs, ModifyFields } from "@kiko-yd/easyts";

// 生产环境下自动禁用类型生成
const easyTs = createEasyTs();

// 类型工具在所有环境中可用
type CustomUser = ModifyFields<
  UserData,
  {
    id: string;
    age: string | number;
  }
>;

配置选项

interface EasyTsConfig {
  /**
   * 输出目录,相对于项目的src目录
   * 默认为 'EasyTsApi'
   */
  outputDir?: string;

  /**
   * 可选的 axios 实例
   * 如果不提供,将创建一个新的实例
   */
  axios?: AxiosInstance;

  /**
   * 是否启用类型生成功能
   * 默认在开发环境下启用,生产环境下禁用
   */
  enableTypeGeneration?: boolean;
}

🔨 核心功能

1. createEasyTs

创建 EasyTs 实例,用于自动拦截 API 响应并生成类型定义。

import { createEasyTs } from "@kiko-yd/easyts";

// 基本使用
const easyTs = createEasyTs();
easyTs.start();

// 高级配置
const easyTs = createEasyTs({
  outputDir: "types/api", // 自定义输出目录
  axios: customAxios, // 自定义 axios 实例
});

// 项目实例
import axios from "axios";
import { createEasyTs } from "@kiko-yd/easyts";
const TIMEOUT_DURATION: number = 150000;
const instance: AxiosInstance = axios.create({
  timeout: TIMEOUT_DURATION,
});

const easyTs = createEasyTs({
  outputDir: "Interface",
  axios: instance,
});

easyTs.start();

instance.interceptors.request.use(
  (
    config: InternalAxiosRequestConfig<any>
  ): InternalAxiosRequestConfig<any> => {
    return config;
  },
  (error: AxiosError) => Promise.reject(error)
);

instance.interceptors.response.use(
  (response: AxiosResponse): Promise<any> | AxiosResponse | any => {
    return response.data;
  },
  (error) => {
    const { response } = error;
    return Promise.reject(error);
  }
);

export default instance;

使用场景:

  • 在项目入口文件中初始化,自动监听所有 API 请求
  • 需要自定义类型文件存储位置
  • 使用自定义的 axios 实例时

2. createTypeInCurrentDir

在当前文件目录下快速生成类型定义文件。

import { createTypeInCurrentDir } from "@kiko-yd/easyts";

// 基本使用
const data = await fetchData();
await createTypeInCurrentDir(data, "UserTypes", import.meta.url);

// 导入生成的类型
import type { IGeneratedInterface } from "./UserTypes";

参数说明:

  • data: any - 需要生成类型的数据
  • fileName: string - 类型文件名(无需扩展名)
  • filePath: string - 当前文件路径(使用 import.meta.url)

使用场景:

  • 需要在组件/模块同级目录管理类型定义
  • 快速为已有数据生成类型定义
  • 希望类型文件与业务代码紧密关联

3. createTypeDefinition

将接口定义字符串保存为类型定义文件。

import { createTypeDefinition } from "@kiko-yd/easyts";

// 基本使用
const interfaceString = `
export interface UserData {
  id: number;
  name: string;
  age: number;
}`;

await createTypeDefinition(interfaceString, "UserTypes");
// 生成文件:types/UserTypes.d.ts

参数说明:

  • interfaceString: string - 接口定义字符串
  • fileName?: string - 可选的文件名,默认为 "types"

使用场景:

  • 已有接口定义需要保存为文件
  • 需要将多个接口合并到一个文件
  • 手动编写的接口需要规范化存储

4. getInterface

直接从数据生成 TypeScript 接口定义字符串。

import { getInterface } from "@kiko-yd/easyts";

const data = {
  user: {
    name: "张三",
    age: 25,
    hobbies: ["读书", "游戏"],
  },
  status: "active",
};

const interfaceString = getInterface(data);
console.log(interfaceString);

输出示例:

export interface IGeneratedInterface {
  user: {
    name: string;
    age: number;
    hobbies: string[];
  };
  status: string;
}

使用场景:

  • 需要快速查看数据结构
  • 临时生成接口定义
  • 作为其他类型生成函数的基础

5. 类型重写与扩展

EasyTs 提供了三个实用的类型工具,用于重写或扩展自动生成的接口类型:

import type { OverrideField, ExtendField, ModifyFields } from "@kiko-yd/easyts";

// 假设自动生成的接口如下:
interface UserData {
  id: number;
  name: string;
  age: number;
  roles: string[];
  profile: {
    avatar: string;
    bio: string;
  };
}

// 1. 完全重写单个字段类型
type UserWithStringId = OverrideField<UserData, "id", string>;
// 结果:
// {
//   id: string;  // 类型被完全重写为 string
//   name: string;
//   age: number;
//   ...
// }

// 2. 扩展单个字段类型(联合类型)
type UserWithFlexibleId = ExtendField<UserData, "id", string>;
// 结果:
// {
//   id: number | string;  // 原类型与新类型的联合
//   name: string;
//   age: number;
//   ...
// }

// 3. 一次性修改多个字段类型(推荐)
type CustomUser = ModifyFields<
  UserData,
  {
    id: string; // 完全重写为string
    age: string | number; // 使用联合类型
    roles: number[]; // 修改数组元素类型
    profile: {
      // 重写嵌套对象类型
      avatar: string;
      bio: string;
      socialLinks: string[]; // 添加新字段
    };
  }
>;

使用场景:

  • API 返回的字段类型需要适配多种格式
  • 需要扩展某些字段的类型范围
  • 需要完全重写特定字段的类型
  • 处理后端返回类型与前端实际使用类型不完全匹配的情况
  • 需要批量修改多个字段类型时,使用 ModifyFields

🌰 最佳实践

1. API 请求类型生成

// api/user.ts
import { createEasyTs } from "@kiko-yd/easyts";

const easyTs = createEasyTs();
const axios = easyTs.getAxiosInstance();

// 自动生成类型并使用
export async function getUserInfo() {
  const response = await axios.get("/api/user/info");
  return response.data; // 类型会自动生成到 src/EasyTsApi/UserInfoResponse.ts
}

2. 组件数据类型生成

// components/UserCard.vue
import { createTypeInCurrentDir } from "@kiko-yd/easyts";

// 生成类型
const mockData = {
  title: "用户卡片",
  user: { name: "张三", avatar: "url" },
};

await createTypeInCurrentDir(mockData, "UserCardTypes", import.meta.url);

// 使用生成的类型
import type { IGeneratedInterface as UserCardProps } from "./UserCardTypes";

📝 注意事项

  1. 确保项目中有 src 目录且具有写入权限
  2. createTypeInCurrentDir 必须使用 import.meta.url 作为第三个参数
  3. 生成的类型文件建议加入版本控制
  4. 使用自定义 axios 实例时,确保在 start() 前完成配置
  5. 类型文件名避免使用特殊字符
  6. 使用类型重写工具时,确保字段名称完全匹配
  7. 类型重写不会影响原始生成的类型文件,只在使用时生效
  8. 类型生成功能(如 createTypeDefinitioncreateTypeInCurrentDir)仅在开发环境可用
  9. 生产环境中调用类型生成功能会收到警告并安全返回空字符串
  10. 类型工具(如 ModifyFieldsExtendField)在所有环境中可用
  11. 可以通过 enableTypeGeneration 配置手动控制类型生成功能的启用状态

🤝 贡献

欢迎提交 Issue 和 Pull Request!

📄 许可

MIT

1.0.9

1 year ago

1.0.8

1 year ago

1.0.7

1 year ago

1.0.6

1 year ago

1.0.5

1 year ago

1.0.4

1 year ago

1.0.3

1 year ago

1.0.2

1 year ago

1.0.1

1 year ago

1.0.0

1 year ago