Back to blog
May 07, 2024
3 min read

src文件目录内容有哪些?扩展或修改已存在的TS接口有几种常见方法?

src文件目录

基于React的后台管理系统

地址: slash-admin

查看src上的目录结构

src上的目录结构

  • _mock:在开发过程中,前端应用常常需要模拟后端API返回的数据,特别是在后端接口尚未开发完成的情况下。_mock目录下的文件通常定义了一些模拟的API接口和返回的假数据,以便开发者可以无缝地进行前端功能开发和测试。
  • 123
  • assets:通常会包含项目中使用的所有静态资源,如图片、图标、样式文件(CSS或Sass)和可能的字体文件。这个目录的结构和内容依赖于项目的具体需求和设计。
  • components:这是React项目中最重要的一个目录,包含了项目中所有的React组件。在这个目录下,每个组件通常都会有一个单独的文件夹或文件,组件通常是函数式组件。这些组件被设计为可重用的UI部分,可以在多个页面或其他组件中使用。
  • hooks:在这个目录下存放的是自定义的React Hooks。自定义Hooks可以帮助你将组件逻辑提取到可重用的函数中。
  • layouts:layouts目录通常包含一些定义页面基本结构的组件。这些布局组件用于定义应用中页面的通用布局结构,例如页头(header)、页脚(footer)和侧边栏,使得这些元素可以在不同的页面中保持一致。
  • locales:这个目录用于存放国际化(i18n)相关的文件,比如不同语言的翻译文件。如果项目需要支持多语言,那么locales目录将包含每种语言对应的资源文件,以便在应用中根据用户的语言偏好显示不同的文本。
  • pages:在pages目录下,通常每一个文件或文件夹代表应用中的一个路由页面。React Router等路由库可以使用这些页面组件来动态地加载对应的页面内容。
  • router:此目录包含项目的路由配置文件。这里定义了URL路径与React组件之间的映射关系。路由配置决定了用户访问不同URL时,应该渲染哪个组件。
  • store:store目录用于存放状态管理相关的文件,在当前项目中使用 Zustand 进行状态管理
  • theme:这个目录包含与主题相关的设置,如颜色、字体和其他主题变量。
  • utils:utils目录包含各种实用工具函数,这些函数不特定于任何组件或业务逻辑,可以在项目的多个地方使用。
  • App.tsx 和 main.tsx:App.tsx 是应用的根组件文件,通常这里会设置路由和全局状态管理的上下文。main.tsx 文件则是应用的入口文件,用于渲染App组件,并进行如应用的初始化设置。
  • vite-env.d.ts:这是一个类型定义文件,特定于使用Vite作为构建工具的项目。它包含了Vite特有的环境变量和类型定义,有助于TypeScript的集成和正确的类型检查。

vite-env.d.ts是干什么的?

/// <reference types="vite/client" />

主要是为了在 TypeScript 项目中确保可以正确地使用 Vite 提供的类型定义,特别是与热模块替换(HMR)和环境变量相关的类型。

  • 三斜线指令:这行代码是一个 TypeScript 的三斜线指令,它用于直接引入其他文件中定义的类型。三斜线指令是一种特殊的注释,它提供编译器指令,常用于声明文件依赖。
  • 类型引用:types=“vite/client” 指明了要引入的类型定义模块。这里,它指向 Vite 提供的客户端库类型定义,这些类型定义包括了 import.meta.env 和 import.meta.hot 等 Vite 特定的扩展。
  • 目的:通过引用 vite/client,你的项目中的 TypeScript 文件可以获得关于 import.meta 扩展的智能提示和编译时类型检查。这包括对 Vite 特有的热模块替换 API 和环境变量的访问,确保这些特性在 TypeScript 代码中被正确使用。

在根目录下已经存在了 vite-env.d.ts 了,为什么还要在src中显示的再重复一遍?

确保所有子目录和文件都能正确识别 Vite 的类型扩展,特别是在大型项目或者复杂的目录结构中。

tsvite-env.d.ts中的这两个接口(ImportMetaEnv / ImportMeta) 是干什么的? 解决什么问题?

interface ImportMetaEnv {
  readonly VITE_GLOB_APP_TITLE: string;
  readonly VITE_APP_BASE_API: string;
  readonly VITE_APP_HOMEPAGE: string;
  readonly VITE_APP_ENV: 'development' | 'production';
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}

ImportMetaEnv接口

  • 定义了所有希望在 TypeScript 中使用的,由 Vite 管理的环境变量类型
  • 每个属性都严格匹配到 .env 文件中定义的环境变量

tip: 当我们提到项目中的 .env 文件时,这通常包括了一系列不同的环境配置文件,如 .env.development、.env.production、.env.test 等

ImportMeta接口

  • 这个接口是对现有的 ImportMeta 接口的扩展,它通常已在 TypeScript 的环境中预定义。
  • 通过扩展此接口来包含 env 属性,你可以使 import.meta.env 的使用在 TypeScript 中获得类型检查支持。
  • env 属性被定义为 ImportMetaEnv 类型,这意味着通过 import.meta.env 访问的任何属性都应该符合 ImportMetaEnv 接口定义。

