typescript - Remix'in useLoaderData<typeof loader> fonksiyonundan dönen JsonifyObject<T> değerini bir fonksiyona nasıl geçirebilirim


Aşağıdaki Remix 2.9.2 rota kodundan, TypeScript hatası alıyorum...

Türü 'JsonifyObject<IdAndDate>' olan argüman, 'IdAndDate' türündeki parametreye atanamaz.

...ve JsonifyObject'i nasıl içe aktaracağımı çözemedim.

import { useLoaderData } from "@remix-run/react";

type IdAndDate = {
  id: number;
  date: Date;
};

export default function Component() {
  //
  const idAndDate = useLoaderData<typeof loader>();
  // this line would work great, and helpfully, idAndDate.date is typed as string because it was serialized...
  //return (<div>{idAndDate.id}: {idAndDate.date}</div>);

  // but this, doesn't work because --
  // "Argument of type 'JsonifyObject<IdAndDate>' is not assignable to parameter of type 'IdAndDate'."
  // -- which is true, but I can't figure out how to import JsonifyObject :\
  return <div>{formatIdAndDate(idAndDate)}</div>;
}

export function loader(): IdAndDate {
  return { id: 42, date: new Date() };
}

function formatIdAndDate(idAndDate: IdAndDate): string {
  return `${idAndDate.id}: ${idAndDate.date}`;
}

Denedim...

import { JsonifyObject } from "@remix-run/server-runtime/dist/jsonify"

...ama hata alıyorum...

Modül '"@remix-run/server-runtime/dist/jsonify"' 'JsonifyObject'u yerel olarak bildiriyor, ancak dışa aktarılmamış.

...ki bu mantıklı çünkü dışa aktarılmıyor -- ama onu başka nereden içe aktarabileceğimi bulamıyorum.

as IdAndDate kullanmak istemiyorum çünkü bu, JsonifyObject’in nesne serileştirildikten sonra tarihin bir string olduğunu bilmesi gibi gerçekten yararlı gerçeği kaybetmek anlamına gelir.

(Ayrıca, örneğin önemsiz olduğunu ve bir fonksiyona gerek olmadığını biliyorum, ama bu sorun çekirdeğini göstermek için basitleştirildi. Gerçek kodda, tarayıcı tarafında yapılmasının mantıklı olduğu daha ayrıntılı bir mantık vardır.)

Basit bir şeyi mi kaçırıyorum? JsonifyObject'i bulamadığım başka bir yerde mi dışa aktarıyorlar?

Cevap #1

Yükleyicinizde json yardımcı öğesini kullanmalısınız.

return json({ id: 42, date: new Date() })

Sonra UI bileşeninizde, useLoaderData verinizi JsonifyObject tipi ile döndürecektir.

DÜZENLEME: Sorunuzu yanlış anlamış olabilirim.

SerializeFrom tür yardımcı programını size serileştirilmiş türü vermesi için kullanabilirsiniz.

type SerializedIdAndDate = SerializeFrom<IdAndDate>

// or

type SerializedIdAndDate = SerializeFrom<typeof loader>

Cevap #2

Bu cevap, kabul edilen cevaptaki öneriyi kullanarak çalışan kodu görmenin birine yardımcı olabileceği ihtimaline karşıdır:

import { useLoaderData } from "@remix-run/react";
import { SerializeFrom } from "@remix-run/node";

type IdAndDate = {
  id: number;
  date: Date;
};

export default function Component() {
  const idAndDate = useLoaderData<typeof loader>();
  return <div>{formatIdAndDate(idAndDate)}</div>;
}

export function loader(): IdAndDate {
  return { id: 42, date: new Date() };
}

function formatIdAndDate(idAndDate: SerializeFrom<IdAndDate>): string {
  return `${idAndDate.id}: ${idAndDate.date}`;
}

Bir sonraki kod bloğu, kabul edilen yanıttaki Joe'nun yorumuna cevap veren bir alternatiftir.

Burada, serileştirilmiş nesne, serileştirilmiş herhangi bir şeyi farklı bir türden orijinal türe geri dönüştürerek orijinal veri türüne geri çevrilir. Benim basit örneğimde, yalnızca Tarih geri adapte edilmesi gerekmektedir.

import { useLoaderData } from "@remix-run/react";

type IdAndDate = {
  id: number;
  date: Date;
};

export default function Component() {
  const serializedIdAndDate = useLoaderData<typeof loader>();
  const idAndDate = { id: serializedIdAndDate.id, date: new Date(serializedIdAndDate.date) };
  return <div>{formatIdAndDate(idAndDate)}</div>;
}

export function loader(): IdAndDate {
  return { id: 42, date: new Date() };
}

// this function now can use the original unserialized type
function formatIdAndDate(idAndDate: IdAndDate): string {
  return `${idAndDate.id}: ${idAndDate.date}`;
}

İlgili makaleler