Express를 통한 TypeScript 향상

안녕, 안녕!


오늘 우리는 이 두 가지 기술을 사용하여 하나를 만들 것이다Rest API.너는 이것이 다른 것 Rest API 과 같다고 생각할 수 있지만, 이 예에서 우리는 대량의 TypeScript 고급 기능을 사용할 것이다. 이것은 이 시범에 진정으로 도움이 될 것이다.그러나 비즈니스 로직 대신 TypeScript를 사용하는 것에 더 많은 관심을 기울일 것입니다.이 예에서는 TypeScript에 많은 기능을 제공하므로 VScode를 사용하는 것이 좋습니다.
우리가 제작할 API는 개에 초점을 맞출 것이다.우리의 단점은 아래와 같다.
GET /api/v1/dogs
GET /api/v1/dogs/:id
POST /api/v1/dogs
PUT /api/v1/dogs/:id
DELETE /api/v1/dogs/:id

우선 폴더를 만들어서 마음대로 이름을 지을 수 있습니다.내 express ts api를 명명할 것입니다.
  mkdir express-ts-api
그리고 노드 항목을 초기화합니다.
 npm init --y
TypeScript를 설치해야 합니다.
 npm i -D typescript
이러한 Express 및 Node 설치 유형에 대한 정의도 필요합니다.
 npm i -D @types/express @types/node
또한 Express를 설치합니다.
 npm i express
마지막으로 이 항목을 TypeScript 항목으로 구성합니다.
이 명령 사용하기
  tsc -init
우리 tConfigjson은 다음과 같다.
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "outDir": "./build",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true
  }
}
간단하게 말하면,이 설정은 저희 코드가 es5 문법 ("target": "es5") 으로 출력되고, 코드는 src 디렉터리 ("rootDir": "/src") 의 내용을 바탕으로 디렉터리 구축 ("outDir": "/build") 에서 CommonJS 모듈 시스템 ("module": "CommonJS") 을 사용하며, typescript 언어 서비스는 강력한 유형 검사 ("strict": "true") 를 강제로 실행해야 하며, 마지막으로 가져오려고 합니다.commonjs 등 서로 다른 모듈 시스템의 모듈은 ES6 모듈의 규범("esModule Interop":true)을 따른다. 이 옵션이 없으면 우리의 가져오기는 다음과 같다.
import * as express from 'express';
// instead of this
// import express from 'express';
우리의 소포.json은 다음과 같다.
{
  "name": "express-ts-api",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@types/express": "^4.17.13",
    "@types/node": "^16.11.4",
    "typescript": "^4.4.4"
  },
  "dependencies": {
    "express": "^4.17.1"
  }
}
나는 네가 nodejs를 이미 알고 있다고 가정하기 때문에 나는 이 파일의 내용을 설명하지 않을 것이다.
자, 시작합시다.src 디렉토리 만들기
 mkdir src
src 폴더에 프로그램을 만듭니다.ts 파일.
import express from 'express'

const app = express()

interface Dog {
  name: string
  breed: 'labrador' | 'german shepherd' | 'golden retriever'
  adopted_at: Date | null
  birth_date: Date | null
}
참고로 저희가 앱 대상에서 사용하는 모든 HTTP 방법은 다섯 가지 일반적인 유형이 있는데 사용자 정의 유형을 제공할 수 있습니다.유형의 배열은 Params, ResBody, ReqBody, ReqQuery 및 Locals입니다.모조약here에 대해 더 많습니다.기본적으로, 범형은 우리가 코드를 다시 사용하는 것을 돕지만, 우리의 예에서 우리는 유형을 다시 사용할 수 있다.
app.get<Params,ResBody,ReqBody,ReqQuery,Locals>('/api/v1/dogs',
(req,res) => { 

})
이 예에서, 우리는 앞의 네 가지 범주 유형만 사용할 것이다.기본적으로 매개 변수 일반 형식의 값은 빈 대상의 형식입니다.ResBody와 ReqBody는any 형식이 있고, 마지막으로 ReqQuery는ParsedQs 형식이 있습니다.
우리는express가 제공하는 기본 형식이 아니라express에서 제공하는 형식을 제공할 것입니다.

/api/v1/dogs 가져오기


