Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
pcattori committed May 3, 2024
1 parent bd6a306 commit 4d483cb
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 64 deletions.
86 changes: 22 additions & 64 deletions packages/remix-react/future/single-fetch.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { MetaArgs, UIMatch, UNSAFE_MetaMatch } from "@remix-run/react";
import type {
LoaderFunctionArgs,
ActionFunctionArgs,
Loader,
Action,
SerializeFrom,
TypedDeferredData,
TypedResponse,
Expand All @@ -11,90 +11,52 @@ import type {
FetcherWithComponents,
} from "react-router-dom";

type Serializable =
| undefined
| null
| boolean
| string
| symbol
| number
| Array<Serializable>
| { [key: PropertyKey]: Serializable }
| bigint
| Date
| URL
| RegExp
| Error
| Map<Serializable, Serializable>
| Set<Serializable>
| Promise<Serializable>;

type DataFunctionReturnValue =
| Serializable
| TypedDeferredData<Record<string, unknown>>
| TypedResponse<Record<string, unknown>>;

type LoaderFunction_SingleFetch = (
args: LoaderFunctionArgs
) => Promise<DataFunctionReturnValue> | DataFunctionReturnValue;
type ActionFunction_SingleFetch = (
args: ActionFunctionArgs
) => Promise<DataFunctionReturnValue> | DataFunctionReturnValue;

// Backwards-compatible type for Remix v2 where json/defer still use the old types,
// and only non-json/defer returns use the new types. This allows for incremental
// migration of loaders to return naked objects. In the next major version,
// json/defer will be removed so everything will use the new simplified typings.
// prettier-ignore
type SingleFetchSerialize_V2<T extends LoaderFunction_SingleFetch | ActionFunction_SingleFetch> =
type Serialize<T extends Loader | Action> =
Awaited<ReturnType<T>> extends TypedDeferredData<infer D> ? D :
Awaited<ReturnType<T>> extends TypedResponse<Record<string, unknown>> ? SerializeFrom<T> :
Awaited<ReturnType<T>>;

declare module "@remix-run/react" {
export function useLoaderData<T>(): T extends LoaderFunction_SingleFetch
? SingleFetchSerialize_V2<T>
: never;
export function useLoaderData<T>(): T extends Loader ? Serialize<T> : T;

export function useActionData<T>(): T extends ActionFunction_SingleFetch
? SingleFetchSerialize_V2<T> | undefined
: never;
export function useActionData<T>(): T extends Action
? Serialize<T> | undefined
: T;

export function useRouteLoaderData<T>(
routeId: string
): T extends LoaderFunction_SingleFetch ? SingleFetchSerialize_V2<T> : never;
): T extends Loader ? Serialize<T> : never;

export function useFetcher<TData = unknown>(
opts?: Parameters<typeof useFetcherRR>[0]
): FetcherWithComponents<
TData extends LoaderFunction_SingleFetch | ActionFunction_SingleFetch
? SingleFetchSerialize_V2<TData>
: never
TData extends Loader | Action ? Serialize<TData> : TData
>;

export type UIMatch_SingleFetch<D = unknown, H = unknown> = Omit<
UIMatch<D, H>,
"data"
> & {
data: D extends LoaderFunction_SingleFetch
? SingleFetchSerialize_V2<D>
: never;
data: D extends Loader ? Serialize<D> : never;
};

interface MetaMatch_SingleFetch<
RouteId extends string = string,
Loader extends LoaderFunction_SingleFetch | unknown = unknown
> extends Omit<UNSAFE_MetaMatch<RouteId, Loader>, "data"> {
data: Loader extends LoaderFunction_SingleFetch
? SingleFetchSerialize_V2<Loader>
: unknown;
L extends Loader | unknown = unknown
> extends Omit<UNSAFE_MetaMatch<RouteId, L>, "data"> {
data: L extends Loader ? Serialize<L> : unknown;
}

type MetaMatches_SingleFetch<
MatchLoaders extends Record<
MatchLoaders extends Record<string, Loader | unknown> = Record<
string,
LoaderFunction_SingleFetch | unknown
> = Record<string, unknown>
unknown
>
> = Array<
{
[K in keyof MatchLoaders]: MetaMatch_SingleFetch<
Expand All @@ -105,17 +67,13 @@ declare module "@remix-run/react" {
>;

export interface MetaArgs_SingleFetch<
Loader extends LoaderFunction_SingleFetch | unknown = unknown,
MatchLoaders extends Record<
L extends Loader | unknown = unknown,
MatchLoaders extends Record<string, Loader | unknown> = Record<
string,
LoaderFunction_SingleFetch | unknown
> = Record<string, unknown>
> extends Omit<MetaArgs<Loader, MatchLoaders>, "data" | "matches"> {
data:
| (Loader extends LoaderFunction_SingleFetch
? SingleFetchSerialize_V2<Loader>
: unknown)
| undefined;
unknown
>
> extends Omit<MetaArgs<L, MatchLoaders>, "data" | "matches"> {
data: (L extends Loader ? Serialize<L> : unknown) | undefined;
matches: MetaMatches_SingleFetch<MatchLoaders>;
}
}
2 changes: 2 additions & 0 deletions packages/remix-server-runtime/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export {
} from "./formData";
export { defer, json, redirect, redirectDocument } from "./responses";
export type {
Loader,
Action,
SingleFetchResult as UNSAFE_SingleFetchResult,
SingleFetchResults as UNSAFE_SingleFetchResults,
} from "./single-fetch";
Expand Down
51 changes: 51 additions & 0 deletions packages/remix-server-runtime/single-fetch.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import type {
ActionFunctionArgs as RRActionArgs,
LoaderFunctionArgs as RRLoaderArgs,
StaticHandler,
unstable_DataStrategyFunctionArgs as DataStrategyFunctionArgs,
unstable_DataStrategyFunction as DataStrategyFunction,
Expand All @@ -19,6 +21,7 @@ import type {
ResponseStubOperation,
} from "./routeModules";
import { ResponseStubOperationsSymbol } from "./routeModules";
import type { TypedDeferredData, TypedResponse } from "./responses";
import { isDeferredData, isRedirectStatusCode, isResponse } from "./responses";

export const SingleFetchRedirectSymbol = Symbol("SingleFetchRedirect");
Expand Down Expand Up @@ -504,3 +507,51 @@ export function encodeViaTurboStream(
],
});
}

type MaybePromise<T> = T | Promise<T>;

type Serializable =
| undefined
| null
| boolean
| string
| symbol
| number
| Array<Serializable>
| { [key: PropertyKey]: Serializable }
| bigint
| Date
| URL
| RegExp
| Error
| Map<Serializable, Serializable>
| Set<Serializable>
| Promise<Serializable>;

type DataFunctionReturnValue =
| Serializable
| TypedDeferredData<Record<string, unknown>>
| TypedResponse<Record<string, unknown>>;

type LoaderArgs = RRLoaderArgs<AppLoadContext> & {
// Context is always provided in Remix, and typed for module augmentation support.
context: AppLoadContext;
response: ResponseStub;
};

export type Loader = (
args: LoaderArgs
) => MaybePromise<DataFunctionReturnValue>;

type ActionArgs = RRActionArgs<AppLoadContext> & {
// Context is always provided in Remix, and typed for module augmentation support.
context: AppLoadContext;
response: ResponseStub;
};

export type Action = (
args: ActionArgs
) => MaybePromise<DataFunctionReturnValue>;

export let defineLoader = <T extends Loader>(loader: T): T => loader;
export let defineAction = <T extends Action>(action: T): T => action;

0 comments on commit 4d483cb

Please sign in to comment.