2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Readonly<T>とreadonly()に気をつけよう!!!

Last updated at Posted at 2024-10-31

はじめに

  • Nuxt3 + TypeScriptを使用した実装でハマったこと
  • コードを書く上でReadonlyとreadonly()の違いを認識できておらずハマってしまった
  • そもそもreadonly()という関数は勝手にプロパティに対して'readonly' 修飾子を付与してくれるものだと勘違いしていた :rolling_eyes:

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)

宣伝

自分が所属している会社についても紹介させてください 🙇‍♂️
弊社では物流課題解決や荷物を配送するドライバーの価値を向上させるために
「ピックゴー」 というサービスを運用しています

image.png

あと、那覇Baseが本店になりました

10月25日に自分のいる那覇Baseが本店になりました🎉

自社開発したい方やエンジニアとして成長したい方など少しでも興味ありましたらカジュアル面談や会社説明会も開催していますの気軽にお問い合わせください!

2
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?