app.get<
{},
{ data: Dog[], message: string },
{},
{ page: number, limit: number, breed: 'labrador' | 'german shepherd' | 'golden retriever' }>
('/api/v1/dogs', (req,res) => { 
  // your implementation
})
이 단점에서 우리는 개의 목록을 얻을 것이다. 그러면 우리는 매개 변수의 범위에서 하나의 유형을 전달하지 않을 것이다. 왜냐하면 우리는 특정한 개를 얻지 못했기 때문이다.우리는 이 단점의 개 목록을 얻을 것이기 때문에 빈 대상으로 보존할 것이다.둘째, ResBody는 우리가res.send 방법에서 보낼 유형입니다. 이 예에서 우리는 대상을 보낼 것입니다. 이 대상은 두 개의 속성 데이터를 가지고 있는데 그 유형은 우리가 이전에 제공한 개 그룹이고 메시지의 유형은 문자열입니다. 이것은 응답의 추가 정보입니다.셋째, ReqBody는 빈 대상 형식입니다. 이 단점에서 데이터를 받지 않기 때문입니다.마지막으로 ReqQuery에서는 페이지 속성 페이지와 제한을 받거나 품목 속성을 사용할 수 있는 객체 유형을 전달하므로 특정 품목에 따라 개를 필터링할 수 있습니다.

GET/api/v1/dogs/:id


app.get<
{ id: number },
{ data: Dog | null, message: string },
{}>
('/api/v1/dogs/:id', (req,res) => { 
  // your implementation
})
이 단점에서 우리는 특정한 개 한 마리를 얻을 것이다. 따라서 우리는 매개 변수에서 하나의 대상 유형을 전달할 것이다. 그 속성은 하나의 id이고, 그 유형은number이다. 왜냐하면 우리는 특정한 개 한 마리를 얻을 것이다.우리는 이 단점의 개 목록을 얻을 것이기 때문에 빈 대상으로 보존할 것이다.둘째, ResBody는 이 예에서 Dog 유형의 결합 유형과null 두 개의 속성 데이터를 가진 객체를 보냅니다. Dog이 존재하면 Dog의 모양을 되돌려주고, 존재하지 않으면 null과 문자열 형식의 속성 메시지를 되돌려줍니다.셋째, ReqBody도 빈 대상 유형이다. 왜냐하면 우리는 이 단점에서 어떠한 데이터도 받지 않기 때문이다.마지막으로, 우리는 ReqQuery에 빈 대상 유형을 전달할 것입니다. 왜냐하면 이 단점은 그것을 필요로 하지 않기 때문입니다.

POST/api/v1/dogs


app.post<
{},
{ data: Dog & { id: number }, message: string },
Dog,
{}>
('/api/v1/dogs', (req,res) => { 
  // your implementation
})
이 단점에서, 우리는 파라메스에서 빈 대상 유형을 전달하기 위해 새로운dog를 만들 것입니다.둘째, ResBody, 이 예에서 우리는 대상을 보낼 것이다. 이 대상은 두 개의 속성 데이터가 있는데 그 유형은 Dog 유형의 union 유형과 한 대상 유형이다. 이 대상 유형은 id 속성이 있고 이 속성은 type number이다. DB는 이 id를 생성하기 때문에 클라이언트와 형식이 문자열인 속성 메시지가 아니다.셋째, ReqBody에는 개 모양의 클라이언트로부터 데이터를 받을 수 있는 개가 있습니다.마지막으로, 우리는 ReqQuery에 빈 대상 유형을 전달할 것입니다. 왜냐하면 이 단점은 그것을 필요로 하지 않기 때문입니다.

PUT/api/v1/dogs/:id


app.put<
{ id: number },
{ data: Dog & { id: number }, message: string },
Partial<Dog>,
{}>
('/api/v1/dogs', (req,res) => { 
  // your implementation
})
이 단점에서, 우리는 매개 변수에서 대상 유형을 전달하기 위해 기존의 개 한 마리를 업데이트할 것입니다. 그 속성은 id이고, 그 유형은number입니다.둘째, ResBody, 이 예에서 우리는 대상을 보낼 것이다. 이 대상은 두 가지 속성 데이터가 있는데 그 유형은 Dog 유형의 union 유형과 한 대상 유형이다. 이 대상 유형은 id 속성이 있고 그 유형은 type number이다. 왜냐하면 우리는 자원의 업데이트 값과 형식이 문자열인 속성 메시지를 되돌려주기 때문이다.셋째, ReqBody에는 Dog 모양의 클라이언트로부터 데이터를 받을 수 있지만 모든 속성은 선택할 수 있어야 한다. 이것은 업데이트이기 때문에 우리는 유틸리티 형식인 Partial을 사용하여 Dog 인터페이스의 모든 속성을 선택할 수 있도록 한다.마지막으로, 우리는 ReqQuery에 빈 대상 유형을 전달할 것입니다. 왜냐하면 이 단점은 그것을 필요로 하지 않기 때문입니다.

/api/v1/dogs/:id 삭제


