Skip to content

Instantly share code, notes, and snippets.

@smeijer
Created October 2, 2023 14:30
Show Gist options
  • Save smeijer/885310fca21828272bca29097f490534 to your computer and use it in GitHub Desktop.
Save smeijer/885310fca21828272bca29097f490534 to your computer and use it in GitHub Desktop.
patch-package to make Remix not use type-fest Jsonify
diff --git a/node_modules/@remix-run/server-runtime/dist/serialize.d.ts b/node_modules/@remix-run/server-runtime/dist/serialize.d.ts
index 70ed67b..c77e90b 100644
--- a/node_modules/@remix-run/server-runtime/dist/serialize.d.ts
+++ b/node_modules/@remix-run/server-runtime/dist/serialize.d.ts
@@ -1,17 +1,31 @@
-import type { Jsonify } from "type-fest";
import type { AppData } from "./data";
import type { TypedDeferredData, TypedResponse } from "./responses";
-type Fn = (...args: any[]) => any;
+type JsonPrimitive = string | number | boolean | String | Number | Boolean | null;
+type NonJsonPrimitive = undefined | Function | symbol;
+type IsAny<T> = 0 extends 1 & T ? true : false;
+type Serialize<T> = IsAny<T> extends true ? any : T extends TypedDeferredData<infer U> ? SerializeDeferred<U> : T extends JsonPrimitive ? T : T extends NonJsonPrimitive ? never : T extends {
+ toJSON(): infer U;
+} ? U : T extends [] ? [] : T extends [unknown, ...unknown[]] ? SerializeTuple<T> : T extends ReadonlyArray<infer U> ? (U extends NonJsonPrimitive ? null : Serialize<U>)[] : T extends object ? SerializeObject<UndefinedToOptional<T>> : never;
+/** JSON serialize [tuples](https://www.typescriptlang.org/docs/handbook/2/objects.html#tuple-types) */
+type SerializeTuple<T extends unknown[]> = T extends [infer F, ...infer R] ? [Serialize<F>, ...SerializeTuple<R>] : [];
+/** JSON serialize objects (not including arrays) and classes */
+type SerializeObject<T extends object> = {
+ [k in keyof T as T[k] extends NonJsonPrimitive ? never : k]: Serialize<T[k]>;
+};
+type SerializeDeferred<T extends Record<string, unknown>> = {
+ [k in keyof T as T[k] extends Promise<unknown> ? k : T[k] extends NonJsonPrimitive ? never : k]: T[k] extends Promise<infer U> ? Promise<Serialize<U>> extends never ? "wtf" : Promise<Serialize<U>> : Serialize<T[k]> extends never ? k : Serialize<T[k]>;
+};
+type UndefinedToOptional<T extends object> = {
+ [k in keyof T as undefined extends T[k] ? never : k]: T[k];
+} & {
+ [k in keyof T as undefined extends T[k] ? k : never]?: Exclude<T[k], undefined>;
+};
+type ArbitraryFunction = (...args: any[]) => unknown;
/**
* Infer JSON serialized data type returned by a loader or action.
*
* For example:
* `type LoaderData = SerializeFrom<typeof loader>`
*/
-export type SerializeFrom<T extends AppData | Fn> = T extends (...args: any[]) => infer Output ? Awaited<Output> extends TypedResponse<infer U> ? Jsonify<U> : Awaited<Output> extends TypedDeferredData<infer U> ? {
- [K in keyof U as K extends symbol ? never : Promise<any> extends U[K] ? K : never]: DeferValue<U[K]>;
-} & Jsonify<{
- [K in keyof U as Promise<any> extends U[K] ? never : K]: U[K];
-}> : Jsonify<Awaited<Output>> : Jsonify<Awaited<T>>;
-type DeferValue<T> = T extends undefined ? undefined : T extends Promise<unknown> ? Promise<Jsonify<Awaited<T>>> : Jsonify<T>;
+export type SerializeFrom<T extends AppData | ArbitraryFunction> = Serialize<T extends (...args: any[]) => infer Output ? Awaited<Output> extends TypedResponse<infer U> ? U : Awaited<Output> : Awaited<T>>;
export {};
@smeijer
Copy link
Author

smeijer commented Oct 2, 2023

The Jsonify helper comes with issues (#7246, #7462) like dropped properties from loader/useLoaderData when types can be null. Till it's fixed in Remix, this patch-package reverts the types to v1.19.x. It's remix v2.0 that switched to Jsonify from type-fest. This basically undoes this pull request.

For a basic demo of the issues, check this TS Playground.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment