<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>香港居民</title>
    <link>https://opendive.tistory.com/</link>
    <description>누군가를 붙잡고 얘기하면 좋겠지만,
항상 누군가를 귀찮게 하기는 싫어서 그냥 적는다.</description>
    <language>ko</language>
    <pubDate>Sun, 12 Jul 2026 13:07:21 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Yeah-Panda</managingEditor>
    <image>
      <title>香港居民</title>
      <url>https://t1.daumcdn.net/cfile/tistory/2459274F5550514422</url>
      <link>https://opendive.tistory.com</link>
    </image>
    <item>
      <title>[Bash] Command</title>
      <link>https://opendive.tistory.com/766</link>
      <description>&lt;pre id=&quot;code_1750724653329&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 특정 폴더 찾기
find /Users/user/Library/pnpm -name &quot;my-module&quot; -type d

# type d의 의미
# -type d는 디렉토리(directory)만 찾으라는 옵션입니다.
# -type d: 디렉토리만 찾기
# -type f: 파일만 찾기
# -type l: 심볼릭 링크만 찾기

# 2&amp;gt;/dev/null의 의미
# 2&amp;gt;/dev/null는 에러 메시지를 숨기라는 옵션입니다.
# 2&amp;gt;: 표준 에러(stderr)를 리다이렉트
# /dev/null: 리눅스/맥의 &quot;휴지통&quot; 같은 곳 (아무것도 출력하지 않음)

find /Users/user/Library/pnpm -name &quot;my-module&quot; -type d 2&amp;gt;/dev/null

# /Users/user 폴더부터 시작해서 my-module이라는 이름의 디렉토리만 찾고 에러 메시지는 숨겨서 깔끔하게 결과만 보여줍니다


# 파일 이름을 변경합니다. 
# mv &amp;lt;original file&amp;gt; &amp;lt;target file name&amp;gt;

mv functions/httpClient.ts functions/http-client.ts

# 파일 내용을 클립보드에 복사합니다. 
cat ~/.zshrc | pbcopy&lt;/code&gt;&lt;/pre&gt;</description>
      <category>코드/Shell</category>
      <author>Yeah-Panda</author>
      <guid isPermaLink="true">https://opendive.tistory.com/766</guid>
      <comments>https://opendive.tistory.com/766#entry766comment</comments>
      <pubDate>Tue, 24 Jun 2025 09:26:24 +0900</pubDate>
    </item>
    <item>
      <title>[Pnpm] 전역 패키지와 Store</title>
      <link>https://opendive.tistory.com/765</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;pnpm package 를 삭제시 다음과 같은 오류를 만나는 경우&lt;/p&gt;
&lt;pre id=&quot;code_1750723567876&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;➜  playground git:(master) pnpm remove -g my-module
&amp;thinsp;ERR_PNPM_UNEXPECTED_STORE&amp;thinsp; Unexpected store location

The dependencies at &quot;/Users/user/Library/pnpm/global/5/node_modules&quot; are currently linked from the store at &quot;/Users/user/Library/pnpm/store/v10&quot;.

pnpm now wants to use the store at &quot;/Users/user/Library/pnpm/store/v3&quot; to link dependencies.

If you want to use the new store location, reinstall your dependencies with &quot;pnpm install&quot;.

