shunnami
@shunnami (miffiy)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

変数名の命名で困っております。お力添えいただけると嬉しいです。

解決したいこと

変数名の付け方で迷っておりご教示いただけますと幸いです。

APIレスポンスでエラー理由を2桁の数字(エラー理由ID)で受け取るとします。
エラー理由IDを受け取ってエラーメッセージを返す関数、またはオブジェクトの命名で迷っています。

以下例では仮としてmappingという関数名にしていますが、抽象的すぎると思っています。
より良い関数名はないでしょうか。

api
export const api = () => {
  return {
    status:200,
    data:{
      reasonCode:"01",
    }
  }
}
api呼び出し
import {mapping} from "./mapping";
import {api} from "./api";

const service = () => {
  const {data} = api();
  const result = mapping(data.reasonCode);
  console.log(result)// => "必須入力項目です"
}
mapping.ts
export const mapping = (reasonCode:string) => {
  if(reasonCode === "01")return "必須入力項目です"
  if(reasonCode === "02")return ""
  if(reasonCode === "03")return ""
}

他のmapping方法

実際はオブジェクトでマッピングしようと思っています。しかし考えるうえでは関数のほうが直感的であると思ったので上では関数で定義しました。オブジェクトでmappingすると以下のようになります。

mapping(オブジェクト)
const MAPPING = {
    "01":"必須入力項目です",
    "02":"",
    "03":"",
}
api呼び出し
import {MAPPING } from "./mapping";
import {api} from "./api";

const service = () => {
  const {data} = api();
  const result = MAPPING(data.reasonCode);
  console.log(result)// => "必須入力項目です"
}
0

4Answer

命名について

エラー理由IDを受け取ってエラーメッセージを返す

これをそのまま表せば良いと思いますよ。
例えば次のような名称はいかがでしょうか?

convertErrorMessage(errorId: string): string { }
toErrorMessage(errorId: string): string { }

オブジェクトか関数か

私は両方使うと思います。
マッピングはオブジェクトの方が分かりやすいです。
ただしconstにしてもプロパティを変更できてしまうので、変換を行う関数だけを公開します。
これならマッピングを変更しても関数の変更は不要です。

// スコープ内でこれしか扱わないのなら名称は"map"で十分
const map = {
  "01":"必須入力項目です",
  // ...
};

export function convertErrorMessage(errorId: string): string {
  return map[errorId];
}

さらに言うとMapの方がよさそうです。

2Like

JavaScript なら Object.fromEntries()String.fromCharCode() などの前例にならって errorReasonFromCode() にしておくといいと思います。

errorCodeToReason() でもいいですが、

const reason = errorReasonFromCode(code)
const reason = errorReasonToCode(reason)

を比べると、後者は名詞が互い違いに並んで読みづらいと個人的には思います。ただし Object や Map によるマッピングの場合は errorCodeToReason の順が一般的です。

いずれにせよ、エクスポートする関数なら、何から何に変換するかを名前に含めるべきです。局所的に使うプライベート関数なら toReason() 程度に略してもいいでしょう。

2Like

命名について

変数名については、後述する実装方法のバリエーションによって慣習的に使われるものが変わるので割愛しますが、関数名についてのみ、あくまで個人的な意見ですが、

function getErrorReason(reasonCode: ErrorReasonCode): ErrorReason {
  // do something
}

で十分かと思います。
reasonを取得するために何を与える必要があるかは引数名および型をみれば明らかだと思いますので、混乱することはないと感じるからです。

捕捉として、例えばあるオブジェクトを取得するためのキーが複数種類存在する場合、例えばDateオブジェクトは

new Date()
new Date("2022-07-09T15:53:31.031Z")
new Date(1657382011031)

など様々なkeyで生成することができますが、これらを関数として命名する際には、それぞれ別の名前として

function getDateNow() {
  return new Date()
}
function getDateFromISOString(isoString: string) {
  return new Date(isoString)
}
function getDateFromTimestamp(timestamp: number) {
  return new Date(timestamp)
}

としてあげるのが分かりやすいでしょう。
今回の投稿者さんのケースではErrorReasonCode以外のものからErrorReasonを取得するケースはほぼなさそうなので、単にgetErrorReasonで良いかなと感じます

