ラベル TypeScript の投稿を表示しています。 すべての投稿を表示
ラベル TypeScript の投稿を表示しています。 すべての投稿を表示

2023年6月1日木曜日

emacs+typescript-language-server設定方法

emacs+typescript-language-server設定方法

概要

emacs で TypeScript の開発環境を整えてみます
typescript-language-server という lsp があるのでこれを使います

環境

  • macOS 11.7.6
  • emacs 28.2
  • nodejs 19.7.0
    • typescript-language-server 3.3.2
    • typescript 5.0.4

typescript-language-server のインストール

  • npm install -g typescript-language-server typescript

lsp-mode と typescript-mode のインストール

  • M-x package-list-packages

で一覧から「typescript-mode」と「lsp-mode」をインストールします

emacs 設定

(require 'typescript-mode)
(add-to-list 'auto-mode-alist '("\\.js\\'" . typescript-mode))
(add-hook 'typescript-mode-hook #'lsp-deferred)

参考サイト

2022年10月18日火曜日

TypeScriptで環境変数を使う方法

TypeScriptで環境変数を使う方法

概要

process.env を使います

環境

  • macOS 11.6.8
  • nodejs 18.7.0
  • TypeScript 4.8.3

準備

  • npm install ts-node typescript
  • npx tsc --init

index.ts

console.log(process.env.USER_NAME || 'hawksnowlog');

動作確認

  • npx ts-node index.ts

最後に

デフォルト値は OR 演算子で設定できます

2022年4月7日木曜日

express のリクエストをクラスのオブジェクトにシリアライズするサンプルコード

express のリクエストをクラスのオブジェクトにシリアライズするサンプルコード

概要

TypeScript を使って型を定義しつつシリアライズします

環境

  • macOS 11.6.5
  • nodejs 17.8.0
  • express 4.17.3

サンプルコード

  • vim app.ts
import express from 'express'
const app = express()
const port = 3000

// ユーザプロファイルを管理するクラス
// 受け取ったリクエストはこのクラスのオブジェクトとして扱われる
// クラスはインタフェースを実装することで定義します 
// そうすることで定義したインタフェースを返り値などの型定義に使用できます
interface UserProfileType {
  name?: string,
  age?: string
}
class UserProfile implements UserProfileType {
  constructor(public name: string | undefined, public age: string | undefined) {
  }
  toJSON(): UserProfileType {
    return {
      name: this.name,
      age: this.age,
    }
  }
  // name と age が指定されているかの判定
  validate(): boolean {
    if (this.name === undefined || this.age === undefined) {
      return false
    } else {
      return true
    }
  }
  // レスポンス返却します
  show(res: express.Response): void {
    if (!this.validate()) {
      let errMsg = {'Error': 'You must specify name and age.'}
      res.send(JSON.stringify(errMsg))
    } else {
      res.send(JSON.stringify(this))
    }
  }
}

// express.Request を拡張してリクエストとして受け取るパラメータを再定義する
// 文字列または未定義のパラメータとして受け取る
interface UserProfileRequest extends express.Request {
  query: {
    name: string | undefined
    age: string | undefined
  }
}

// 受け取ったリクエストをそのままレスポンスとして返すルーティング
app.get('/', (req: UserProfileRequest, res: express.Response) => {
  let profile = new UserProfile(req.query.name, req.query.age)
  profile.show(res)
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

ポイント

UserProfileRequest インタフェースを定義して受け取るべきリクエストを定義しています
UserProfileRequest から UserProfile クラスのオブジェクトにシリアライズしていますが factory などを作って req から直接オブジェクトを生成してもいいかもしれません

クエリストリングは文字列でしか受け取れないので UserProfile.age も文字列で定義しています
本当は number として扱いたいので parseInt などを使ってどこかで変換してあげてもいいかもしれません

ちなみに undefined の部分はユニオンではなく Optional Property としても定義できます

interface UserProfileRequest extends express.Request {
  query: {
    name?: string
    age?: string
  }
}

あと toJSON の返り値の型も指定したかったので UserProfileType インタフェースを作成したあとで implements で UserProfile クラスを定義しています

最後に

今回は自力でシリアライズしましたが探せば便利なパッケージがあるかもしれません

2022年4月6日水曜日

express + TypeScript 超入門

express + TypeScript 超入門

概要

express のサンプルコードに TypeScript を適用してみました

環境

  • macOS 11.6.5
  • nodejs 17.8.0
  • express 4.17.3

インストール

  • npm install express --save-dev

サンプルアプリ

  • vim app.js
const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

動作確認

  • npm exec node app.js
  • curl localhost:3000

これを TypeScript 化してみます

TypeScript 化する

ts-node というパッケージを使うと簡単に TypeScript 化した express アプリを動かすことができます
TypeScript に必要なパッケージも合わせてインストールします

  • npm install ts-node typescript @types/node @types/express --save-dev

tsconfig.json も作成しておきましょう

  • npx tsc --init

とりあえずインタフェースを導入してみます
TypeScript を使うので拡張子を .ts にしましょう

  • vim app.ts
import express from 'express'
const app = express()
const port = 3000

interface MyResponse {
  message: string;
}

function createMessage(my_message: string): MyResponse {
  let myResponse = {
    message: my_message
  }
  return myResponse
}

app.get('/', (req: express.Request, res: express.Response) => {
  let msg = createMessage('Hello World!')
  res.send(msg.message)
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})
  • npx ts-node app.ts
  • curl localhost:3000

少し解説

express のインポートを require から import 文に変更する必要があります
これは routing の req と res 引数に express.Request と express.Response を型定義するためです

createMessage は MyResponse インタフェースで返す必要があります

class を導入してみる

  • vim app.ts
import express from 'express'
const app = express()
const port = 3000

class UserProfile {
  constructor(public name: string, public age: number) {
  }
  toJSON = () => {
    return {
      name: this.name,
      age: this.age,
    }
  }
}

function show(profile: UserProfile, res: express.Response) {
  res.send(JSON.stringify(profile))
}

app.get('/', (req: express.Request, res: express.Response) => {
  let profile = new UserProfile("hawksnowlog", 10)
  show(profile, res)
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

UserProfile というクラスを定義しました
toJSON を実装しておくと JSON.stringify 時に自動で呼び出してくれるようです

最後に

express で扱うリクエストのオブジェクトはクラスなどで管理するとどんなリクエストが飛んでくるのかクラスの定義を見ただけでわかるようになるので良いかなと思います

レスポンスも同様でクラス化するとどんなレスポンスが返るのかわかりやすくなるかなと思います

express.Request をクラスのオブジェクトにシリアライズする簡単な方法もあるかもしれません

参考サイト