Typescriptの関数の引数optionalになりがち問題
読者の問題提起と解決策の提案
TypeScriptで関数を定義する時、引数をオプショナル(optional)にすることが多いですよね。便利な機能ですが、場合によっては予期しない動作を引き起こすことがあります。この記事では、この問題を解決する方法を具体例を通じて紹介します。
概要
関数の引数をオプショナルにする問題
TypeScriptでは、関数の引数をオプショナルにできます。しかし、これによって関数が予期しない動作をしたり、不正な引数が渡されたりすることがあります。
使用技術
- TypeScript
具体例と詳細説明
例1: 単純なSMS送信関数
まず、単純なSMS送信関数を見てみましょう。
const greatToSms = ({ me, to, toSms, text }: { me: string; to: string; toSms: PhoneNumber; text: string }) => {
sendToSms({ to: toSms, text: `Hi ${to}, ${me} says: ${text}` })
}
const sendToSms = ({ to, text }: { to: string; text: string }) => {
console.log(`Sending SMS to ${to} with text: ${text}`)
}
この関数は正しく動作しますが、仕様変更に対応する必要が出てくることがあります。
例2: SMSまたはEmail送信関数
次に、SMSだけでなくEmailにも対応するように仕様変更があったとしましょう。
const greatToSmsOrEmail = ({
me,
to,
sms,
email,
text,
}: { me: string; to: string; sms?: PhoneNumber; email?: Email; text: string }) => {
if (sms) {
sendToSms({ to: sms, text: `Hi ${to}, ${me} says: ${text}` })
}
if (email) {
sendToEmail({ to: email, text: `Hi ${to}, ${me} says: ${text}` })
}
}
この実装でも動作しますが、予期しない動作や不正な引数が発生する可能性があります。
実際のプロダクトでは実装が楽だからといって、このように書かれることが多いですが、かなり危険です。筆者は実務で、このコードのようにsms
とemail
が両方nullになってしまい、想定された動作をせず機能が動かないというケースを見てきました。
解決方法
以下のコードでは、引数をより厳密に定義しています。
const greatToSmsOrEmail = ({
me,
to,
sms,
email,
text,
}: { me: string; to: string; text: string } & ({ sms: PhoneNumber; email?: never } | { email: Email; sms?: never })) => {
if (sms) {
sendToSms({ to: sms, text: `Hi ${to}, ${me} says: ${text}` })
}
if (email) {
sendToEmail({ to: email, text: `Hi ${to}, ${me} says: ${text}` })
}
}
この方法により、関数の引数が厳密に管理され、予期しない動作を防ぐことができます。
このように実装することで、以下のような実装ミスが発生した場合でも、TypeScriptの型エラーで防ぐことができます。
if (sms) {
sendToSms({ to: sms, text: `Hi ${to}, ${me} says: ${text}` })
}
if (email) {
sendToEmail({ to: sms, text: `Hi ${to}, ${me} says: ${text}` }) // 型エラーが発生
}
メリット・デメリット
メリット
- 厳密な型定義により、予期しない動作を防止
- 不正な引数の代入を防ぐ
デメリット
- コードが少し複雑になる
総括と結論
TypeScriptの関数において引数をオプショナルにすることは便利ですが、仕様変更や予期しない動作を防ぐために、引数を厳密に定義する方法も検討する価値があります。型定義をしっかり行いましょう!
参考記事
この記事を通して、TypeScriptの関数引数をより適切に扱う方法を学び、プロジェクトでの活用を目指しましょう。