オブジェクトか関数か

今回のケースでいうと、命名よりReasonCodeとしてstringを受け取っていることのほうがTypescriptの型安全性を活用できていないのでもったいないかもしれません。

ErrorReasonCodeやErrorReasonは取りうる値が事前に分かっていると思いますので、少なくともErrorReasonCodeはTypescriptではEnumconstキーワードを伴ったオブジェクトで定義するのが良いでしょう
ErrorReasonCodeだけEnumを使って、ErrorReasonは関数だけで表現することは可能ですが、あまり一般的ではないかもしれません

Enum or constオブジェクトを使うメリット及び両者の比較は、 こちらのサイト などが参考になると思います

実装方法はいくつかのバリエーションが考えられるため、いくつかの例を示します

いずれの例も、ErrorReasonを取得する再に存在しないErrorReasonCodeは入力できない(コンパイル時にエラーとなる)ようになっているはずです。
もし気に入っていただけるようでしたら、実際にいくつか書いてみてしっくりくるものを探してみてもよいかもしれません。

Enum + 関数

enum ErrorReasonCode = {
  REQUIRED: "01",
  // ...
}

enum ErrorReason = {
  REQUIRED: "必須入力項目です",
  // ...
}

function getErrorReason(reasonCode: ErrorReasonCode): ErrorReason {
  if (reasonCode === ErrorReasonCode.REQUIRED) {
    return ErrorReason.REQUIRED
  }
  // else if(...) { ... }
}

const api = () => {
  const reasonCode = ErrorReasonCode.REQUIRED
  return {
    status:200,
    data:{
      reasonCode,
      reason: getReason(reasonCode),
    }
  }
}

constオブジェクト (ErrorReasonCode + ReasonCode) + 関数

export const ErrorReasonCode = {
  REQUIRED: "01",
  // ...
} as const

export type ErrorReasonCode = typeof ErrorReasonCode[keyof typeof ErrorReasonCode]

export enum ErrorReason = {
  ErrorReasonCode.REQUIRED: "必須入力項目です",
  // ...
} as const

export type ErrorReason = typeof ErrorReason[keyof typeof ErrorReason]

export function getErrorReason(reasonCode: ErrorReasonCode): ErrorReason {
  return ErrorReason[reasonCode]
}

const api = () => {
  const reasonCode = ErrorReasonCode.REQUIRED
  return {
    status:200,
    data:{
      reasonCode,
      reason: getReason(reasonCode),
    }
  }
}

constオブジェクト (ErrorReason) + 関数

export enum ErrorReason = {
  "01": "必須入力項目です",
  // ...
} as const

export type ErrorReasonCode = keyof typeof ErrorReason
export type ErrorReason = typeof ErrorReason[keyof typeof ErrorReason]

export function getErrorReason(reasonCode: ErrorReasonCode): ErrorReason {
  return ErrorReason[reasonCode]
}

const api = () => {
  const reasonCode = "01"
  return {
    status:200,
    data:{
      reasonCode,
      reason: getReason(reasonCode),
    }
  }
}

constオブジェクト (ErrorReason + ReasonCode) ( +関数なし)

export const ErrorReasonCode = {
  REQUIRED: "01",
  // ...
} as const

export type ErrorReasonCode = typeof ErrorReasonCode[keyof typeof ErrorReasonCode]

export enum ErrorReason = {
  ErrorReasonCode.REQUIRED: "必須入力項目です",
  // ...
} as const

export type ErrorReason = typeof ErrorReason[keyof typeof ErrorReason]


const api = () => {
  const reasonCode = ErrorReasonCode.REQUIRED
  return {
    status:200,
    data:{
      reasonCode,
      reason: ErrorReason[reasonCode],
    }
  }
}
1Like

皆様、ご丁寧な回答と有益な記事の共有いただきありがとうございます。
大変勉強になりました。たくさんのパターンを知ることができました。今後はコード規約などと見比べてプロダクトにあったコードにできるよう努力していきたいと思います。

本当にありがとうございました。

0Like

Your answer might help someone💌