这个ImportMeta接口是对,现有ImportMeta接口的扩展,那么疑惑来了,扩展一般不都是 extends语法 或 &交叉类型。这种是什么写法? 这个ImportMeta接口是对,现有ImportMeta接口的扩展,那么疑惑来了,扩展一般不都是 extends语法 或 &交叉类型。这种是什么写法? 这个ImportMeta接口是对,现有ImportMeta接口的扩展,那么疑惑来了,扩展一般不都是 extends语法 或 &交叉类型。这种是什么写法?

扩展或修改已存在接口的几种常见方法

一般有三种,分别是接口继承、声明合并、交叉类型

接口继承

接口继承是在定义新接口时使用 extends 关键词来继承一个或多个现有接口的属性。这种方式清晰直观,适用于需要明确层次结构的场景,例如,你需要创建一个特定类型的接口,它应当包括一个基本接口的所有属性加上一些额外的属性。

常用于面向对象编程范式中,当多个接口或类之间存在明确的层次关系时。例如,你可能有一个基本的 Vehicle 接口,然后 Car 和 Truck 接口从 Vehicle 继承。

interface BasicAddress {
    country: string;
    city: string;
    street: string;
}
interface PersonAddress extends BasicAddress {
    name: string;
}

在这个例子中,PersonAddress 接口继承了 BasicAddress 接口,并添加了一个新属性 name。

声明合并

声明合并是 TypeScript 的一个独特特性,它允许开发者为已存在的数据结构(类、接口、命名空间等)添加更多的成员。 这在需要向第三方类型声明或全局声明中添加新信息时非常有用。

特别适合在需要扩展第三方库的类型定义或集成大型项目中的全局类型时使用。例如,扩展现有的 DOM 库的接口(如扩展 Window 或 Document 接口),或在项目中添加自定义的全局属性而不修改原有的库定义。

// 原有的接口信息
interface Car {
    make: string;
    model: string;
}

// 后来添加的更多的信息
interface Car {
    year: number;
}

// TypeScript 会自动合并上述两个声明
const myCar: Car = {
    make: 'Toyouta',
    model: 'Corolla',
    year: 2021
}

在这个例子中,Car 接口最初只有 make 和 model 两个属性,通过声明合并,我们添加了 year 属性。

声明合并(Declaration Merging)是一种强大的语言特性,允许开发者在多个地方对同一个名称的接口、命名空间或类进行定义,而 TypeScript 编译器会智能地将这些声明合并成一个单一的声明。 这种声明合并本身就是一种与众不同的特性 这种声明合并本身就是一种与众不同的特性 这种声明合并本身就是一种与众不同的特性

在大多数语言中,如果在同一个作用域内定义了两个相同名称的接口或类,通常会导致编译错误或者后定义的会覆盖前面定义的。为什么?TypeScript使用声明合并?

  1. 第三方类型定义的扩展:通过声明合并,开发者可以在不修改原始类型定义的情况下扩展第三方库的类型声明。这是在社区驱动的 DefinitelyTyped 项目中常见的做法,允许社区成员为现有的 JavaScript 库提供和改进 TypeScript 类型定义。
  2. 支持渐进式增强:TypeScript 设计用来适应 JavaScript 的动态性和灵活性,声明合并允许开发者渐进式地增强和扩展已存在的类型。
  3. 模块化和可重用性:声明合并使得类型定义可以分散到不同的文件或模块中,然后合并为一个统一的类型。这样做不仅有助于保持代码的整洁,还可以提高代码的可重用性。 tip: 最典型的应用即使由社区驱动的 DefinitelyTyped 项目是什么意思?主要目的是为那些本身不提供 TypeScript 类型声明的 JavaScript 库提供高质量的类型定义文件(.d.ts 文件)。这使得 TypeScript 用户能够在他们的项目中利用到这些流行的 JavaScript 库,同时享受 TypeScript 提供的强类型检查和编辑器智能支持的好处。

交叉类型

交叉类型是通过使用 & 符号将多个类型合并为一个类型。这常用于组合现有类型或接口到一个全新的类型,它包括所有参与交叉的类型的属性。这种方法在你需要临时组合多个类型为一个类型时特别有用,而不需要显式定义一个新接口。

当你需要组合多个独立类型的特征时,而不必创建一个全新的接口。这在处理多个来自不同域的数据类型时特别有用,比如在处理多个来自不同服务的API响应结构时。

interface BusinessPartner {
    name: string;
    credit: number;
}

interface Identity {
    id: number;
    location: string;
}

type BusinessIdentity = BusinessPartner & Identity;

const partner: BusinessIdentity = {
    name: "Example Corp",
    credit: 200,
    id: 12345,
    location: "Earth"
};

在这个例子中,BusinessIdentity 类型是通过合并 BusinessPartner 和 Identity 两个接口的属性得到的。