セルへ=関数名(A2)と書いて使うGASのカスタム関数は、エディタの実行ボタンから動かす関数と同じ権限・用途ではありません。セルの計算に使う仕組みなので、別の場所を書き換える処理や、利用者の承認が必要なサービスで止まることがあります。
表の数値を計算するだけなら、入力を引数として受け取り、計算結果を返す小さな関数が向いています。メール送信や別ファイルの更新まで詰め込む前に、カスタム関数として許される範囲を確かめます。
入力から計算結果を返す例
次は金額へ手数料を加える関数です。数字として入力された値だけを扱い、文字列の金額を推測して数値化しません。関数名が既存のスプレッドシート関数と重ならないよう、練習用の名前を付けています。
/**
* 金額に固定の手数料を加えます。
* @param {number|Array<Array<number>>} values 金額または金額の範囲
* @param {number} fee 0以上の手数料
* @return {number|Array<Array<number>>} 計算結果
* @customfunction
*/
function PRACTICE_ADD_FEE(values, fee) {
if (typeof fee !== 'number' || !Number.isFinite(fee) || fee < 0) {
throw new Error('手数料は0以上の数値で指定してください');
}
const add = function (value) {
if (value === '') return '';
if (typeof value !== 'number' || !Number.isFinite(value)) {
throw new Error('金額は数値で指定してください');
}
const total = value + fee;
if (!Number.isFinite(total)) throw new Error('計算結果が範囲外です');
return total;
};
return Array.isArray(values) ? values.map(row => row.map(add)) : add(values);
}
A2へ100、A3へ200を入れ、B2に=PRACTICE_ADD_FEE(A2:A3,50)と指定すると、期待する結果はB2が150、B3が250です。B3は結果を展開する先なので空けます。A列の空欄は空欄で返します。空欄を手数料だけの金額にしないという、この例の業務上の決め方です。
任意のセルを書き換えられない
公式のカスタム関数のガイドでは、値を返すセルとその隣へ結果を展開すること、任意のセルを書き換えないことが示されています。別シートの状態欄へ「完了」と記入するような処理は、計算結果を返す関数とは分けます。
2次元配列の結果が広がる場所に既存の値がある場合は、上書きする代わりにエラーになります。上の例ならB3へメモを入れた状態と、空欄にした状態を比べます。結果が出ないからといって、周囲の値を自動で消すコードを追加しないでください。
更新や通知を行う機能が必要なら、メニューやボタンから通常の関数を実行する構成にします。画面からの操作はHTML Serviceのサイドバーのように、利用者が処理を選んで実行できる形も候補です。
承認と実行時間の制約
カスタム関数は、個人データへのアクセスについて利用者へ承認を求める仕組みではありません。利用できるサービスは公式一覧で確認します。通常の関数で承認を済ませたからといって、そのサービスをカスタム関数でも自由に使えるわけではありません。
公式資料は1回のカスタム関数が30秒以内に値を返す条件を示しています。外部通信を何件も重ねたり、長い待機を入れたりする処理はこの用途に合いません。通常実行の割当と同じ時間だと考えないようにします。
NOW()やRAND()のように計算のたびに変わる値を引数へ渡す使い方にも制限があります。再計算を起こすために、目的と関係のない揮発性の関数を付け足す方法は避けます。
再計算させたい値は引数に渡す
参照元を関数の内部でこっそり読み取るより、A2:A3のように引数へ明示すると、どの値が計算に関係するかをシートから確認できます。手数料も別セルへ置くなら、そのセル参照を第2引数へ渡します。
ローカルで確認したのは、単一金額、2次元配列、空欄、不正な値と手数料の計算です。Google上の再計算、承認、配列の展開は未確認です。GAS全体の実行方法との違いはGASの始め方から整理できます。
