技術とかの雑なToday I Learnedメモ

今日のタブ記事、悩み、JS/TSのプリミティブ型とラッパーオブジェクト

今日のタブ記事

Next.js + MDX でブログを書いていますを読んだ。

Next.js と、MDX というマークダウンの中に JSX を書けるフォーマットでブログを作った話。

MDX、ぱっと見てみると頭がこんがらがる……!(以下記事から引用)

import Button from '../components/button.js'

# MDX + Next.js

Look, a button! 👇

<Button>👋 Hello</Button>

import 文を見た瞬間に頭が JSX だと認識するけど、次の行の#で「あれ、このコメントの方式は Ruby だったような……?」みたいな感じでバグってしまうし、3 行目の通常の文章が逆に異質に見えてしまう。

でもこれ慣れたら便利そうだな〜と思い、日付を見たら 2019 年の記事だった。2019 年で Next.js を使ってブログを作ってるってすごいなあ。

TypeScript のプリミティブ型の大文字と小文字

たとえば、

const moji: string = 'hoge'

みたいな感じで型をつけるときってstringと小文字で書く場合もあれば、Vue の props を定義するときに

props: {
  moji: {
    type: String,
    default: 'hoge
  },
}

みたいにStringと最初だけ大文字のときもある。

これは一体なんぞや……どっちをどのタイミングで使えばいいんだ?となり調べてみた。

タイプスクリプトのプリミティブ型というちょっと怪しい翻訳の記事がヒットしたので読んでみたら、

JavaScript コードで適切に使用されることはほとんどない非プリミティブボックスオブジェクトを参照します。(引用)

と書いてあり、非プリミティブボックスオブジェクト?というよくわからない言葉が出てきたので調べたところ、ラッパーオブジェクトなるものがあることが分かった。

ラッパーオブジェクト

jsprimer のラッパーオブジェクトによると、

  • Boolean, Number, String, Symbol にはそれぞれ対応するオブジェクトが存在する
  • それぞれのオブジェクトを new することでそのオブジェクトのインスタンスを使える
    • たとえば String なら
const str = new String('hoge')
str.toUpperCase() // => "HOGE"
  • 上記のように、プリミティブ型のオブジェクトをインスタンス化すると、「そのプリミティブ型の値を包んだオブジェクト」ができあがる
  • これを「その型の値を包んだオブジェクト」ということでラッパーオブジェクトと呼ぶ
  • null と undefined にはラッパーオブジェクトは存在しない
  • ラッパーオブジェクトは名前の通り Object 型で、typeof を使うと object になる。
const str = 'hoge'
console.log(typeof str) // => "string"

const str2 = new String('hoge')
console.log(typeof str2) // => "object"

自動変換

プリミティブ型の値に対してプロパティアクセスをすると自動的にラッパーオブジェクトに変換されるらしい。

つまり、

const str = 'hoge'
str.toUpperCase() // <= ここでラッパーオブジェクトに変換されてるのでプロパティアクセスできる
// (new String(str)).toUpperCase() と同じらしい

逆に、ラッパーオブジェクトから値を取り出すときはvalueOfを使うらしい。

const strObj = new String('hoge')
console.log(strObj.valueOf()) // => "hoge"

こんな感じで、プリミティブな値 <=> ラッパーオブジェクトの変換は自動でやってくれている。

どっちを使うほうがいいかは、基本的にリテラルを使ったプリミティブな値を使ったほうがいいということらしい。理由は

  • 必要に応じてプリミティブな値からラッパーオブジェクトに変換される
  • ラッパーオブジェクトを常に使う利点がない
  • typeof の評価が object になるため混乱する

まあ実際に自動で変換してくれるなら、使いたいプロパティにアクセスするまで全てのプロパティを内包する必要もなさそうだしなるほどといった感じ。

で、結局

そういえば大文字と小文字の使いわけの話だったのに全然違う話になってしまった。

自分でふと考えたけど、Vue の props に渡すときは{ type: String }で、これは別に「TypeScript の構文ではなくて Object の value としてStringを渡している」ということだと思う。

{ type: string }と書いたら構文エラーになったけど、'string' only refers to a type, but is being used as a value here.Vetur(2693)というエラーを見るに「型を参照したいのに値を渡してるぞ」みたいな感じっぽいので、Vue 側で受け取る値の型定義的なものだと思う。

ちなみに{ type: Stirng as PropType<string>}だといけた。えぇ……

Composition API にするときに Options API の props の定義方法をガラリと崩したら混乱するからあんま変えないでおこう、でも PropTypes というやつで拡張できるようにしよう、という感じなんだろうか。

悩み

  • コードを読むスピードが遅い
  • コードを読んで理解してもすぐ忘れる
  • 仕様理解はどうすれば進むのか
  • 仕様は全部メモらないと忘れる

みたいな悩みがある。

そもそもプロダクトの仕様理解がなかなかうまく効率的にできなくて、実装中にわからなくなって手が止まって……みたいな感じで実装スピードに影響が出る。

もしかして仕様をコード読んだりプロダクトを触ったりして全て網羅して言語化しておくしかないのだろうか。

頭が悪すぎて単に理解力がないというだけなのだろうか……。

今のチームに入って間もないのだけど、仕様理解が全然進まないので一回時間を取って仕様を全部書き出すようなことをやってみようかと思うんだけど、それが効率の悪いやり方だとしたらと思うと手が動かない。

誰か助けて。