vue项目中使用ts经验

你用ts干什么

  1. 跟风....
  2. 编写公用方法、全局配置、公用组件,提示调用者别传错参数。
  3. 使用类推推导,避免你拼写错,漏写等低级错误,提前发现问题。
  4. 提前定义类型,梳理开发思路,规划大大纲,避免后面开发偏离原有目标。

代码实战

api函数参数和返回 定义类型

对于这块,大概可以理解成是复制后端接口的入参和结果类型(结果只需要写上自己用得上的字段)

javascript 复制代码
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';

const instance = axios.create({
  baseURL: baseUrl,
  timeout: 30 * 1000,
  headers: {
    'Content-Type': 'application/json;charset=UTF-8',
  },
});

// 请求拦截器,一般是添加token, 格式化参数
instance.interceptors.request.use(
  (config: AxiosRequestConfig) => {
    config.headers = {
      Authorization: getToken(),
      ...config.headers,
    };
    // 后端接收json数据
    config.data = JSON.stringify(config.data);
    return config;
  },
  (error) => {
    // 对请求错误做些什么
    return Promise.reject(error);
  },
);

// 响应拦截器,一般用于全局错误提示,特殊状态码判断跳转
service.interceptors.response.use((response: AxiosResponse) => {
  const { code, message, data } = response.data
 
  // 根据自定义错误码判断请求是否成功
  if (code === 0) {
    // 将组件用的数据返回
    return data
  } else {
    // 处理业务错误。
    Message.error(message)
    return Promise.reject(new Error(message))
  }
}, (error: AxiosError) => {
  // 处理 HTTP 网络错误
  let message = ''
  // HTTP 状态码401 403 404 500等状态处理
  const status = error.response?.status
  Message.error(message) 
  return Promise.reject(error)
})

// 接口统一数据结构
interface ApiResult<T> {
  code: number;
  hasError: boolean;
  message: null | string;
  result: T;
}

export default function request<T>(options: AxiosRequestConfig = {}) {
  return new Promise<T>((resolve, reject) => {
    instance(options)
      .then((res: AxiosResponse<ApiResult<T>>) => {
         resolve(res.data.result);
      })
      .catch((err) => {
        reject(err);
      })
  });
}

api文件ts应用

javascript 复制代码
    import request from '@/utils/request';
    
    /* 登录接口参数类型 */
    export interface LoginData {
      username: string,
      password: string,
    }
 
    /* 登录接口返回值类型 */
    export interface LoginRes {
      token: string;
      username: string;
    }
    
    // 登录
    export const loginApi = (data: LoginData) => {
       return request<LoginRes>({ url: "/api/login", method: "GET", params: data });
    }
    

页面使用,就可以看到入参跟响应结构

vue-route 定义类型

  1. 定义跳转添加RouteRecordRaw类型
javascript 复制代码
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";

const routes: RouteRecordRaw[] = [
  {
    path: "/",
    name: "home",
    meta: {
      isAuth: false,
    },
    component: () => import("@/views/home.vue"),
  },
  {
    path: "/detail",
    name: "detail",
    component: () => import("@/views/detail.vue"),
  },
  {
    path: "/list",
    name: "list",
    component: () => import("@/views/list.vue"),
  },
];

const router = createRouter({
  history: createWebHistory(),
  routes: [],
});

router.addRoute({
  path: "/about",
  component: () => import("@/views/about.vue"),
});

const parseRouter = (arr: RouteRecordRaw[]) => {
  arr.forEach((item) => {
    router.addRoute(item);
  });
};

parseRouter(routes);
  1. 自定义meta类型, 在源码中有举例,每个项目的meta可能都不同
  • 添加router-meta.d.ts
javascript 复制代码
project-root/
├─ src/
│  ├─ components/
│  ├─ views/
│  ├─ router/
│  └─ ...
├─ types/
│  └─ router-meta.d.ts
├─ tsconfig.json
└─ ...

// router-meta.d.ts
import 'vue-router'

declare module 'vue-router' {
  interface RouteMeta {
    // 这些字段根据你的项目需求自定义
    requiresAuth?: boolean
    title?: string
    roles?: string[]
  }
}
  • tsconfig.json 引入
json 复制代码
{
  "compilerOptions": {
    // 编译选项
  },
  "include": [
    "src/**/*", // 包含 src 目录下的所有文件
    "types/**/*" // 也包含 types 目录下的所有文件
  ]
}

这样就可以获取meta类型了

定义的时候也可以校验类型

vuex 定义类型

  1. 定义全局store.state类型

