TypeScript node 프로젝트 에서 의 실천

TypeScript 는 JavaScript 의 초 집합 으로 이해 할 수 있 습 니 다. 즉, 모든 JavaScript 의 기능 을 포함 하고 그 위 에 자신 만 의 독특한 문법 을 가지 고 있 습 니 다.최근 의 새로운 프로젝트 가 TS 의 구덩이 밟 기 여행 을 시 작 했 습 니 다. 참고 할 만 한 방법 을 공유 하 겠 습 니 다.
TS 를 선택 한 이유
거 경 회사 에서 생산 한 정태 적 이 고 강 한 유형의 컴 파일 형 언어 로 서 이 언어 는 몇 년 동안 등장 되 었 고 지역사회 의 유지 아래 안정 적 인 언어 라 고 믿 습 니 다.우 리 는 자바 스 크 립 트 는 동적 약 유형 해석 형 스 크 립 트 언어 로 동태 적 으로 많은 편 의 를 가 져 왔 다 는 것 을 알 고 있 습 니 다. 우 리 는 코드 실행 에서 변수 유형 을 임의로 수정 하여 기대 하 는 목적 을 달성 할 수 있 습 니 다.그러나 이것 은 양날 의 검 입 니 다. 거대 한 프로젝트 가 당신 앞 에 나타 나 면 매우 복잡 한 논리 에 직면 하여 코드 를 통 해 특정한 변수 가 어떤 유형 인지 알 기 어렵 습 니 다. 이 변 수 는 무엇 을 해 야 하 는 지 자칫 구 덩이 를 밟 을 수 있 습 니 다.
한편, 정적 강 유형 컴 파일 은 많은 장점 을 가 져 올 수 있다. 그 중에서 가장 중요 한 것 은 개발 자 들 이 부주의 한 문 제 를 근절 하 는 데 도움 을 줄 수 있다 는 것 이다. 그림 은 rollbar 가 통계 한 수천 개 프로젝트 중 수량 이 가장 많은 10 개 이상 이다.
유형 이 일치 하지 않 고 변수 가 비어 있 기 때문에 인정 할 수 있 는 횟수 보다 이상 하 다 는 것 을 알 수 있 습 니 다.예 를 들 어 이 점 은 TS 에서 잘 개선 되 었 습 니 다. 모든 변수의 인용 은 자신의 유형 을 지정 해 야 합 니 다. 그리고 아래 에 코드 에서 무엇 을 사용 할 수 있 고 어떤 방법 을 지원 할 수 있 는 지 위 에서 정 의 를 내 려 야 합 니 다. 이 힌트 는 개발, 컴 파일 기간 에 개발 자 에 게 제시 하여 온라인 에서 문제 가 발견 되 지 않도록 하고 수정 해 야 합 니 다.
또 다른 정적 컴 파일 형식 이 가 져 온 장점 은 함수 서명 입 니 다.아니면 위 에서 말 한 것 처럼 동적 스 크 립 트 언어 이기 때문에 개발 기간 에 호출 할 함수 가 어떤 인 자 를 전달 해 야 하 는 지 정확하게 알려 주 는 편집기 가 있 기 어렵 습 니 다. 함수 가 어떤 종류의 반환 값 을 되 돌려 줍 니까?
TS 에서 하나의 함수 에 대해 먼저 모든 매개 변수의 유형 과 반환 값 의 유형 을 정의 해 야 합 니 다.이렇게 함수 가 호출 될 때 우 리 는 이 함수 의 효 과 를 뚜렷하게 볼 수 있다.
이것 은 가장 기본 적 이 고 프로그램 을 안정 시 킬 수 있 는 두 가지 특성 입 니 다. 물론 TS 에 더 많은 기능 이 있 습 니 다: TypeScript | Handbook
TypeScript node 에서 의 응용
TS 홈 페이지 에 대량의 예시 가 있 는데 그 중에서 Express 버 전의 예 를 찾 았 습 니 다. 이 를 약간 수식 하여 koa 프로젝트 에 사 용 했 습 니 다.
환경 의존
TS 를 사용 하기 전에 이 물건 들 을 준비 해 야 합 니 다.
  • VS code 는 같은 하 드 코어 회사 에서 제작 되 었 고 그 자체 가 TS 가 개발 한 것 이기 때문에 이 편집 기 는 현재 TS 에 대한 지지 도가 가장 높 은 것 이다
  • .
  • Node. js 추천 8.11 버 전 이상
  • npm i -g typescript 전역 에 TS 를 설치 하고 사용 하 는 tsc 명령 을 컴 파일 합 니 다
  • npm i -g nodemon, 전역 에 nodemon 을 설치 하고 tsc 컴 파일 후 자동 으로 서버 프로그램 새로 고침
  • 공식 수첩
  • 공식 익 스프 레 스 예시
  • 그리고 프로젝트 에 사용 되 는 핵심 의존 도:
  • reflect-metadata: 대량의 장식 기의 가방 은 모두 의존 하 는 기초 가방 으로 데 이 터 를 주입 하 는 데 사용 된다
  • routing-controllers: 장식 기 를 사용 하여 koa - router 개발
  • sequelize: 추상 화 된 데이터베이스 조작
  • sequelize-typescript: 상기 플러그 인의 장식 기 버 전, 실 체 를 정의 할 때 사용
  • 프로젝트 구조
    우선, 현재 프로젝트 의 구 조 를 방출 합 니 다.
    .
    ├── README.md
    ├── copy-static-assets.ts
    ├── nodemon.json
    ├── package-lock.json
    ├── package.json
    ├── dist
    ├── src
    │   ├── config
    │   ├── controllers
    │   ├── entity
    │   ├── models
    │   ├── middleware
    │   ├── public
    │   ├── app.ts
    │   ├── server.ts
    │   ├── types
    │   └── utils
    ├── tsconfig.json
    └── tslint.json
    src 는 주요 개발 디 렉 터 리 로 모든 TS 코드 가 이 안에 있 습 니 다. 컴 파일 을 거 친 후에 src 와 같은 등급 의 dist 폴 더 가 생 성 됩 니 다. 이 폴 더 는 node 엔진 이 실제 실행 하 는 코드 입 니 다.src 에서 주요 코드 는 다음 과 같은 구조 로 나 뉜 다 (자신의 프로젝트 의 실제 상황 에 따라 첨삭).
    |folder|desc
    1 controllers
    인터페이스 요청, 원본 apps, routes 폴 더 를 처리 하 는 데 사 용 됩 니 다.
    2 middleware
    각종 미들웨어, 전역 or 사용자 정의 미들웨어 를 저장 합 니 다.
    3 config
    각종 설정 항목 의 위 치 는 포트, log 경로, 각종 바라 바라 의 상수 정 의 를 포함한다.
    4 entity
    여기에 저 장 된 것 은 모든 실체 정의 입 니 다.
    5 models entity 에서 온 실 체 를 사용 하여 sequelize 초기 화 작업 을 수행 하고 sequelize 대상 을 던 집 니 다.
    6 utils
    저 장 된 각종 일상 개발 에서 추출 한 공공 함수
    7 types
    각종 객 제 화 된 복합 유형의 정 의 를 저장 하고 각종 구조, 속성, 방법 반환 값 의 정의 (현재 자주 사용 되 는 Promise 판 redis 와 qconf 포함)
    controllers
    controllers 는 데이터베이스 가 아 닌 논리 만 처리 하고 model 대상 을 조작 하여 데이터 의 첨삭 검 사 를 진행 합 니 다.
    회사 의 대부분 Node 프로젝트 버 전이 Node 8.11 로 업그레이드 되 었 음 을 감안 하여 우 리 는 새로운 문법 을 시도 할 것 이다.즉, 우 리 는 버 릴 것 이다 Generator, 포옹 async / await.Koa, Express 인 터 페 이 스 를 쓴 어린이 신발 은 한 항목 이 커지 면 실제로 중복 되 는 비 논리 코드 가 많이 생 긴 다 는 것 을 잘 알 고 있 을 것 이다.
    router.get('/', ctx => {})
    router.get('/page1', ctx => {})
    router.get('/page2', ctx => {})
    router.get('/page3', ctx => {})
    router.get('/pageN', ctx => {})

    모든 경로 에서 감청 을 하면 서 반복 되 는 작업 을 많이 하고 있다.
    router.get('/', ctx => {
      let uid = Number(ctx.cookies.get('uid'))
      let device = ctx.headers['device'] || 'ios'
      let { tel, name } = ctx.query
    })

    거의 모든 경로 의 머리 는 파 라 메 터 를 얻 는 작업 을 하고 있 고 파 라 메 터 는 header, body 심지어 cookiequery 에서 나 올 수 있다.
    그래서 우 리 는 원래 koa 의 사용 방법 에 대해 비교적 큰 변경 을 했 고 routing - controllers 의 대량의 응용 장식 기 를 사용 하여 대부분의 비 논리 코드 를 처리 하 는 데 도움 을 주 었 다.
    원래 router 의 정의:
    module.exports = function (router) {
      router.get('/', function* (next) {
        let uid = Number(this.cookies.get('uid'))
        let device = this.headers['device']
        
        this.body = {
          code: 200
        }
      })
    }

    TypeScript 와 장식 기의 정 의 를 사 용 했 습 니 다:
    @Controller
    export default class {
      @Get('/')
      async index (
        @CookieParam('uid') uid: number,
        @HeaderParam('device') device: string
      ) {
        return {
          code: 200
        }
      }
    }

    인 터 페 이 스 를 검색 하기 쉽 고 선명 하 게 하기 위해 우 리 는 기 존의 bd-router 기능 을 버 렸 다.controllers 아래 파일 에 해당 하 는 인 터 페 이 스 를 직접 설명 하여 감청 합 니 다.
    middleware
    전역 미들웨어 라면 클 라 스 @Middleware 장식 기 를 직접 추가 하고 설정 type: 'after|before' 하면 된다.특정한 미들웨어 라면 일반적인 class 를 만 들 면 됩 니 다. 그리고 사용 해 야 할 controller 대상 에 지정 @UseBefore / @UseAfter (class 에 쓸 수도 있 고 method 에 쓸 수도 있 습 니 다).
    모든 미들웨어 는 대응 하 는 MiddlewareInterface 인 터 페 이 스 를 계승 하고 실현 use 방법 이 필요 하 다.
    // middleware/xxx.ts
    import {ExpressMiddlewareInterface} from "../../src/driver/express/ExpressMiddlewareInterface"
    
    export class CompressionMiddleware implements KoaMiddlewareInterface {
      use(request: any, response: any, next?: Function): any {
        console.log("hello compression ...")
        next()
      }
    }
    
    // controllers/xxx.ts
    @UseBefore(CompressionMiddleware)
    export default class { }

    entity
    파일 은 데이터 모델 만 정의 하고 논리 적 인 조작 은 하지 않 습 니 다.
    마찬가지 로 sequelize + 장식 기 를 사용 하 였 으 며, enity 는 데이터베이스 와 통신 하 는 데이터 모델 을 만 드 는 데 만 사 용 됩 니 다.
    import { Model, Table, Column } from 'sequelize-typescript'
    
    @Table({
      tableName: 'user_info_test'
    })
    export default class UserInfo extends Model {
      @Column({
        comment: '  ID',
        autoIncrement: true,
        primaryKey: true
      })
      uid: number
    
      @Column({
        comment: '  '
      })
      name: string
    
      @Column({
        comment: '  ',
        defaultValue: 0
      })
      age: number
    
      @Column({
        comment: '  '
      })
      gender: number
    }

    sequelize 가 연결 을 만 드 는 것 도 해당 하 는 데이터베이스 주소, 계 정, 비밀번호, database 등 정보 가 필요 하기 때문에 같은 데이터베이스 의 모든 실 체 를 하나의 디 렉 터 리 에 두 는 것 을 추천 합 니 다. sequelize 가 해당 하 는 모델 을 불 러 오 는 데 편리 하고 config 에서 해당 하 는 설정 정 보 를 만 들 고 실 체 를 저장 하 는 key 열 을 추가 하 는 것 을 추천 합 니 다.이렇게 하면 데이터베이스 링크 를 만 들 고 데이터 모델 을 불 러 올 때 이 경로 의 모든 실 체 를 동적 으로 가 져 올 수 있 습 니 다.
    // config.ts
    export const config = {
      // ...
      mysql1: {
        // ... config
    +   entity: 'entity1' //               key
      },
      mysql2: {
        // ... config
    +   entity: 'entity2' //               key
      }
      // ...
    }
    
    // utils/mysql.ts
    new Sequelize({
      // ...
      modelPath: [path.reolve(__dirname, `../entity/${config.mysql1.entity}`)]
      // ...
    })

    model
    model 의 포 지 셔 닝 은 해당 하 는 실체 에 따라 추상 화 된 데이터베이스 대상 을 만 드 는 것 입 니 다. sequelize 를 사 용 했 기 때문에 이 디 렉 터 리 의 파일 은 매우 간결 해 집 니 다.기본적으로 sequelize 대상 을 초기 화하 고 모델 을 불 러 온 후에 던 지 는 것 입 니 다.
    export default new Sequelize({
      host: '127.0.0.1',
      database: 'database',
      username: 'user',
      password: 'password',
      dialect: 'mysql', //           
      modelPaths: [path.resolve(__dirname, `../entity/${configs.mysql1.entity}`)], //        
      pool: { //           
        max: 5,
        min: 0,
        acquire: 30000,
        idle: 10000
      },
      operatorsAliases: false,
      logging: true // true         sequelize      SQL  
    })

    utils
    모든 공공 함수 가 여기에 놓 여 있 습 니 다.색인 파일 (index. ts) 을 작성 하 는 것 을 추천 합 니 다. 대략적인 형식 은 다음 과 같 습 니 다.
    // utils/get-uid.ts
    export default function (): number {
      return 123
    }
    
    // utils/number-comma.ts
    export default function(): string {
      return '1,234'
    }
    
    // utils/index.ts
    export {default as getUid} from './get-uid'
    export {default as numberComma} from './number-comma'

    새로운 util 을 추가 할 때마다 index 에 해당 하 는 색인 을 추가 하면 한 줄 을 통 해 도입 하고 싶 은 모든 utils 을 도입 할 수 있다 는 장점 이 있 습 니 다.
    import {getUid, numberComma} from './utils'

    configs
    configs 아래 에 저 장 된 것 은 바로 각종 설정 정보 입 니 다. 제3자 인터페이스 URL, 데이터 베이스 설정, 로그 경 로 를 포함 합 니 다.각종 balabala 의 정적 데이터.설정 파일 이 많 으 면 여러 파일 로 나 눈 다음 utils 방식 으로 색인 파일 을 작성 하 는 것 을 권장 합 니 다.
    types
    여기에 저 장 된 것 은 모든 사용자 정의 형식 정의 입 니 다. 일부 오픈 소스 커 뮤 니 티 에서 제공 하지 않 았 지만 우리 가 사용 하 는 제3자 플러그 인 은 여기 서 정 의 를 내 려 야 합 니 다. 일반적으로 자주 사용 하 는 것 은 있 지만 일부 작은 가방 은 TS 의 지원 이 없 을 수도 있 습 니 다. 예 를 들 어 우리 가 사용 하 는 것 node-qconf:
    // types/node-qconf.d.ts
    export function getConf(path: string): string | null
    export function getBatchKeys(path: string): string[] | null
    export function getBatchConf(path: string): string | null
    export function getAllHost(path: string): string[] | null
    export function getHost(path: string): string | null

    형식 정의 파일 은 접 두 사 를 d. ts types 아래 에 있 는 모든 파일 을 직접 참조 할 수 있 도록 규정 하고 있 으 며, 상대 적 인 경로 에 관심 을 가지 지 않 아 도 됩 니 다. (다른 일반적인 model 은 상대 적 인 경 로 를 써 야 합 니 다. 이것 은 매우 난처 한 문제 입 니 다.)
    질문
    현재 GitHub 창고 에는 2600 + 가 열 려 있 는 상태 인 issues 가 있 습 니 다. bug 탭 을 선택 한 후에 도 900 + 가 존재 합 니 다.그래서 사용 하 는 과정 에서 구 덩이 를 밟 지 않 을 것 이 라 고 장담 하기 어렵 지만 한 프로젝트 가 이렇게 활발 한 issues 를 가지 고 있 으 니 이 프로젝트 의 인기 정 도 를 측면 에서 설명 할 수 있다.
    현재 직면 하고 있 는 유일한 난처 한 문 제 는 파일 경 로 를 참조 하려 면 반드시 다 써 야 한 다 는 것 이다.
    import module from '../../../../f**k-module'

    작은 매듭
    TypeScript 를 처음 시도 해 보 았 습 니 다. 이 언어 를 깊이 좋아 하 게 되 었 습 니 다. 작은 문제 도 있 지만 극복 할 수 있 습 니 다.)정적 강 한 유형의 컴 파일 언어 를 사용 하면 많은 bug 를 개발 기간 에 없 앨 수 있 습 니 다.
    상기 설명 을 바탕 으로 하 는 간단 한 예제: 코드 창고
    즐 거 운 시간 보 내세 요. TS 관련 질문 이 있 으 시 면 소란 피 우 러 오 세 요.NPM loves U.

    좋은 웹페이지 즐겨찾기