関数は、その引数の型が取りうる値を全てサポートする責任がある
例えば、3つのboolean型を引数に取る関数があった場合
code:ts
const f = (a: boolean, b: boolean, c: boolean) => {..}
どんな組み合わせの3つが来たとしても処理を全うしないといけない
numberやstringだともっとパターン数が増える
numberが引数の場合、
負数も
0も
小数も
整数も
正数も
でけー数も
いずれが来ても正常に処理する必要がある
stringが引数の場合、
空文字も
1文字も、
なげー文字も
いずれが来ても正常に処理する必要がある
recordの場合も同様で、
code:1.ts
type X = {
a: A1 | A2;
b: B1 | B2;
}
const f = (x: X) => {..}
以下の4パターンを正常に処理する必要がある
{ a: A1, b: B1}
{ a: A1, b: B2}
{ a: A2, b: B1}
{ a: A2, b: B2}
型が荒くなれば荒くなるほど、
サポートしないといけない組み合わせが増える
関数を定義する際に考えるべきこと
そもそも、その引数は全て必要なものか?
処理には不要なものが紛れ込んでいないか?
型を絞って許容するものを制限する
本当に数値全てを取るのか?
1|2|3で十分だったりはしないか
本当に文字列すべてを取るのか?
\`id${number}\`で表現できたりしないか
1.tsは本当に4パターンなのか?
本当に表現したかったのはこの2パターンではないのか?
code:2.ts
type X = { a: A1; b: B1 }
| { a: A2; b: B2 }
const f = (x: X) => {..}
でも、厳密にやりすぎるとそれはそれで大変になるので妥協が必要mrsekut.icon
どれだけ楽できるかは、その言語が持っている型システムの力にも依る
簡単な例で言えば、numberが、IntegerとFloatに分かれているとかも1つ
動的型付き言語の場合、「どんな値が来ても大丈夫」になっている必要がある
というかそもそもそういう思想なので、逆に言えば実装者は考えなくても良い(そんなことはないが)
だからどんな値が来てもクラッシュせずに、なんか良い感じのエラーで処理される
それが開発者の意図に沿うものかどうか知らんけど
このとき、LoginButtonが対応しなければならないパターンは4パターンに増えます。例えば「colorが"red"でhasShadowがtrueのパターンは存在しないから実装をサボろう」のような考え方をしてはいけません
わかるmrsekut.icon
Atomic Designのatomsはやや例外になる
いや別に「例外」ではないかmrsekut.icon
これを読んで思ったmrsekut.icon
atomsがやりたいことが、propsの制限であるのならば、↑の記事の「お勧めできません」の書き方で書くべき
でも実際、atomsの目的はそこではなく、統一的なstyleのあたったパーツを使いたい、というものなので、propsは制限されるべきではない
だから、今は必要ないpropsも全部受け取れるようにして、元のhtmlタグと同一なものとして扱えるようにしておく
これは別に「例外」ではないmrsekut.icon
「全ての引数をサポートしている」という意味には沿っている