通过查看vuex的类型定义文件, 可以发现createStore支持泛型, 这个泛型S对应的就是state的类型

javascript 复制代码
export function createStore<S>(options: StoreOptions<S>): Store<S>;

export interface StoreOptions<S> {
  state?: S | (() => S);
  getters?: GetterTree<S, S>;
  actions?: ActionTree<S, S>;
  mutations?: MutationTree<S>;
  modules?: ModuleTree<S>;
  plugins?: Plugin<S>[];
  strict?: boolean;
  devtools?: boolean;
}

那么就可以提前定义好state的类型,在编写state代码的时候就可以有类型提示了

ts 复制代码
import { createStore } from "vuex";

interface UserProps {
  userName: string;
  token: string;
  isLogin: boolean;
}

interface TemplateItem {
  id: number;
  name: string; 
  coverImg: string;
}

interface GlobalDataProps {
  user: UserProps;
  templates: TemplateItem[];
}

const store = createStore<GlobalDataProps>({
  state: {},
  getters: {},
  actions: {},
  mutations: {},
});

export default store;
  • 不写state的话vscode插件就会提示ts错误
  • state类型补全
user templates
  1. 应用页面

如果是平时的写在js或template模板中无法进行类型推导

实现这个就注意useStore的泛型,ctrl+鼠标点击可以跳转查看文档

javascript 复制代码
   export function useStore<S = any>(injectKey?: InjectionKey<Store<S>> | string): Store<S>;
  1. vux module 模块分割
javascirpt 复制代码
export interface Module<S, R> {
  namespaced?: boolean;
  state?: S | (() => S);
  getters?: GetterTree<S, R>;
  actions?: ActionTree<S, R>;
  mutations?: MutationTree<S>;
  modules?: ModuleTree<R>;
}

模块下面的代码,需要添加Model进行泛型传递才能正常推荐,第一个为当前模块的state类型,后者为全局的

组件props 定义类型

  1. 组件内props定义类型,使用PropTyp传递泛型参数,使得模板获取类型推断

2. 在使用子组件的父组件中,判断传递的prop是否满足,子组件中defineProps使用泛型定义类型

javascirpt 复制代码
export declare function defineProps<PP extends ComponentObjectPropsOptions = ComponentObjectPropsOptions>(props: PP): Readonly<ExtractPropTypes<PP>>;

export declare type ComponentObjectPropsOptions<P = Data> = {
    [K in keyof P]: Prop<P[K]> | null;
};

<template>
  <div class="">
    <div v-for="item in list" :key="item.id">{{ item.name }}</div>
  </div>
</template>

<script setup lang="ts">
import { defineProps } from "vue";
import type { TemplateItem } from "../store/templates";

interface TemplateProps {
  list: TemplateItem[];
  name: string;
}

defineProps<TemplateProps>();
</script>
<style lang="scss" scoped></style>

如果漏传,错传都会提示

日常开发ts报错...

定义一个空对象,但后面会赋值,模板上使用了,就会报错

处理这个只能断言了

dom类型错误

javascript 复制代码
const onClick = (event: MouseEvent) => {
  const target = event.target as HTMLElement;
  console.log(target.tagName); // 访问 tagName 属性来检查元素类型

  // 具体 HTMLElement 子类
  // input 元素
  // const target = event.target as HTMLInputElement; // 如果你知道这是一个 input 元素,可以断言为 HTMLInputElement 类型
  // console.log(target.value); // 现在你可以访问 value 属性了
};

下面是一些常见的具体 HTMLElement 子类,它们代表了不同功能的 HTML 元素:

  • HTMLInputElement - 代表 <input> 元素,包含如 valuecheckedtype 等特有属性和方法。
  • HTMLSelectElement - 代表 <select> 元素,包含如 optionslengthselectedIndex 等特有属性和方法。
  • HTMLTextAreaElement - 代表 <textarea> 元素,包含如 valuerowscols 等特有属性和方法。
  • HTMLButtonElement - 代表 <button> 元素,包含值和状态相关的属性。
  • HTMLAnchorElement - 代表 <a>(锚)元素,包含如 hreftargetdownload 等特有属性和方法。
  • HTMLDivElement - 代表 <div> 元素。
  • HTMLImageElement - 代表 <img> 元素,包含如 srcaltwidthheight 等特有属性和方法。
  • HTMLFormElement - 代表 <form> 元素,包含如 submitreset 方法以及表单相关的属性和方法。
相关推荐
崔庆才丨静觅10 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606111 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了11 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅11 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅11 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅12 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment12 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅12 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊12 小时前
jwt介绍
前端
爱敲代码的小鱼12 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax