Как передать JsonifyObject<T>, возвращенный из useLoaderData<typeof loader> Remix, в функцию

Из приведенного ниже кода маршрута Remix 2.9.2 я получаю ошибку TypeScript...

Аргумент типа «JsonifyObject<IdAndDate>» нельзя назначить параметру типа «IdAndDate».

... и я не могу понять, как импортировать JsonifyObject.

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}`;
}

Я пытался...

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

...но получаю ошибку...

Модуль «@remix-run/server-runtime/dist/jsonify» объявляет «JsonifyObject» локально, но он не экспортируется.

...что имеет смысл, поскольку оно не экспортируется, но я не могу найти другое место, откуда его можно было бы импортировать.

Я не хочу использовать as IdAndDate, потому что это лишит нас того действительно полезного факта, что JsonifyObject знает, что дата является строкой после сериализации объекта.

(Кроме того, я знаю, что пример тривиален и не требует функции, но он упрощен, чтобы показать суть проблемы. В реальном коде есть более сложная логика, которую имеет смысл реализовать на стороне браузера. .)

Я упускаю что-то простое? Экспортируется ли JsonifyObject куда-то еще, чего я не могу найти?

Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
0
0
295
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

В вашем загрузчике вы должны использовать помощник json.

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

Затем в вашем компоненте пользовательского интерфейса useLoaderData вернет ваши данные с типом JsonifyObject.

Обновлено: Возможно, я неправильно понял ваш вопрос.

Вы можете использовать помощник типа SerializeFrom, чтобы получить сериализованный тип.

type SerializedIdAndDate = SerializeFrom<IdAndDate>

// or

type SerializedIdAndDate = SerializeFrom<typeof loader>

Сначала я не смог найти SerializeFrom и попытался импортировать Jsonify из @remix-run/server-runtime/dist/jsonify, где находится JsonifyObject, и это сработало. Затем я нашел SerializeFrom в @remix-run/node, и это тоже сработало. Предпочтителен ли SerializeFrom? Любое руководство о том, почему? В любом случае — спасибо!

rickjoi 06.07.2024 02:50

Что делать, если я просто хочу использовать свой собственный тип (IdAndDate в этом примере). У меня есть компоненты, которые принимают мой тип, и я не хочу, чтобы все они использовали этот сериализованный тип.

Joe 06.07.2024 10:21

@Джо, я опубликовал ответ как с кодом, подразумеваемым в этом ответе, так и с другой версией кода, которая показывает другую опцию, которая будет работать для компонентов, принимающих несериализованный тип - простой ответ заключается в том, что вам нужно адаптировать сериализованный тип. напечатайте обратно к исходному типу

rickjoi 06.07.2024 13:19

Если вы хотите использовать нативные типы, предлагаю вам воспользоваться моим пакетом remix-typedjson. Или вы можете использовать функцию me Single Data Fetch в Remix, которая изначально поддерживает все типы.

Kiliman 07.07.2024 03:09

Этот ответ на тот случай, если кому-то может помочь просмотр рабочего кода, используя предложение из принятого ответа:

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}`;
}

Следующий блок кода — это альтернатива, отвечающая на комментарий Джо по поводу принятого ответа.

Здесь сериализованный объект преобразуется обратно в исходный тип данных путем адаптации всего, что было сериализовано к другому типу, обратно в исходный тип. В моем простом примере необходимо адаптировать обратно только дату.

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}`;
}

Спасибо за внимание к моему комментарию. Я надеялся, что есть способ автоматически конвертировать даты, но думаю, что это невозможно (без добавления отдельной библиотеки) согласно этому github.com/remix-run/remix/discussions/634.

Joe 06.07.2024 19:35

Другие вопросы по теме