You may change the global store location by running &quot;pnpm config set store-dir &amp;lt;dir&amp;gt; --global&quot;.
(This error may happen if the node_modules was installed with a different major version of pnpm)&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;pnpm의 전역 패키지와 store란?&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;1.&amp;nbsp; 전역 패키지(global package)&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-indent=&quot;0&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;pnpm add -g 패키지명&lt;/span&gt;&lt;span&gt;으로 설치한 패키지는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;전역(global)&lt;/span&gt;&lt;/span&gt;&lt;span&gt;으로 설치됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;이 패키지들은 보통 한 곳(예:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;/Users/user/Library/pnpm/global/5&lt;/span&gt;)에 모여 있습니다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-indent=&quot;0&quot;&gt;이 폴더 안에 여러 전역 패키지들이 들어 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.&amp;nbsp; store란?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pnpm은 패키지를 효율적으로 관리하기 위해&amp;nbsp;store라는 별도의 저장소를 사용합니다.&lt;/li&gt;
&lt;li&gt;store에는 실제 패키지 파일들이 저장되고,전역 패키지 폴더(예:&amp;nbsp;/Users/user/Library/pnpm/global/5/node_modules)에는이 store를&amp;nbsp;가리키는&amp;nbsp;심볼릭 링크(바로가기)가 만들어집니다.&lt;/li&gt;
&lt;li&gt;store의 위치는 예를 들어&amp;nbsp;/Users/user/Library/pnpm/store/v10처럼 보입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;에러 메시지의 의미&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 전역 패키지가&amp;nbsp;/Users/user/Library/pnpm/global/5에 설치되어 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;rarr; 전역 패키지들이 이 폴더에 모여 있다는 뜻입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;store는 /Users/user/Library/pnpm/store/v10입니다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;rarr; 실제 패키지 파일들은 이 store 폴더에 저장되어 있다는 뜻입니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;왜 문제가 생겼나요?&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;pnpm의 버전이 바뀌거나 설정이 바뀌면,&lt;/span&gt;store의 위치가 달라질 수 있습니다(예:&amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;/v10&lt;/span&gt;&amp;nbsp;&amp;rarr;&amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;/v3&lt;/span&gt;).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴 때, 전역 패키지 폴더와 store의 위치가 서로 다르면패키지 삭제/설치 시 에러가 발생할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;1.&amp;nbsp; store 위치를 맞춰서 삭제 (권장)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;에러 메시지에서 store 위치가 다르다고 나왔으니,&lt;/span&gt;&lt;span&gt;&lt;span&gt;store 위치를 기존과 동일하게 맞춘 뒤&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;삭제를 시도할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1750723776083&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pnpm config set store-dir /Users/user/Library/pnpm/store/v10 --global
pnpm remove -g my-module&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 하면 기존 전역 패키지와 store가 연결되어 정상적으로 삭제가 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;2.&amp;nbsp; pnpm을 최신 버전으로 업데이트 후 재시도&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;pnpm 버전이 달라서 생기는 문제일 수 있으니,&lt;/span&gt;&lt;span&gt;아래 명령어로 pnpm을 최신 버전으로 업데이트한 후 다시 시도해보세요.&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;af1b0f8b-3cf6-4d5f-ad62-bd709d7dd536&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1750723794375&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pnpm self-update
pnpm remove -g my-module&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;3.&amp;nbsp; 수동 삭제 (최후의 수단)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;위 방법이 모두 안 될 때는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;수동으로 심볼릭 링크와 store 파일을 직접 삭제&lt;/span&gt;&lt;/span&gt;&lt;span&gt;해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;심볼릭 링크 삭제&lt;/span&gt;&lt;/h4&gt;
&lt;div id=&quot;61ceb0fd-efc7-4603-8ac5-89fcf3e6e050&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-mode-id=&quot;shellscript&quot; data-keybinding-context=&quot;106&quot;&gt;
&lt;div style=&quot;background-color: #000000; color: #000000;&quot; data-uri=&quot;composer-code-block-anysphere://yzapsfgqck&quot;&gt;
&lt;div data-mprt=&quot;3&quot;&gt;
&lt;div data-mprt=&quot;6&quot;&gt;
&lt;div style=&quot;background-color: #000000;&quot;&gt;
&lt;div aria-hidden=&quot;true&quot;&gt;
&lt;pre id=&quot;code_1750723814692&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;rm -rf /Users/user/Library/pnpm/global/5/node_modules/my-module&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;store 내 실제 파일 삭제&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;store 내 my-module 관련 폴더도 직접 삭제할 수 있습니다.&lt;/span&gt;&lt;span&gt;(이 경로는 패키지마다 다를 수 있습니다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;1 번에 따라 진행한다면&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;1. store 위치를 기존 위치로 변경&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1750724024655&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  pnpm config set store-dir /Users/user/Library/pnpm/store/v10 --global&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;2. 전역 패키지 삭제&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1750724058261&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pnpm remove -g my-module&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3.&amp;nbsp;&lt;span&gt;&lt;span&gt;store 위치를 원래대로 복구&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 현재 pnpm이&amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;/Users/user/Library/pnpm/store/v3&lt;/span&gt;&lt;span&gt;을 사용하고 있다면:&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1750724087600&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pnpm config set store-dir /Users/user/Library/pnpm/store/v3 --global&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 하면 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;패키지 삭제도 정상적으로 되고, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;pnpm의 store 설정도 원래대로 돌아가 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;앞으로의 전역 패키지 관리도 문제없이 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>코드/Package manager(npm, pnpm)</category>
      <author>Yeah-Panda</author>
      <guid isPermaLink="true">https://opendive.tistory.com/765</guid>
      <comments>https://opendive.tistory.com/765#entry765comment</comments>
      <pubDate>Tue, 24 Jun 2025 09:18:35 +0900</pubDate>
    </item>
    <item>
      <title>[Pnpm] command list</title>
      <link>https://opendive.tistory.com/764</link>
      <description>&lt;pre id=&quot;code_1750723339088&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# config list
pnpm config list

pnpm ls -g

pnpm remove -g &amp;lt;package_name&amp;gt;

# store 폴더 위치 확인
pnpm store path

# store dir 설정
pnpm set store-dir &amp;lt;directory_path&amp;gt;

# pnpm 이 현재 사용하고 있는 store 위치 확인
pnpm get store-dir&lt;/code&gt;&lt;/pre&gt;</description>
      <category>코드/Package manager(npm, pnpm)</category>
      <author>Yeah-Panda</author>
      <guid isPermaLink="true">https://opendive.tistory.com/764</guid>
      <comments>https://opendive.tistory.com/764#entry764comment</comments>
      <pubDate>Tue, 24 Jun 2025 09:04:58 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt-Module] Livecycle hooks</title>
      <link>https://opendive.tistory.com/763</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt 의 Livecycle hook 은 두 가지 방법으로 선언할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739234820492&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default defineNuxtModule&amp;lt;ModuleOptions&amp;gt;({
  meta: {
    name: 'nuxt-basic-optimizer',
    configKey: 'nuxtBasicOptimizer'
  },
  // Default configuration options of the Nuxt module
  defaults: {
  },
  hooks: {
    'app:resolve': (nuxt) =&amp;gt; {
      console.log('App resolvec', nuxt);
    }
  },
  setup(options, nuxt: Nuxt) {
    nuxt.hook('app:resolve', (nuxtApp: NuxtApp) =&amp;gt; {
      console.log('app resolve hook is called', nuxtApp);
  });
 })&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;setup 에 nuxt.hook 과 defineModule 자체의 property hooks 로 접근할수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만&amp;nbsp; hooks property 에서는 setup 에서 파라미터로 전달되는 options 대한 접근이 어렵습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hooks property 로 별도 선언시 가독성 향상을 가져올수있으나 그에 따른 단점이 존재합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>코드/Nuxt3</category>
      <author>Yeah-Panda</author>
      <guid isPermaLink="true">https://opendive.tistory.com/763</guid>
      <comments>https://opendive.tistory.com/763#entry763comment</comments>
      <pubDate>Tue, 11 Feb 2025 10:38:34 +0900</pubDate>
    </item>
    <item>
      <title>[Typescript] unknown은 any 의 counterpart</title>
      <link>https://opendive.tistory.com/761</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;1. &lt;/span&gt;any와 unknown의 기본적인 차이&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;특성&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;any&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;unknown&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;제한&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;아무런 제한 없음&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;모든 작업이 제한됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;타입 검사&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;런타임시 타입 오류를 방지하지 않음&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;컴파일시 타입 확인이 필요함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;유연성&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;매우 유연함(모든 타입에 할당 가능)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;안전함(할당은 가능하지만 사용은 제한됨)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. any&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;any는 &amp;ldquo;아무거나 될 수 있음&amp;rdquo;을 의미하며, 모든 작업이 허용됩니다.&lt;/li&gt;
&lt;li&gt;안전성이 낮음: 타입스크립트가 타입 검사를 포기하므로, 런타임 오류가 발생할 가능성이 높습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1738566739789&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let value: any = &quot;Hello&quot;;
value.foo(); // 런타임 오류 발생 가능하지만 컴파일러가 경고하지 않음&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. unknown&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;unknown은 &amp;ldquo;아직 타입을 알 수 없음&amp;rdquo;을 의미하며, 특정 타입으로 명확히 확인되기 전까지 사용이 제한됩니다.&lt;/li&gt;
&lt;li&gt;안전성이 높음: 값을 사용하려면 타입을 좁히거나(type narrowing) 타입 단언(type assertion)을 해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1738566761984&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let value: unknown = &quot;Hello&quot;;
value.foo(); // 컴파일 오류: 'foo' 속성을 사용할 수 없음

