はじめに
- Nuxt3 + TypeScriptを使用した実装でハマったこと
- コードを書く上でReadonlyとreadonly()の違いを認識できておらずハマってしまった
- そもそもreadonly()という関数は勝手にプロパティに対して'readonly' 修飾子を付与してくれるものだと勘違いしていた
Readonly<T>
と readonly()
は別物
そもそもではありますが、Readonlyとreadonly()は別物になります
まず、Readonly<T>
はTypeScriptのユーティリティ型のひとつになります
そして、readonly()
はVueが提供する関数のひとつになります
それぞれ読み取り専用にしてくれるという機能だが...?
それぞれ「受け取ったオブジェクトに対して読み取り専用にする」という機能であるが、
そのプロパティに対して 「読み取り専用にする深さ」 が違います
深い・浅いとは?
- Readonlyに関しては受け取ったオブジェクトの直下プロパティしか読み取り専用にしてくれません
- ですが、readonly()はネストされたプロパティに対しても読み取り専用にしてくれます
勘違いしてしまったコード
provide/inject を使用しつつ、injectの出しどころを制御したやつ
import type { User } from '...'
import type { InjectionKey } from 'vue'
interface UserState {
user: Readonly<Ref<User | null>>
setUser: (_user: User) => void
}
export const UserSymbol: InjectionKey<UserState> = Symbol('UserSymbol')
export function provideUserState () {
const user = ref<User | null>(null)
const setUser = (_user: User): void => {
user.value = _user
}
const userState = {
user: readonly(user),
setUser
}
provide(UserSymbol, userState) // ← userStateで型エラー
return userState
}
export function injectUserState (): UserState {
const userState = inject(UserSymbol)
if (!userState) {
console.log('userState', userState)
throw new Error('userState is undefined')
}
return userState
}
UserStateインターフェースに対して、userStateを当て込めようとしたが型エラーで怒られる
気をつけたい
readonly()
は返り値として、DeepReadonly
を返すため Readonly<T>
と混同しないようにしたい
interface UserState {
user: DeepReadonly<Ref<User | null>> // Readonly→DeepReadonly
setUser: (_user: User) => void
}
export const UserSymbol: InjectionKey<UserState> = Symbol('UserSymbol')
export function provideUserState () {
const user = ref<User | null>(null)
:
const userState = {
user: readonly(user), // DeepReadonlyが返ってくるよ!
setUser
}
}
provide(UserSymbol, userState)
宣伝
自分が所属している会社についても紹介させてください 🙇♂️
弊社では物流課題解決や荷物を配送するドライバーの価値を向上させるために
「ピックゴー」 というサービスを運用しています
あと、那覇Baseが本店になりました
10月25日に自分のいる那覇Baseが本店になりました🎉
自社開発したい方やエンジニアとして成長したい方など少しでも興味ありましたらカジュアル面談や会社説明会も開催していますの気軽にお問い合わせください!