客户端和服务器之间共享类型

问题描述 投票:0回答:3

我正在开发一个包含 Node.js、Express.js 和 TypeScript 后端(REST API)以及 React、Redux 和 TypeScript 前端的项目。

在后端我创建了一些类型,例如:

模型/产品.ts

export type Product = {
    title: string
    description: string
    price: number
}

因此 REST API 正在发送如下响应:

{
  "data": [
     {"title": "Shoe", "Description": "This is a shoe.", "price": 20},
     {...}
   ] // inside here all the Products[]
}

在客户端,我想将

data
转换为
Product
数组类型。但由于前端和后端是不同的代码库并且是分开的,我仍然想利用在前端使用类型的优势。但我想在不重复代码的情况下实现这一目标。所以我不想在修改或添加模型时更新2个地方。

有人知道在客户端和服务器之间共享类型的最佳方法是什么吗?

我正在考虑在后端创建一个端点 客户端可以命中,然后将所有模型写入一个文件中 客户端上的示例

models.ts
。所以我认为我需要循环遍历后端 /models/ 内的每个文件,然后在一个新文件中解析它,该文件在客户端上写为 models.ts。但这真的是个好办法吗?有人知道实现这种结构的更好方法吗?

typescript server model client
3个回答
38
投票

您可以使用 TypeScript 路径映射

我是作者的项目示例:
SampleTypes.ts 中的后端定义类型在 client 项目中重用,以避免重复代码。

client/tsconfig.json

{
  "compilerOptions": {
    "paths": { "@backend/*": ["../server/src/api/*"], },
  }
}

../server/src/api/
-> https://github.com/winwiz1/crisp-react/tree/master/server/src/api

client/....ts

import { SampleRequest } from "@backend/types/SampleTypes";

2
投票

您本质上是希望在多个包之间共享代码(在您的情况下是类型定义)。 Yarn 为此开发了workspaces,并且它不像其他答案那样依赖 tsconfig/Typescript。

这是一次深入兔子洞的尝试,需要对 Yarn 配置进行一些工作,并可能使用 Lerna 等工具。然而,当您拥有共享类型的紧密耦合的包时,这确实有意义,但也许还有验证逻辑。


0
投票

您可以在模块中构建 Node.js 代码,其中每个模块的类型都位于 type.ts 文件中。

例如:

src/modules/devices/types.ts

export interface Route {
  timestamp: string
  name: string
  geojsonString: string
}

export type AddRouteBodyParams = Pick<Route, 'name' | 'geojsonString'>

export interface DeleteRouteBodyParams {
  deviceId: string
  timestamp: string
}

export interface EditRouteBodyParams {
  deviceId: string
  timestamp: string
  name: string
  geojsonString: string
}

src/modules/devices/controllerDevice.ts

import type { Request, Response } from 'express'
import type { ParsedQs } from 'qs'

import type { ResponseError, ResponseSuccess } from '../../api-types'

import { editRoute } from './serviceRoutes'
import type { EditRouteBodyParams } from './types'

export const deviceController = {
  editRoute: async (
    req: Request<any, any, EditRouteBodyParams, ParsedQs, Record<string, any>>,
    res: Response<ResponseSuccess | ResponseError>
  ) => {
    const editResponse = await editRoute({ ...req.body })
      if (editResponse instanceof Error) {
        return res.status(500).json({ error: editResponse.message })
      }
      return res.send({ message: `Route with name: ${req.body.name} was updated` })
  },
} as const

然后,您可以将所有 api 类型导出到单个文件中,并通过运行 npm 命令将其复制到前端项目中:

"scripts": {
    "generate-types": "tsc -p tsconfig-export.json && cp ./dist/export-api-types.d.ts ../client_map_app/src/types"
}

您可以查看更多详情这里

© www.soinside.com 2019 - 2024. All rights reserved.