if (typeof value === &quot;string&quot;) {
  console.log(value.toUpperCase()); // 타입이 좁혀진 후에는 안전하게 사용 가능
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. any와 unknown의 관계&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;공통점:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘 다 모든 타입의 값을 할당받을 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738566780258&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let value1: any = 42;
let value2: unknown = 42; // 모두 허용&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;차이점:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;any는 아무 작업이나 허용: 어떤 속성 접근이나 연산도 제한이 없습니다.&lt;/li&gt;
&lt;li&gt;unknown은 제한적: 값을 사용하려면 반드시 타입 확인을 거쳐야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 왜 unknown이 any의 counterpart인가?&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;any는 타입 검사와 안전성을 포기한 &amp;ldquo;최대 유연성&amp;rdquo;을 제공합니다.&lt;/li&gt;
&lt;li&gt;반대로, unknown은 타입 안정성을 유지하기 위해 유연성을 제한합니다.&lt;/li&gt;
&lt;li&gt;두 타입 모두 &amp;ldquo;모든 타입의 값을 받을 수 있다&amp;rdquo;는 공통점을 가지지만, 사용 방식과 안전성에서 대조적입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6. 실제 사용 시 예&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;any: 빠르게 개발하거나 타입 검사에 신경 쓰지 않을 때 사용하지만, 권장되지 않습니다.&lt;/li&gt;
&lt;li&gt;unknown: 타입을 미리 알 수 없지만, 이후 타입 확인을 통해 안전하게 사용하고자 할 때 적합합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요약하자면, &lt;span&gt;unknown&lt;/span&gt;은 &lt;span&gt;any&lt;/span&gt;와 대조적으로 타입 안정성을 유지하기 위한 타입스크립트의 도구입니다. &amp;ldquo;counterpart&amp;rdquo;라는 표현은 이 대조적인 특성을 나타냅니다.  &lt;/p&gt;</description>
      <category>코드/Typescript</category>
      <author>Yeah-Panda</author>
      <guid isPermaLink="true">https://opendive.tistory.com/761</guid>
      <comments>https://opendive.tistory.com/761#entry761comment</comments>
      <pubDate>Mon, 3 Feb 2025 16:14:41 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt] toJSON 이 선언된 api 응답</title>
      <link>https://opendive.tistory.com/760</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt에서 API 엔드포인트로부터 반환되는 객체가 &lt;span&gt;toJSON&lt;/span&gt; 메서드를 포함하고 있다면, 해당 객체가 &lt;b&gt;직렬화(Serialization)&lt;/b&gt; 또는 &lt;b&gt;JSON 변환&lt;/b&gt; 과정에서 &lt;span&gt;toJSON&lt;/span&gt; 메서드가 호출될 수 있습니다. 이를 이해하려면 Nuxt와 관련된 데이터 흐름 및 &lt;span&gt;toJSON&lt;/span&gt;의 역할을 살펴볼 필요가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. toJSON과 직렬화&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;toJSON&lt;/span&gt;은 객체를 JSON 문자열로 변환하거나, JSON.stringify 함수가 호출될 때 특정 형태로 변환하려는 목적에 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;Nuxt에서 API의 응답 데이터가 처리되는 단계에서 &lt;b&gt;JSON.stringify&lt;/b&gt;가 호출될 가능성이 있는 경우, &lt;span&gt;toJSON&lt;/span&gt;이 실행됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. Nuxt에서의 API 데이터 흐름&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt는 일반적으로 Axios와 같은 HTTP 클라이언트를 사용하여 API로부터 데이터를 가져옵니다. 다음은 API 응답 데이터의 처리 과정입니다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;1.&lt;span&gt; &lt;/span&gt;&lt;b&gt;API 호출&lt;/b&gt;: 서버에서 데이터를 반환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;2.&lt;span&gt; &lt;/span&gt;&lt;b&gt;Axios 또는 Fetch 처리&lt;/b&gt;:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;데이터를 JSON으로 자동 파싱합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;이 과정에서 반환된 객체가 &lt;span&gt;toJSON&lt;/span&gt; 메서드를 포함하고 있는 경우, 필요에 따라 &lt;span&gt;toJSON&lt;/span&gt; 메서드가 호출될 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;3.&lt;span&gt; &lt;/span&gt;&lt;b&gt;컴포넌트나 스토어에서 데이터 사용&lt;/b&gt;:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;toJSON&lt;/span&gt; 메서드가 호출되었다면, 데이터는 직렬화된 JSON 형태로 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 동작 원리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;toJSON&lt;/span&gt;이 포함된 객체가 반환되는 경우, 실제 사용 시 동작 방식은 다음과 같습니다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예제 1: 기본적인 API 호출&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1737593607321&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// API 응답으로 반환되는 객체
const apiResponse = {
  name: &quot;Alice&quot;,
  age: 30,
  toJSON() {
    return { name: this.name }; // age는 직렬화되지 않음
  }
};

