Из приведенного ниже кода маршрута 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 куда-то еще, чего я не могу найти?
В вашем загрузчике вы должны использовать помощник json
.
return json({ id: 42, date: new Date() })
Затем в вашем компоненте пользовательского интерфейса useLoaderData
вернет ваши данные с типом JsonifyObject
.
Обновлено: Возможно, я неправильно понял ваш вопрос.
Вы можете использовать помощник типа SerializeFrom
, чтобы получить сериализованный тип.
type SerializedIdAndDate = SerializeFrom<IdAndDate>
// or
type SerializedIdAndDate = SerializeFrom<typeof loader>
Что делать, если я просто хочу использовать свой собственный тип (IdAndDate в этом примере). У меня есть компоненты, которые принимают мой тип, и я не хочу, чтобы все они использовали этот сериализованный тип.
@Джо, я опубликовал ответ как с кодом, подразумеваемым в этом ответе, так и с другой версией кода, которая показывает другую опцию, которая будет работать для компонентов, принимающих несериализованный тип - простой ответ заключается в том, что вам нужно адаптировать сериализованный тип. напечатайте обратно к исходному типу
Если вы хотите использовать нативные типы, предлагаю вам воспользоваться моим пакетом remix-typedjson
. Или вы можете использовать функцию me Single Data Fetch в Remix, которая изначально поддерживает все типы.
Этот ответ на тот случай, если кому-то может помочь просмотр рабочего кода, используя предложение из принятого ответа:
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.
Сначала я не смог найти SerializeFrom и попытался импортировать Jsonify из @remix-run/server-runtime/dist/jsonify, где находится JsonifyObject, и это сработало. Затем я нашел SerializeFrom в @remix-run/node, и это тоже сработало. Предпочтителен ли SerializeFrom? Любое руководство о том, почему? В любом случае — спасибо!