app.delete<
{ id: number },
{ data: Dog & { id: number }, message: string },
{},
{}>
('/api/v1/dogs', (req,res) => { 
  // your implementation
})
이 단점에서 개 한 마리를 삭제할 것입니다. 따라서 매개 변수에 대상 형식을 전달할 것입니다. 속성은 id이고, 형식은number입니다.둘째, ResBody. 이 예에서 우리는 대상을 보낼 것이다. 이 대상은 두 개의 속성 데이터가 있는데, 그 유형은 Dog 형식의 연합 유형과 하나의 대상 유형이다. 이 대상 유형의 속성 id는 type number이다. 삭제된 Dog 자원과 문자열 형식의 속성 메시지를 되돌려주기 때문이다.셋째, ReqBody는 빈 대상 형식입니다. 이 단점에서 데이터를 받지 않기 때문입니다.마지막으로, 우리는 ReqQuery에 빈 대상 유형을 전달할 것입니다. 왜냐하면 이 단점은 그것을 필요로 하지 않기 때문입니다.
나는 우리가 끝났다고 생각한다.

나는 우리가 아직 끝나지 않았다고 생각한다.우리는 줄곧 우리 자신의 사용자 정의 유형을 직접 전달하고 있는데, 그 중 일부 유형은 우리의 일부 방법에서 중복되어 우리의 코드를 깨끗하게 하지 못하게 한다.이 점을 바꾸자.
interface BaseParams<IDType = number> {
  id: IDType
}

interface DogDetails {
  name: string
  breed: DogBreed
  adopted_at: Date | null
  birth_date: Date | null
}

interface APIResponse<Data> {
  data: Data
  message: string
}

interface Pagination {
  page: number
  limit: number
  breed: DogBreed
}

interface Empty {

}

type DogBreed = 'labrador' | 'german shepherd' | 'golden retriever'

type Dog = BaseParams & DogDetails
네, 제가 당신들이 본 모든 새로운 유형을 설명하겠습니다.우선, 인터페이스 BaseParams는 저희가 Params에 제공할 형식입니다. BaseParams는 일반적인 IDType을 가지고 있으며, 기본값은 type number입니다. 여기에서 다른 종류 BaseParams<string> 를 전달해서 id에 다른 종류를 제공할 수 있습니다.DogDetails 인터페이스는 ReqBody 위치에 사용할 유형입니다.인터페이스 APIresponse는 ResBody 위치에 사용할 유형입니다. 이 유형도 하나의 범위가 있습니다. 유형BaseParams와 같이 범위ResultType 형식은 데이터 속성의 유형이 될 것입니다.인터페이스 페이지 나누기는 Position ReqQuery에 사용할 유형입니다. 이 유형에는 하나의 속성이 있으며, 다른 사용자 정의 형식을 인용합니다. 이 유형에 대해 곧 토론할 것입니다.interface Empty는 빈 객체에 사용할 지원 인터페이스 유형입니다.Dogbride 유형 별칭도 페이지 나누기 인터페이스와 DogDetails 인터페이스에서 참조하는 도우미 유형입니다.마지막으로 Dog 유형 별명은 두 인터페이스BaseParams와 DogDetails의 조합으로 우리는 &intersection 유형을 사용하여 이 점을 실현했다.
만약 우리가 코드에 이 모든 새로운 유형을 적용한다면, 우리의 코드는 반드시 이와 같아야 한다.
import express from 'express'

const app = express()

interface BaseParams<IDType = number> {
  id: IDType
}

interface DogDetails {
  name: string
  breed: DogBreed
  adopted_at: Date | null
  birth_date: Date | null
}

interface APIResponse<Data> {
  data: Data
  message: string
}

interface Pagination {
  page: number
  limit: number
  breed: DogBreed
}

interface Empty {

}

type DogBreed = 'labrador' | 'german shepherd' | 'golden retriever'

type Dog = BaseParams & DogDetails

app.get<Empty, APIResponse<Dog[]>, Empty, Pagination>('/api/v1/dogs', (req, res) => {
  // your implementation
})

app.get<BaseParams, APIResponse<Dog | null>, Empty, Empty>('/api/v1/dogs/:id', (req, res) => {
  // your implementation
})

app.post<Empty, APIResponse<Dog>, DogDetails, Empty>('/api/v1/dogs', (req, res) => {
  // your implementation
})

app.put<BaseParams, APIResponse<Dog>, Partial<DogDetails>, Empty>('/api/v1/dogs', (req, res) => {
  // your implementation
})

app.delete<BaseParams, APIResponse<Dog>, Empty, Empty>('/api/v1/dogs', (req, res) => {
  // your implementation
})
우리가 새로운 유형을 만들었기 때문에, 새 코드는 구 코드보다 더 읽기 쉽고 유지보수성이 있다.
나는 우리가 정말 끝났다고 생각한다.

이 글을 읽어 주셔서 감사합니다.


좋은 하루 되세요.😃!.

좋은 웹페이지 즐겨찾기