// Axios를 사용한 Nuxt API 호출
export default {
  async asyncData({ $axios }) {
    const data = await $axios.$get('/api/user');
    console.log(data); // { name: &quot;Alice&quot; }
  }
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;API 반환 객체&lt;/b&gt;에 &lt;span&gt;toJSON&lt;/span&gt; 메서드가 정의된 경우, Axios는 데이터를 JSON으로 직렬화하며 &lt;span&gt;toJSON&lt;/span&gt; 메서드를 호출합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;최종적으로 &lt;span&gt;JSON.stringify&lt;/span&gt;에서 반환된 값(즉, &lt;span&gt;{ name: &quot;Alice&quot; }&lt;/span&gt;)이 Nuxt 컴포넌트로 전달됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예제 2: 서버 사이드 렌더링(SSR)에서 toJSON&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt의 SSR에서 데이터를 직렬화하여 HTML에 삽입하거나 클라이언트로 전달할 때, 내부적으로 &lt;span&gt;JSON.stringify&lt;/span&gt;를 호출할 수 있습니다. 이 경우에도 &lt;span&gt;toJSON&lt;/span&gt;이 호출됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1737593650527&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default {
  async asyncData({ $axios }) {
    const user = await $axios.$get('/api/user');
    return { user }; // user 객체의 toJSON 메서드가 작동할 수 있음
  }
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;asyncData&lt;/span&gt;에서 반환된 데이터(&lt;span&gt;user&lt;/span&gt;)는 서버에서 JSON 직렬화를 거치므로, &lt;span&gt;toJSON&lt;/span&gt; 메서드가 실행될 가능성이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. toJSON이 실제 동작하는 경우&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;toJSON&lt;/span&gt; 메서드가 Nuxt에서 호출될 수 있는 대표적인 경우는 다음과 같습니다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;1.&lt;span&gt; &lt;/span&gt;&lt;b&gt;API 응답 직렬화&lt;/b&gt;: Axios와 같은 HTTP 클라이언트가 데이터를 JSON으로 변환하는 경우.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;2.&lt;span&gt; &lt;/span&gt;&lt;b&gt;서버에서 클라이언트로 상태 전달&lt;/b&gt;: Nuxt의 SSR에서는 상태를 JSON으로 직렬화하여 HTML에 포함하므로, 이 과정에서 &lt;span&gt;toJSON&lt;/span&gt;이 호출될 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;3.&lt;span&gt; &lt;/span&gt;&lt;b&gt;클라이언트 측 JSON 변환&lt;/b&gt;: &lt;span&gt;JSON.stringify&lt;/span&gt;를 직접 호출하는 경우.&lt;/p&gt;</description>
      <category>코드/Nuxt3</category>
      <author>Yeah-Panda</author>
      <guid isPermaLink="true">https://opendive.tistory.com/760</guid>
      <comments>https://opendive.tistory.com/760#entry760comment</comments>
      <pubDate>Thu, 23 Jan 2025 09:55:06 +0900</pubDate>
    </item>
    <item>
      <title>(Typescript) as unknown as typeof data</title>
      <link>https://opendive.tistory.com/759</link>
      <description>&lt;pre id=&quot;code_1737590750517&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { stringify } from 'devalue';
export default defineEventHandler(async (event) =&amp;gt; {
  const data = {
    createAt: new Date()
  }
  const dataToJSON = {
    ...data,
    toJSON() {
      return this;
    }
  }
  return stringify(data) as unknown as typeof dataToJSON;
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;as unkonwn as typeof dataJSON 이라는 표현이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TypeScript에서 type assertion을 사용하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; data-keybinding-context=&quot;109&quot; data-href=&quot;file:///Users/user/Monday/nuxt-datafetch/server/api/date.ts#3%2C9&quot;&gt;&lt;span&gt;as unknown as typeof data&lt;/span&gt;&lt;/a&gt;로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; data-keybinding-context=&quot;110&quot; data-href=&quot;file:///Users/user/Monday/nuxt-datafetch/server/api/date.ts#3%2C9&quot;&gt;&lt;span&gt;data&lt;/span&gt;&lt;/a&gt;의 타입을 강제로 지정하는 것입니다. 이를 단계별로 설명하겠습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #f6f8fa; color: #586069; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;as unknown&lt;/b&gt;: 먼저, 어떤 타입이든&lt;span&gt;&amp;nbsp;&lt;/span&gt;unknown&lt;span&gt;&amp;nbsp;&lt;/span&gt;타입으로 변환합니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;unknown&lt;span&gt;&amp;nbsp;&lt;/span&gt;타입은 모든 값이 할당될 수 있는 타입입니다. 이는 타입 안전성을 높이기 위해 사용됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a style=&quot;color: #000000;&quot; data-keybinding-context=&quot;111&quot; data-href=&quot;file:///Users/user/Monday/nuxt-datafetch/server/api/date.ts#3%2C9&quot;&gt;&lt;span&gt;as typeof data&lt;/span&gt;&lt;/a&gt;&lt;/b&gt;: 그 다음,&lt;span&gt;&amp;nbsp;&lt;/span&gt;unknown&lt;span&gt;&amp;nbsp;&lt;/span&gt;타입을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; data-keybinding-context=&quot;112&quot; data-href=&quot;file:///Users/user/Monday/nuxt-datafetch/server/api/date.ts#3%2C9&quot;&gt;&lt;span&gt;data&lt;/span&gt;&lt;/a&gt;의 타입으로 다시 변환합니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; data-keybinding-context=&quot;113&quot; data-href=&quot;file:///Users/user/Monday/nuxt-datafetch/server/api/date.ts#3%2C9&quot;&gt;&lt;span&gt;typeof data&lt;/span&gt;&lt;/a&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; data-keybinding-context=&quot;114&quot; data-href=&quot;file:///Users/user/Monday/nuxt-datafetch/server/api/date.ts#3%2C9&quot;&gt;&lt;span&gt;data&lt;/span&gt;&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;변수의 타입을 가져옵니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 이중 타입 선언은 타입스크립트의 타입 시스템을 우회하여 강제로 타입을 지정할때 사용됩니다. 일반적으로 타입을 정확히 추론할수 없거나, 개발자가 타입을 더 명확하게 지정하고자 할때 사용됩니다.&lt;/p&gt;</description>
      <category>코드/Typescript</category>
      <author>Yeah-Panda</author>
      <guid isPermaLink="true">https://opendive.tistory.com/759</guid>
      <comments>https://opendive.tistory.com/759#entry759comment</comments>
      <pubDate>Thu, 23 Jan 2025 09:11:35 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt] Payload serialized by devalue</title>
      <link>https://opendive.tistory.com/758</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt에서 &lt;span&gt;useAsyncData&lt;/span&gt;와 &lt;span&gt;useFetch&lt;/span&gt;는 서버 사이드 렌더링(SSR) 과정에서 데이터를 가져온 후, 해당 데이터를 클라이언트로 전달하기 위해 &lt;span&gt;payload&lt;/span&gt;에 직렬화합니다. 이때 Nuxt는 JavaScript 객체를 안전하고 정확하게 직렬화하기 위해 &lt;a href=&quot;https://github.com/Rich-Harris/devalue&quot;&gt;&lt;span&gt;devalue&lt;/span&gt;&lt;/a&gt; 라이브러리를 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1.&amp;nbsp; 왜 devalue를 사용하는가?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;JSON.stringify&lt;/span&gt;만으로는 Nuxt의 직렬화 요구 사항을 충족할 수 없는 경우가 있습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Circular references(순환 참조): JSON.stringify는 순환 참조를 처리할 수 없습니다.&lt;/li&gt;
&lt;li&gt;Functions, Symbols, undefined: JSON.stringify는 이러한 데이터를 직렬화하지 않습니다.&lt;/li&gt;
&lt;li&gt;Prototype references: 특정 객체의 프로토타입 정보를 유지해야 할 경우 JSON.stringify는 이를 잃어버릴 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;devalue&lt;/span&gt;는 이러한 한계를 극복하고, 안전하면서도 SSR에서 복잡한 데이터를 클라이언트로 전달할 수 있도록 도와줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2.&amp;nbsp; Nuxt에서의 사용 흐름&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt는 SSR 렌더링 후 데이터를 클라이언트로 전달하기 위해 다음 과정을 거칩니다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;a. 서버 사이드 데이터 획득&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;useAsyncData나 useFetch를 호출하면 서버 측에서 API 호출 등의 작업을 통해 데이터를 가져옵니다.&lt;/li&gt;
&lt;li&gt;데이터는 서버 측에서 JSON 객체 형태로 관리됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;b. 데이터 직렬화 (devalue 사용)&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;데이터를 클라이언트로 보내기 전에 직렬화 과정이 필요합니다.&lt;/li&gt;
&lt;li&gt;이때 Nuxt는 devalue를 사용하여 데이터를 안전하게 문자열로 변환합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;c. 클라이언트로 전달&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;직렬화된 데이터는 Nuxt의 payload로 포함됩니다.&lt;/li&gt;
&lt;li&gt;이 payload는 클라이언트로 전달되고, HTML 문서 내 &amp;lt;script&amp;gt; 태그에 주입됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예)&lt;/p&gt;
&lt;pre id=&quot;code_1737077706782&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script&amp;gt;
  window.__NUXT__ = {
    data: [{ foo: 'bar', date: new Date(&quot;2025-01-17T00:00:00.000Z&quot;) }],
    state: {}
  };
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;d. 클라이언트 측 역직렬화&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;클라이언트는 payload 데이터를 읽고 JavaScript 객체로 복원합니다.&lt;/li&gt;
&lt;li&gt;복원 과정에서도 devalue의 역직렬화 처리가 포함됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Nuxt에서 devalue가 필요한 이유&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt는 SSR과 CSR을 원활하게 연결하기 위해 클라이언트가 서버에서 처리한 데이터를 정확히 사용할 수 있도록 보장해야 합니다. &lt;span&gt;devalue&lt;/span&gt;는 다음과 같은 데이터 유형을 처리하는 데 탁월합니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Date 객체: JSON.stringify는 Date 객체를 ISO 문자열로 변환하지만, devalue는 이를 유지합니다.&lt;/li&gt;
&lt;li&gt;RegExp 객체: 정규식을 문자열 대신 올바르게 직렬화합니다.&lt;/li&gt;
&lt;li&gt;Nested Structures: 깊은 중첩 객체를 처리하고, 순환 참조도 감지하여 에러를 방지합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. Nuxt 내부에서 devalue의 실제 사용 위치&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt 소스 코드에서 &lt;span&gt;devalue&lt;/span&gt;는 SSR에서 데이터를 직렬화할 때 다음 위치에서 사용됩니다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.&lt;span&gt; &lt;/span&gt;&lt;b&gt;서버에서 데이터 직렬화&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Nuxt의 renderPayload 함수에서 데이터 직렬화에 devalue를 호출합니다.&lt;/li&gt;
&lt;li&gt;소스 코드 예시(Nuxt 3 기준): 아래&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1737077770402&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { devalue } from 'devalue';

function renderPayload(data) {
  return devalue(data);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.&lt;span&gt; &lt;/span&gt;&lt;b&gt;클라이언트에서 직렬화된 데이터를 주입&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;bull; 서버에서 렌더링된 데이터를 HTML 문서 내에 &amp;lt;script&amp;gt;로 삽입합니다.&lt;/li&gt;
&lt;li&gt;클라이언트는 이 데이터를 복원해 재사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 참고 사항&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;보안 이슈&lt;/b&gt;: &lt;span&gt;devalue&lt;/span&gt;는 XSS 공격을 방지하기 위해 직렬화 과정에서 안전성을 보장합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;성능&lt;/b&gt;: &lt;span&gt;devalue&lt;/span&gt;는 JSON.stringify보다 약간 느릴 수 있지만, Nuxt의 기능 요구를 충족하는 데 필수적입니다.&lt;/p&gt;</description>
      <category>코드/Nuxt3</category>
      <author>Yeah-Panda</author>
      <guid isPermaLink="true">https://opendive.tistory.com/758</guid>
      <comments>https://opendive.tistory.com/758#entry758comment</comments>
      <pubDate>Fri, 17 Jan 2025 10:39:32 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt] Data serialized from interal api server</title>
      <link>https://opendive.tistory.com/757</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nuxt.com/docs/getting-started/data-fetching#serializing-data-from-server-to-client&quot;&gt;https://nuxt.com/docs/getting-started/data-fetching#serializing-data-from-server-to-client&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1737074238730&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Data Fetching &amp;middot; Get Started with Nuxt&quot; data-og-description=&quot;Nuxt provides composables to handle data fetching within your application.&quot; data-og-host=&quot;nuxt.com&quot; data-og-source-url=&quot;https://nuxt.com/docs/getting-started/data-fetching#serializing-data-from-server-to-client&quot; data-og-url=&quot;https://nuxt.com/docs/getting-started/data-fetching#serializing-data-from-server-to-client&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bH29mO/hyX4lRrjPH/aNKfcvFZxEQVBaD0w3E9wk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/coVPuJ/hyX0u3ANHf/NZ2pk285D9XWnySQapQ8Jk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://nuxt.com/docs/getting-started/data-fetching#serializing-data-from-server-to-client&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nuxt.com/docs/getting-started/data-fetching#serializing-data-from-server-to-client&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bH29mO/hyX4lRrjPH/aNKfcvFZxEQVBaD0w3E9wk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/coVPuJ/hyX0u3ANHf/NZ2pk285D9XWnySQapQ8Jk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Data Fetching &amp;middot; Get Started with Nuxt&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Nuxt provides composables to handle data fetching within your application.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nuxt.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt 는 서버에서 획득한 데이터를 payload 를 통해서 클라이언트로 동일하게 복사하여 전달합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nuxt.com/docs/api/composables/use-nuxt-app#payload&quot;&gt;https://nuxt.com/docs/api/composables/use-nuxt-app#payload&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1737074286539&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;useNuxtApp &amp;middot; Nuxt Composables&quot; data-og-description=&quot;Access the shared runtime context of the Nuxt Application.&quot; data-og-host=&quot;nuxt.com&quot; data-og-source-url=&quot;https://nuxt.com/docs/api/composables/use-nuxt-app#payload&quot; data-og-url=&quot;https://nuxt.com/docs/api/composables/use-nuxt-app#payload&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/mXpNk/hyX4ypIIBE/7eKad89bX5m2hdTWzO1u21/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/Xuz2W/hyX4nBIZrv/zrO9EYAJIZ3W466L9SUyp0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://nuxt.com/docs/api/composables/use-nuxt-app#payload&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nuxt.com/docs/api/composables/use-nuxt-app#payload&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/mXpNk/hyX4ypIIBE/7eKad89bX5m2hdTWzO1u21/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/Xuz2W/hyX4nBIZrv/zrO9EYAJIZ3W466L9SUyp0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;useNuxtApp &amp;middot; Nuxt Composables&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Access the shared runtime context of the Nuxt Application.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nuxt.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1737074601262&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script lang=&quot;ts&quot; setup&amp;gt;
const {data: timeData} = useAsyncData&amp;lt;Date&amp;gt;(() =&amp;gt; {
  return new Date();
}, {key: 'time', url: ''});

// get on the client slide
onMounted(() =&amp;gt; {
  alert(timeData.value?.getHours());
});
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 볼수 있는 것처럼 서버에서 획득한 데이터를 클라이언트 사이드에서 확인 할수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt 서버에서는 devalue 라는 라이브러리를 사용하여 payload 를 만든다음 클라이언트로 전달합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.npmjs.com/package/devalue&quot;&gt;https://www.npmjs.com/package/devalue&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1737074847565&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;devalue&quot; data-og-description=&quot;Gets the job done when JSON.stringify can't. Latest version: 5.1.1, last published: 4 months ago. Start using devalue in your project by running &amp;#96;npm i devalue&amp;#96;. There are 203 other projects in the npm registry using devalue.&quot; data-og-host=&quot;www.npmjs.com&quot; data-og-source-url=&quot;https://www.npmjs.com/package/devalue&quot; data-og-url=&quot;https://www.npmjs.com/package/devalue&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jAnc7/hyX4AnxfXZ/gf3JdlSk0nOLanfy0wK0ok/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://www.npmjs.com/package/devalue&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.npmjs.com/package/devalue&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jAnc7/hyX4AnxfXZ/gf3JdlSk0nOLanfy0wK0ok/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;devalue&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Gets the job done when JSON.stringify can't. Latest version: 5.1.1, last published: 4 months ago. Start using devalue in your project by running `npm i devalue`. There are 203 other projects in the npm registry using devalue.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.npmjs.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt 는 서버 endpoint 에서 데이터를 반환할때는 devalue 를 사용하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그로 인해 아래 코드는 오류가 발생합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1737077414760&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// /api/date.ts
export default defineEventHandler(async (event) =&amp;gt; {
  return new Date();
});

// .vue
&amp;lt;script lang=&quot;ts&quot; setup&amp;gt;
const {data: dateData} = await useFetch&amp;lt;Date&amp;gt;('/api/date');
onMounted(() =&amp;gt; {
  alert(dateData.value?.getHours());
})
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://opendive.tistory.com/758&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;nuxt 가 payload 를 직렬화 하는 과정&lt;/a&gt;&amp;nbsp;도 참고바랍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드의 경우 data 는 직렬화된 string 임으로 getHours 라는 메서드에 대한 참조가 이루어지지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 어떻게 internal api endpoint data를 직렬화해야 client 에서 사용 가능할까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nuxt.com/docs/getting-started/data-fetching#custom-serializer-function&quot;&gt;https://nuxt.com/docs/getting-started/data-fetching#custom-serializer-function&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1737592448170&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Data Fetching &amp;middot; Get Started with Nuxt&quot; data-og-description=&quot;Nuxt provides composables to handle data fetching within your application.&quot; data-og-host=&quot;nuxt.com&quot; data-og-source-url=&quot;https://nuxt.com/docs/getting-started/data-fetching#custom-serializer-function&quot; data-og-url=&quot;https://nuxt.com/docs/getting-started/data-fetching#custom-serializer-function&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ikXKE/hyX4rk3Vsa/DG7QyfjdPryVRwnhkxKIO1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/zLbe3/hyX4ptZHf9/XOz8fI3kOYLnCgK2DWWmvk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://nuxt.com/docs/getting-started/data-fetching#custom-serializer-function&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nuxt.com/docs/getting-started/data-fetching#custom-serializer-function&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ikXKE/hyX4rk3Vsa/DG7QyfjdPryVRwnhkxKIO1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/zLbe3/hyX4ptZHf9/XOz8fI3kOYLnCgK2DWWmvk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Data Fetching &amp;middot; Get Started with Nuxt&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Nuxt provides composables to handle data fetching within your application.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nuxt.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같은 형태로 개발자가 원하는 속성들이 선언된 object를 반환하는 방법입니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1737592487483&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default defineEventHandler(() =&amp;gt; {
  const data = {
    createdAt: new Date(),

    toJSON() {
      return {
        createdAt: {
          year: this.createdAt.getFullYear(),
          month: this.createdAt.getMonth(),
          day: this.createdAt.getDate(),
        },
      }
    },
  }
  return data
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 위 경우는 단순히 몇몇 property 들만 있으며,&amp;nbsp; date object 자체가 응답되진 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영 리소스가 많이 발생합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nuxt.com/docs/getting-started/data-fetching#using-an-alternative-serializer&quot;&gt;https://nuxt.com/docs/getting-started/data-fetching#using-an-alternative-serializer&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1737592608508&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Data Fetching &amp;middot; Get Started with Nuxt&quot; data-og-description=&quot;Nuxt provides composables to handle data fetching within your application.&quot; data-og-host=&quot;nuxt.com&quot; data-og-source-url=&quot;https://nuxt.com/docs/getting-started/data-fetching#using-an-alternative-serializer&quot; data-og-url=&quot;https://nuxt.com/docs/getting-started/data-fetching#using-an-alternative-serializer&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/L0rxz/hyX4mRxPX3/PHtKbi9qLohPjSUuO5K7t1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/sstXm/hyX4xlfiNZ/lwCDzDfYqrVzTTP79vrQo0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://nuxt.com/docs/getting-started/data-fetching#using-an-alternative-serializer&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nuxt.com/docs/getting-started/data-fetching#using-an-alternative-serializer&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/L0rxz/hyX4mRxPX3/PHtKbi9qLohPjSUuO5K7t1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/sstXm/hyX4xlfiNZ/lwCDzDfYqrVzTTP79vrQo0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Data Fetching &amp;middot; Get Started with Nuxt&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Nuxt provides composables to handle data fetching within your application.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nuxt.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대체 serializer 의 사용은 아직 nuxt 에서 제공되지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 우리는&amp;nbsp; toJSON 이라는 메서드가 선언된 객체를 생성하고 이를 직렬화하여 제공하는 방식으로 우회할수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 typescript의 타입 시스템에서 추론 가능하고 또한 runtime 에서 모두 동작하는 방법입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1737592985613&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import superjson from 'superjson'

export default defineEventHandler(() =&amp;gt; {
  const data = {
    createdAt: new Date(),

    // Workaround the type conversion
    toJSON() {
      return this
    }
  }

  // Serialize the output to string, using superjson
  return superjson.stringify(data) as unknown as typeof data
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;createAt 를 선언하여 date 객체를 담아 둔다음 toJSON 메서드를 선언하고 this 를 반환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;toJSON 메서드를 선언함으로써 타입 추론이 가능하도록 만듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nuxt 내에서 toJSON 이 동작하는 과정 :&amp;nbsp;&lt;a href=&quot;https://opendive.tistory.com/760&quot;&gt;https://opendive.tistory.com/760&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1737593736285&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Nuxt] toJSON 이 선언된 api 응답&quot; data-og-description=&quot;Nuxt에서 API 엔드포인트로부터 반환되는 객체가 toJSON 메서드를 포함하고 있다면, 해당 객체가 직렬화(Serialization) 또는 JSON 변환 과정에서 toJSON 메서드가 호출될 수 있습니다. 이를 이해하려면 Nuxt&quot; data-og-host=&quot;opendive.tistory.com&quot; data-og-source-url=&quot;https://opendive.tistory.com/760&quot; data-og-url=&quot;https://opendive.tistory.com/760&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/j3u3j/hyX4ld0Lt3/XPkzOCbAf0iv92fpusGSg0/img.png?width=225&amp;amp;height=225&amp;amp;face=0_0_225_225,https://scrap.kakaocdn.net/dn/b3hqU8/hyX4u9UAwM/2vZZ57aSQDBojoa8OwTDaK/img.png?width=225&amp;amp;height=225&amp;amp;face=0_0_225_225,https://scrap.kakaocdn.net/dn/iarWB/hyX4wfz6sN/zEurBe5QCwLaTKjoiUsTp1/img.jpg?width=474&amp;amp;height=360&amp;amp;face=0_0_474_360&quot;&gt;&lt;a href=&quot;https://opendive.tistory.com/760&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://opendive.tistory.com/760&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/j3u3j/hyX4ld0Lt3/XPkzOCbAf0iv92fpusGSg0/img.png?width=225&amp;amp;height=225&amp;amp;face=0_0_225_225,https://scrap.kakaocdn.net/dn/b3hqU8/hyX4u9UAwM/2vZZ57aSQDBojoa8OwTDaK/img.png?width=225&amp;amp;height=225&amp;amp;face=0_0_225_225,https://scrap.kakaocdn.net/dn/iarWB/hyX4wfz6sN/zEurBe5QCwLaTKjoiUsTp1/img.jpg?width=474&amp;amp;height=360&amp;amp;face=0_0_474_360');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Nuxt] toJSON 이 선언된 api 응답&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Nuxt에서 API 엔드포인트로부터 반환되는 객체가 toJSON 메서드를 포함하고 있다면, 해당 객체가 직렬화(Serialization) 또는 JSON 변환 과정에서 toJSON 메서드가 호출될 수 있습니다. 이를 이해하려면 Nuxt&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;opendive.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 위 예제에서는 superjson 을 이용하여 data 를 직렬화하며,&amp;nbsp;client 에서는 다시 superjson.parse 를 이용해 역 직렬화하였습니다.&amp;nbsp; &amp;nbsp;우리는 devalue 를 사용하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1737595470894&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { stringify } from 'devalue';
export default defineEventHandler(async (event) =&amp;gt; {
  const data = {
    createAt: new Date(),
        toJSON() {
      return this;
    }
  }
  return stringify(data) as unknown as typeof data;
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에 보시면 as unkonwn as typeof data 의 표현식이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입 추론과 런타임 참조를 위한 표현 방식입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;api endpoint 에서 어떤 타입을 반환하건 data 타입으로 추론하도록 강제합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://opendive.tistory.com/759&quot;&gt;https://opendive.tistory.com/759&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1737595552495&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;(Typescript) as unknown as typeof data&quot; data-og-description=&quot;import { stringify } from 'devalue';export default defineEventHandler(async (event) =&amp;gt; { const data = { createAt: new Date() } const dataToJSON = { ...data, toJSON() { return this; } } return stringify(data) as unknown as typeof dataToJSON;});&amp;nbsp;as unkonwn &quot; data-og-host=&quot;opendive.tistory.com&quot; data-og-source-url=&quot;https://opendive.tistory.com/759&quot; data-og-url=&quot;https://opendive.tistory.com/759&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bpk27o/hyX4AhZikG/bkIlnXdmjqjcM2pHm0ByO0/img.jpg?width=256&amp;amp;height=256&amp;amp;face=0_0_256_256,https://scrap.kakaocdn.net/dn/xqhzX/hyX4oIBbnn/iSsat2Xc69VMRQnRgqHULK/img.jpg?width=256&amp;amp;height=256&amp;amp;face=0_0_256_256,https://scrap.kakaocdn.net/dn/e7m83/hyX4mxet7K/4djBLKKHF2OVXnTxh7Ufi0/img.jpg?width=474&amp;amp;height=360&amp;amp;face=0_0_474_360&quot;&gt;&lt;a href=&quot;https://opendive.tistory.com/759&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://opendive.tistory.com/759&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bpk27o/hyX4AhZikG/bkIlnXdmjqjcM2pHm0ByO0/img.jpg?width=256&amp;amp;height=256&amp;amp;face=0_0_256_256,https://scrap.kakaocdn.net/dn/xqhzX/hyX4oIBbnn/iSsat2Xc69VMRQnRgqHULK/img.jpg?width=256&amp;amp;height=256&amp;amp;face=0_0_256_256,https://scrap.kakaocdn.net/dn/e7m83/hyX4mxet7K/4djBLKKHF2OVXnTxh7Ufi0/img.jpg?width=474&amp;amp;height=360&amp;amp;face=0_0_474_360');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;(Typescript) as unknown as typeof data&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;import { stringify } from 'devalue';export default defineEventHandler(async (event) =&amp;gt; { const data = { createAt: new Date() } const dataToJSON = { ...data, toJSON() { return this; } } return stringify(data) as unknown as typeof dataToJSON;});&amp;nbsp;as unkonwn&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;opendive.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;client 는 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1737596158993&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const {data: dateData} = await useFetch('/api/date')
// dateData.value?.createAt.getHours()

onMounted(() =&amp;gt; {
  console.log(dateData.value?.createAt.getHours()); // runtime 시 undefined
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에디터가 지원해 준다면 data 에 마우스 오버시 타입 추론되는 것이 보일 것입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 runtime 에는 undefined 가 발생하는 것을 볼수 있습니다. (client side: onMounted hook)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저 주소창을 통해 api endpoint url 을 직접 입력해보면 &lt;span style=&quot;background-color: #ffffff; color: #444d56; text-align: start;&quot;&gt;Cannot stringify a function &lt;/span&gt;오류가 발생하는 것을 알수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애초에 server api endpoint 에서 stringify 의 사용시 toJSON 에 대한 충돌이 발생하는 것을 알수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;stringify 함수는 object 타입이 아닌 function type 을 만날시 오류를 발생시킵니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #444d56; text-align: start;&quot;&gt;The error &quot;Cannot stringify a function&quot; occurs because the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-keybinding-context=&quot;1094&quot; data-href=&quot;file:///Users/user/Monday/nuxt-datafetch/node_modules/.pnpm/devalue%405.1.1/node_modules/devalue/src/stringify.js#25%2C17&quot;&gt;&lt;span&gt;stringify&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;background-color: #ffffff; color: #444d56; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;function does not support serializing functions. In &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #444d56; text-align: start;&quot;&gt;&amp;nbsp;the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-keybinding-context=&quot;1096&quot; data-href=&quot;file:///Users/user/Monday/nuxt-datafetch/server/api/date.ts#3%2C9&quot;&gt;&lt;span&gt;data&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;background-color: #ffffff; color: #444d56; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;object includes a&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-keybinding-context=&quot;1097&quot; data-href=&quot;file:///Users/user/Monday/nuxt-datafetch/server/api/date.ts#5%2C5&quot;&gt;&lt;span&gt;toJSON&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;background-color: #ffffff; color: #444d56; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;method, which is a function. When&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-keybinding-context=&quot;1098&quot; data-href=&quot;file:///Users/user/Monday/nuxt-datafetch/node_modules/.pnpm/devalue%405.1.1/node_modules/devalue/src/stringify.js#25%2C17&quot;&gt;&lt;span&gt;stringify&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;background-color: #ffffff; color: #444d56; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;tries to process this object, it encounters the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-keybinding-context=&quot;1099&quot; data-href=&quot;file:///Users/user/Monday/nuxt-datafetch/server/api/date.ts#5%2C5&quot;&gt;&lt;span&gt;toJSON&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;background-color: #ffffff; color: #444d56; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;method and throws an error.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Stringify Function&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #444d56; text-align: left;&quot;&gt;: The&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-keybinding-context=&quot;1105&quot; data-href=&quot;file:///Users/user/Monday/nuxt-datafetch/node_modules/.pnpm/devalue%405.1.1/node_modules/devalue/src/stringify.js#25%2C17&quot;&gt;&lt;span&gt;stringify&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;background-color: #ffffff; color: #444d56; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;function is designed to convert various data types into a string representation. However, it explicitly throws an error when it encounters a function.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1737597174541&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (typeof thing === 'function') {
  throw new DevalueError(`Cannot stringify a function`, keys);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리하여 여기서는 data 와 타입을 구분할 필요가 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1737597252350&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { stringify } from 'devalue';
export default defineEventHandler(async (event) =&amp;gt; {
  const data = {
    createAt: new Date()
  }
  const dataToJSON = {
    ...data,
    toJSON() {
      return this;
    }
  }
  return stringify(data) as unknown as typeof dataToJSON;
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;data 가 실질적인 데이터를 가지고 dataToJSON 으로 타입을 지정합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우 데이터는 직렬화되어 있음으로 역 직렬화가 필요합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1737597343400&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const {data: dateData} = await useFetch('/api/date', {
  transform(data) {
    return parse(data as unknown as string) as typeof data;
  }
});


&amp;lt;template&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;h1&amp;gt;Pick Data&amp;lt;/h1&amp;gt;
    &amp;lt;div&amp;gt;
      {{ dateData?.createAt.getDate() }}
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로 parse 는 string 타입의 매개변수가 필요함으로 data as unknown as string 형태로 타입 우회합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 타입이 올지 알수 없음으로 unknown 이 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 parse 된 데이터는 data 타입으로 선언되어야 타입추론이 가능함으로 as typeof data 가 추가되게 됩니다.&amp;nbsp;&lt;/p&gt;</description>
      <category>코드/Nuxt3</category>
      <author>Yeah-Panda</author>
      <guid isPermaLink="true">https://opendive.tistory.com/757</guid>
      <comments>https://opendive.tistory.com/757#entry757comment</comments>
      <pubDate>Fri, 17 Jan 2025 10:34:01 +0900</pubDate>
    </item>
    <item>
      <title>[Nuxt] useFetch options</title>
      <link>https://opendive.tistory.com/756</link>
      <description>&lt;pre id=&quot;code_1736899653004&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script lang=&quot;ts&quot; setup&amp;gt;
const { data, execute } = await useFetch('https://dummyjson.com/users/1',
  {
    server: false,
    immediate: false,
    default: () =&amp;gt; {
      return {
        firstName: 'John',
        lastName: 'Doe'
      }
    }
  }
);

&amp;lt;/script&amp;gt;
&amp;lt;template&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;h1&amp;gt;UseFetch Brief&amp;lt;/h1&amp;gt;
    &amp;lt;button type=&quot;button&quot; @click=&quot;() =&amp;gt; execute()&quot;&amp;gt;Fetch&amp;lt;/button&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;pre&amp;gt;
        {{ data }}
      &amp;lt;/pre&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;server&lt;/b&gt;: client side 에서 api 를 호출하도록 합니다. (server side 에서 api를 호출하지 않습니다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;default&lt;/b&gt;: factory 함수나 기본값을 등록합니다. api 호출의 응답이 오기 전까지 data 가 가지고 있는 값입니다. api 호출이 완료되면 overwrite 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;immediate: &lt;/b&gt;즉시 호출하지 않고 execute 함수의 호출을 기다립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nuxt.com/docs/api/composables/use-fetch#params&quot;&gt;https://nuxt.com/docs/api/composables/use-fetch#params&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1736899807836&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;useFetch &amp;middot; Nuxt Composables&quot; data-og-description=&quot;Fetch data from an API endpoint with an SSR-friendly composable.&quot; data-og-host=&quot;nuxt.com&quot; data-og-source-url=&quot;https://nuxt.com/docs/api/composables/use-fetch#params&quot; data-og-url=&quot;https://nuxt.com/docs/api/composables/use-fetch#params&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/GVXOw/hyX0tiY6aO/fKi2YM6QhJ2kEKmknGS611/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/oCX2Z/hyX0sRXc2L/AlPiQJJz9KkhLSLC9LNG4K/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://nuxt.com/docs/api/composables/use-fetch#params&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nuxt.com/docs/api/composables/use-fetch#params&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/GVXOw/hyX0tiY6aO/fKi2YM6QhJ2kEKmknGS611/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/oCX2Z/hyX0sRXc2L/AlPiQJJz9KkhLSLC9LNG4K/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;useFetch &amp;middot; Nuxt Composables&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Fetch data from an API endpoint with an SSR-friendly composable.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nuxt.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 dedupe 옵션이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;defer&quot; 과 &quot;cancel&quot; 값을 설정할수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1736901920578&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script lang=&quot;ts&quot; setup&amp;gt;
const { data, execute } = await useFetch('/api/random-user',
  {
    server: false,
    immediate: false,
    dedupe: &quot;defer&quot;,
    default: () =&amp;gt; {
      return {
        firstName: 'John',
        lastName: 'Doe'
      }
    }
  }
);

&amp;lt;/script&amp;gt;
&amp;lt;template&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;h1&amp;gt;UseFetch Brief&amp;lt;/h1&amp;gt;
    &amp;lt;button type=&quot;button&quot; @click=&quot;() =&amp;gt; execute()&quot;&amp;gt;Fetch&amp;lt;/button&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;pre&amp;gt;
        {{ data }}
      &amp;lt;/pre&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드의 api/random-user 는 2초의 딜레이후 api 를 호출하도 구현되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;api 호출후에 execute 버튼을 빠르게 반복적으로 누르는등 동일한 API 의 반복호출에 대한 처리 옵션입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;cancel&quot; 의 경우 이전 API 의 호출이 완료되지 않았다면 캔슬시킨 다음 현재의 API 를 재호출합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;defer&quot; 의 경우 이전 API 의 호출이 완료된 이후에 재호출할수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;lodash 의 throttle 와 bounce 와 유사합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 밖에 필요한 옵션들은 공식문서를 참고하면 자세하게 확인할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>코드/Nuxt3</category>
      <author>Yeah-Panda</author>
      <guid isPermaLink="true">https://opendive.tistory.com/756</guid>
      <comments>https://opendive.tistory.com/756#entry756comment</comments>
      <pubDate>Wed, 15 Jan 2025 09:48:51 +0900</pubDate>
    </item>
  </channel>
</rss>