TS 进阶 - 实际应用 04

2023-05-17 20:40:55 浏览数 (1)

# TS Config

# 构建相关

  • 特殊语法相关
    • experimentalDecorators 与 emitDecoratorMetadata
    • jsx、jsxFactory、jsxFragmentFactory 与 jsxImportSource
  • target 与 lib、noLib
  • 构建解析相关
    • files、include 与 exclude
      • exclude 只能剔除已经被 include 包含的文件
    • baseUrl
    • rootDir
    • rootDirs
    • types 与 typeRoots
    • moduleResolution
    • moduleSuffixes
    • noResolve
    • paths
    • resolveJsonModule
  • 构建产物相关
    • 构建输出相关
      • outDir 与 outFile
      • preserveConstEnums
      • noEmit 与 noEmitOnError
      • module
      • importHelpers 与 noEmitHelpers
      • downlevelIteration
      • importsNotUsedAsValues 与 preserveValueImports
  • 声明文件相关
    • declaration、declarationDir
    • declarationMap
    • emitDeclarationOnly
  • Source Map 相关
    • sourceMap 与 inlineSourceMap
    • sourceRoot 与 mapRoot
  • 构建产物代码格式化配置
    • newLine
    • removeComments
    • stripInternal

# 检查相关

  • 允许类
    • allowUmdGlobalAccess
    • allowUnreachableCode
    • allowUnusedLabels
  • 禁止类
    • 主要关注未被妥善处理的逻辑代码与无类型信息(手动标注与自动推导均无)的部分
  • 类型检查
    • noImplicitAny
    • useUnknownInCatchVariables
  • 逻辑检查
    • noFallthroughCasesInSwitch
    • noImplicitOverride
    • noImplicitReturns
    • noImplicitThis
    • noPropertyAccessFromIndexSignature 与 noUncheckedIndexedAccess
    • noUnusedLocals 与 noUnusedParameters
  • 严格检查
    • exactOptionalPropertyTypes
    • alwaysStrict
    • strict
    • strictBindCallApply
    • strictFunctionTypes
    • strictNullChecks
    • strictPropertyInitialization
    • skipLibCheck 与 skipDefaultLibCheck

# 工程相关

Project References

  • 可以将整个工程拆分成多个部分,比如你的 UI 部分、Hooks 部分以及主应用等等
  • 和 Monorepo 非常相似,但它并不需要各个子项目拥有自己独立的 package.json、独立安装依赖、独立构建等
  • 可以使用完全独立的 TSConfig 配置文件,也可以使用一个 TSConfig 配置文件
代码语言:javascript复制
{
  "references": [
    { "path": "../ui" },
    { "path": "../hooks" },
    { "path": "../app" }
  ]
}

composite

# JavaScript 相关

  • allowJs
  • checkJs

# 模块相关

  • esModuleInterop 与 allowSyntheticDefaultImports

# 编译器相关

  • incremental
  • watch 相关
  • 编译器检查

# 其他工程相关

  • extends

# Prisma NestJS 实战

# Heroku 环境配置

# NestJS

新建项目:

代码语言:javascript复制
npm i -g @nestjs/cli

nest new nest-prisma

主要文件结构:

  • app.controller.ts API 路由定义文件
    • 一般不在 Controller 中处理业务逻辑,Controller 通常只处理请求入参的校验、请求响应的包装
  • app.service.ts 在 Service 层去处理数据库交互、BFF、日志等逻辑,然后供 Controller 层调用
    • 注意,不意味着 Controller 层有一个 UpdateUser 处理方法,那 Service 层也要有专门的 UpdateUser 方法,更好的方法是将 Service 拆得更细一些,在未来新增 Controller 时,只需要按照逻辑重新组装 Service 即可
  • app.module.ts 应用的核心文件,需要这个模块才能在 main.ts 中去启动应用
    • 在实际中,可能会有多个 .module.ts 文件来实现对业务逻辑的模块拆分,如 user.module.tsupload.module.ts
    • 在这个文件中会定义属于该模块的 Controller 和 Service,其他模块可以通过导入该模块来使用其内部的 Service,而不是直接导入 Service 造成模块间的混乱引用
  • main.ts 应用的入口文件,负责启动应用
    • 定义全局级别的应用配置

# Prisma

ORM 库(Object-Relational Mapping),其实就是编程语言到 SQL 的映射,无需学习 SQL 的使用,直接用最熟悉的代码调用方法,即可与数据库进行交互。

NodeJs 中的 ORM 目前基本都是通过 js / ts 文件进行定义的,比如 Sequelize、TypeORM 等,均是通过面向对象的方式进行数据库实体的定义。

Prisma 最特殊的一点,它使用自己的 SDL(Schema Define Language,也可以说是 DSL ,Domain-Specified Language)来声明一个实体。

初始化 Prisma:

代码语言:javascript复制
npx prisma init

npm i prisma -g

npm i @prisma/client -D

声明 Schema:

代码语言:javascript复制
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model Tag {
  id String @id @default(cuid())
  name String
  description String?
  Article Article[]
}

model Category {
  id String @id @default(cuid())
  name String
  description String?
  Article Article[]
}

model Article {
  id Int @id @default(autoincrement())
  title String?
  description String @default("there is no description")
  content String
  visible Boolean @default(true)
  tag Tag[]
  category Category[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

生成 Client:

代码语言:javascript复制
prisma generate

Prisma Client 会被生成到 node_modules/@prisma/client 目录下,可以通过 import { PrismaClient } from '@prisma/client' 来引入。

# NestJS 中集成 Prisma

将 Prisma 相关逻辑封装到 Service 中:

代码语言:javascript复制
import {
  Injectable,
  OnApplicationShutdown,
  OnApplicationBootstrap,
} from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService
  extends PrismaClient
  implements OnApplicationBootstrap, OnApplicationShutdown
{
  constructor() {
    super();
  }

  async onApplicationBootstrap() {
    await this.$connect();
  }

  async onApplicationShutdown(signal?: string) {
    await this.$disconnect();
  }
}

实例化:

代码语言:javascript复制
import { Global, Module } from '@nestjs/common';

import { PrismaService } from './prisma.service';

@Global()
@Module({
  providers: [PrismaService],
  exports: [PrismaService],
})

export default class PrismaModule {}

app.module.ts 中导入:

代码语言:javascript复制
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import PrismaModule from './data/prisma.module';

@Module({
  imports: [
    PrismaModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

声明相关类型:

代码语言:javascript复制
export type { Article, Tag, Category } from '@prisma/client';

import type { Prisma } from '@prisma/client';

export type ArticleCreateInput = Prisma.ArticleCreateInput;
export type ArticleUpdateInput = Prisma.ArticleUpdateInput &
  Prisma.ArticleWhereUniqueInput;

export type TagCreateInput = Prisma.TagCreateInput;
export type TagUpdateInput = Prisma.TagUpdateInput & Prisma.TagWhereUniqueInput;

export type CategoryCreateInput = Prisma.CategoryCreateInput;
export type CategoryUpdateInput = Prisma.CategoryUpdateInput &
  Prisma.CategoryWhereUniqueInput;

export type MaybeArray<T> = T | T[];

export type MaybeNull<T> = T | null;

0 人点赞