Gitee地址

我已经将该模板发布到Gitee,即拉即用,记得点个star哦~

文章目录

地址:https://gitee.com/zhenYuFeng/express-ts-template

1.配置库

可以先输入 tsc -v | nodemon -v | ts-node -v 命令来查看电脑是否安装对应的库。

// TypeScript
npm install -g typescript

// ts-node: 可以直接运行启动 ts 项目.
npm install -g ts-node

// nodemon: 监视文件的修改, 用来配合 ts-node, 当文件修改后重新使用 ts-node 启动项目.
npm install -g nodemon

注意:nodemon也可以运行 ts 文件, 但是无法识别到全局的类型声明,在编译时会报错。


2.创建配置文件

在此之前需要明确的是:工程文件都应该放在 src 下,否则需要自行修改下面配置的 rootDir 配置项。

在创建的项目中,需要先初始化 package.json | tsconfig.json

// 创建 package.jsn
npm init --y

// 创建 tsconfig.json
tsc --init

然后配置 tsconfig.json 文件。

{
    // 编译选项
    "compilerOptions": {
        // 入口目录
        "rootDir": "./src/",
        // 出口目录
        "outDir": "./dist/",
        // 严格模式
        "strict": true,
        // 在函数中未使用的局部变量会报错
        "noUnusedLocals": true,
        // 函数中未使用的参数会报错
        "noUnusedParameters": true,
        // 函数缺少返回值时会报错
        "noImplicitReturns": true,
        // 在 switch 语句中,每个 case 后都需要显式地指定 break、return 或 throw
        "noFallthroughCasesInSwitch": true,
        // 允许导入 CommonJS 模块时使用 ES 模块的语法
        "esModuleInterop": true
    },
    // 表示只会编译src下的 .ts 文件
    "include":["src/**/*"],
    // 不开启该项, 会出现类型丢失的情况, 因为 ts-node 不主动加载文件.
    "ts-node": { "files": true }
}

3.安装其它库

在该示例中使用的是 express 框架,所以安装的是 @types/express

// 安装express
npm install express

// express类型文件
npm install @types/express -D

// 开发 Nodejs 程序,为了获得合适的类型校验和代码提示,我们需要引入 Nodejs 的类型文件
npm install @types/node -D

// 安装 dotenv 和 cross-env
npm install dotenv cross-env

4.关于 dotenv 和 cross-env

通过以上两个库的配合,可以在不同的环境下读取不同的配置参数。

在项目根目录中创建 .env.development | .env.production | .env 三个文件。

// .env.development 文件
PORT=3001

// .env.production
PORT=3000

// .env
这里面写以上两个文件中, 需要共有且值一样的字段。

上面两个文件中分别定义了开发环境和正式环境中不同的端口。

4.1 配置

const dotenv = require('dotenv');
/**
* 这里的 process.env.NODE_ENV 是在启动项目时指定的环境。
* 
* 当调用完 config 方法就可以使用 process.env.key 了,最好就在入口文件配置。
*  - 这里的 .key 代表的是:文件中的字段。
*  - 例如:process.env.PORT。
*/
dotenv.config({ path: `.env.${process.env.NODE_ENV}` });
dotenv.config({ path: `.env` });

接下来需要在启动项目时指定环境,但是在不同的系统中,配置环境的方法都不一样,所以我们可以使用 cross-env 这个库来实现多平台适配。

需要在 package.json 中进行配置启动脚本。

{
    "script": {
        // 开发环境
        "dev": "cross-env NODE_ENV=development nodemon",
        // 打包
        "build": "tsc",
        // 正式环境
        "prod": "cross-env NODE_ENV=production node ./dist/app.js"
    }
}

5.让 nodemon 和 ts-node 关联

在上面我们在 package.json 中配置了 nodemon 监视文件,但此时还没配置它。

在项目根目录创建一个 nodemon.json,然后粘贴以下配置项。

{
    // 监视哪些文件? -> 监视整个src目录的变化
    "watch": ["src"],
    // 监视哪些文件, 不配置会不生效
    "ext": "*",
    // 当文件变化时执行的命令, (ts-node ./src/index.ts)就是用ts-node运行ts文件
    "exec": "ts-node ./src/index.ts"
}

6.开发依赖和项目依赖

在安装 @types/express 时看了一下它在 npm 上的简介,发现他的安装参数是 -S

我很迷惑,这个不应该是开发依赖吗?为什么要安装到项目依赖中呢?

6.1 解答

该项目不作为其它项目的依赖时,其实安装到哪里都无所谓。

如果其他项目依赖我们写的项目时,那其他用户肯定会执行 npm install 安装并导入我们的项目。

用户在安装我们的项目时,会将我们项目中 项目依赖 所依赖的文件也下载一遍,不然的话它就会无法使用我们所提供的功能。

而开发依赖就不会下载到用户的项目中。


7.让 (全局属性/方法 | process.env) 有更好的提示

在 types 文件夹中创建 global.d.ts 文件,在 NodeJs 命名空间下的 ProcessEnv 接口中,添加 .env.xxx 文件中定义的环境变量即可。

为什么这样定义, 你是如何知道的? -> 可以将光标悬浮到 process.env 上看到类型。

declare global {
    namespace NodeJS {
        interface ProcessEnv {
            PORT: string;
            DATA_BASE_URI: string;
        }
    }

    // 在此处, 可以定义全局的方法/属性
    var baseUrl: string;
    var getBaseUrl: () => string;
}

8.枚举

在使用 TS 写统一返回函数时,我在 .dts 文件中使用 declare enum Code 声明了一个全局的枚举,然后想在其它文件中直接使用。

在学习 TS 时,我记得老师讲过枚举最终会转换成对象。

// 声明全局枚举
declare enum Code {
    Success = 200,
    Fail = 500
}

// 理想的样子
const Code = {
    Success: 200,
    Fail: 500
};

但其实不是这样子的,只有在声明普通枚举的时候才会进行转换全局枚举不会编译进去的,不进行转换

最终写成了这样子,感觉比使用枚举更合适点。

// 状态码可选项
const stateOptions = {
    Success: 200,
    Fail: 400,
    Authentication: 401,
    NotFound: 404,
};

// 函数参数类型
interface params {
    data?: any;
    code?: keyof typeof stateOptions;
    msg?: string;
}

// 函数类型
export type formatFunType = ({ code, data, msg }: params) => {
    data: any;
    code: number;
    msg: string;
};

const formatResJsonFun: formatFunType = ({ data = null, code = 'Success', msg = '' } = {}) => {
    if (!stateOptions[code]) throw new Error('code参数错误');
    return { data, code: stateOptions[code], msg };
};

global.formatResJson = formatResJsonFun;