Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/kiliman/remix-typedjson
This package is a replacement for superjson to use in your Remix app. It handles a subset of types that `superjson` supports, but is faster and smaller.
https://github.com/kiliman/remix-typedjson
Last synced: 6 days ago
JSON representation
This package is a replacement for superjson to use in your Remix app. It handles a subset of types that `superjson` supports, but is faster and smaller.
- Host: GitHub
- URL: https://github.com/kiliman/remix-typedjson
- Owner: kiliman
- License: mit
- Created: 2022-07-22T22:20:47.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2023-11-29T14:05:17.000Z (11 months ago)
- Last Synced: 2024-10-28T07:46:02.441Z (7 days ago)
- Language: TypeScript
- Size: 783 KB
- Stars: 445
- Watchers: 4
- Forks: 22
- Open Issues: 7
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.md
Awesome Lists containing this project
- awesome-remix - remix-typedjson - This package is a replacement for superjson to use in your Remix app. (Utility)
- awesome-remix - remix-typedjson - This package is a replacement for superjson to use in your Remix app. (Utility)
README
# remix-typedjson
[![All Contributors](https://img.shields.io/badge/all_contributors-11-orange.svg?style=flat-square)](#contributors-)
This package is a replacement for [`superjson`](https://github.com/blitz-js/superjson) to use in your [Remix](https://remix.run/) app. It handles a subset
of types that `superjson` supports, but is faster and smaller.NOTE: Although faster, `remix-typedjson` is nowhere near as flexible as `superjson`. It only supports a subset of types with no extensibility. If you need the advanced features of `superjson`, then I definitely recommend it.
Example site: https://remix-typedjson-example-production.up.railway.app/
Example repo: https://github.com/kiliman/remix-typedjson-example
The following types are supported:
- `Date`
- `BigInt`
- `Set`
- `Map`
- `RegExp`
- `undefined`
- `Error`
- `NaN`
- `Number.POSITIVE_INFINITY`
- `Number.NEGATIVE_INFINITY`# 🚧 Work In Progress
Sets and Maps currently only support string keys and JSON serializable values. Complex types coming soon.
# 🛠 How to Use with Remix
In order to get full-type fidelity and type inference, you must be on Remix
v1.6.5+. You will also need to import the following replacement functions.## `typedjson`
### Installation
```bash
npm i remix-typedjson
```Replacement for Remix `json` helper. It also supports the optional `ResponseInit`, so you can return headers, etc.
Make sure your `loader` and `action` use the new declaration format:
```js
❌ export const loader: LoaderFunction = async ({request}) => {}
❌ export const action: ActionFunction = async ({request}) => {}✅ export const loader = async ({request}: LoaderFunctionArgs) => {}
✅ export const action = async ({request}: ActionFunctionArgs) => {}✅ export async function loader({request}: LoaderFunctionArgs) {}
✅ export async function action({request}: ActionFunctionArgs) {}
```### Usage
```js
return typedjson(
{ greeting: 'hello', today: new Date() },
// ResponseInit is optional, just like the `json` helper
{ headers: { 'set-header': await commitSession(session) } },
)
```## `useTypedLoaderData`
Replacement for Remix `useLoaderData`. Use the generic `` to
get the correct type inference.### Usage
```js
const loaderData = useTypedLoaderData()
```## `useTypedActionData`
Replacement for Remix `useActionData`. Use the generic `` to
get the correct type inference.### Usage
```js
const actionData = useTypedActionData()
```## `typeddefer`
✨ New in v0.3.0
Replacement for Remix `defer` helper. It also supports the optional `ResponseInit`, so you can return headers, etc.
### Usage
```js
return typeddefer({
fastData: { message: 'This is fast data', today: new Date() },
slowData: new Promise(resolve => setTimeout(resolve, 2000)).then(() => {
return { message: 'This is slow data', tomorrow: new Date() }
}),
})
```## ``
In your route component, use the new `` component instead of the
Remix `` component### Usage
```js
export default function DeferRoute() {
const { fastData, slowData } = useTypedLoaderData()
return (
Defer Route
Fast Data
{JSON.stringify(fastData, null, 2)}
fastData.today is {fastData.today.toLocaleString()}
Loading slow data...}>
Error loading slow data!}
>
{slowData => (
Slow Data
{JSON.stringify(slowData, null, 2)}
slowData.tomorrow is {slowData.tomorrow.toLocaleString()}
)}
)
}
```## `useTypedRouteLoaderData`
Helper for `useMatches` that returns the route data based on provided route `id`
### Usage
```ts
import { loader as rootLoader } from '~/root'const rootData = useTypedRouteLoaderData('root')
```## `useTypedFetcher`
✨ Add support for `key` in v0.4.0
Replacement for Remix `useFetcher`. Use the generic `` to
get the correct type inference for the `fetcher.data` property.### Usage
```ts
const fetcher = useTypedFetcher({ key: 'abc' })
fetcher.data // data property is fully typed
```## `redirect`
In order to return a `redirect`, you will need to import the `redirect` function from this package, in order for the type inference to work properly.
However, you can also `throw redirect()` and you can use the original `redirect` function from Remix.
## ~~`TypedMetaFunction`~~
🔥 Removed in v0.4.0 since it didn't actually work correctly. Will be replaced
with a `typedmeta` wrapper function in next releaseYou can now get typed arguments for both `data` and `parentsData` from your `meta`
function export. Based on [new feature coming to Remix](https://github.com/remix-run/remix/pull/4022)```js
export const meta: TypedMetaFunction = ({ data }) => {
return {
title: `Posts | ${data?.post.title}`,
}
}
// for parentsData, you can specify a Record of typed loaders keyed by route id
// root.tsx
export type LoaderType = typeof loader
// routes/parent.tsx
export type LoaderType = typeof loader
// routes/child.tsx
import { type LoaderType as RootLoaderType } from '~/root'
import { type LoaderType as ParentLoaderType } from '~/routes/parent'export const meta: TypedMetaFunction<
typeof loader,
// parent loader types keyed by route id
{
'root': RootLoader
'routes/parent': ParentLoader
}
> = ({ data, parentsData }) => {
// access typed parent data by route id
const rootData = parentsData['root']
const parentData = parentsData['routes/parent']return {
title: `Posts | ${data?.post.title}`,
}
}
```## `registerCustomType`
✨ New in v0.2.0
`remix-typed-json` support a limited number of native types in order to keep the
bundle small. However, if you need to support a custom type like `Decimal`, then
use the `registerCustomType` API. This way you only pay the cost of the custom
type if you use it.```ts
type CustomTypeEntry = {
type: string
is: (value: unknown) => boolean
serialize: (value: T) => string
deserialize: (value: string) => T
}export function registerCustomType(entry: CustomTypeEntry)
```### Usage
Register the custom type in _root.tsx_ once.
```ts
// root.tsx
import {
typedjson,
registerCustomType,
useTypedLoaderData,
} from 'remix-typedjson'import Decimal from 'decimal.js'
registerCustomType({
type: 'decimal',
is: (value: unknown) => value instanceof Decimal,
serialize: (value: Decimal) => value.toString(),
deserialize: (value: string) => new Decimal(value),
})
```You can now serialize and deserialize the `Decimal` type.
```ts
// route.tsx
export function loader() {
const d = new Decimal('1234567890123456789012345678901234567890')
return typedjson({ greeting: 'Hello World', today: new Date(), d })
}export default function Index() {
const data = useTypedLoaderData()return (
<>
Loader Data
{JSON.stringify(data, null, 2)}
- today: {data.today.toLocaleString()}
-
d instanceof Decimal: {data.d instanceof Decimal ? 'true' : 'false'}
- d: {data.d.toFixed(0)}
>
)
}
```
## 😍 Contributors
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
Kiliman
💻 📖
Kent C. Dodds
💻
Simon Knott
💻 🐛 ⚠️
Tony Truand
💻 ⚠️
Gregori Rivas
💻
Afsah Nasir
📖
Magnus Markling
💻
Jozsef Lazar
💻
Luke Bowerman
💻
Dan Marshall
📖
Eric Allam
📖
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!