diff --git a/.changeset/rotten-geckos-yawn.md b/.changeset/rotten-geckos-yawn.md index c924d49c3e6..9718c85596f 100644 --- a/.changeset/rotten-geckos-yawn.md +++ b/.changeset/rotten-geckos-yawn.md @@ -37,14 +37,18 @@ You can return custom responses via the `json`/`defer` utilities, but doing so w let loader1 = () => { return { a: 1, b: new Date() }; }; -let data1 = useLoaderData(); -// ^? {a: number, b: Date} +function Component() { + let data1 = useLoaderData(); + // ^? {a: number, b: Date} +} let loader2 = () => { return json({ a: 1, b: new Date() }); // this opts-out of turbo-stream }; -let data2 = useLoaderData(); -// ^? JsonifyObject<{a: number, b: Date}> which is really {a: number, b: string} +function Component2() { + let data2 = useLoaderData(); + // ^? JsonifyObject<{a: number, b: Date}> which is really {a: number, b: string} +} ``` You can also continue to return totally custom responses with `Response` though this continues to be outside of the typesystem since the built-in `Response` type is not generic diff --git a/.changeset/sharp-bags-call.md b/.changeset/sharp-bags-call.md new file mode 100644 index 00000000000..ee83be5dea5 --- /dev/null +++ b/.changeset/sharp-bags-call.md @@ -0,0 +1,6 @@ +--- +"@remix-run/react": patch +"@remix-run/server-runtime": patch +--- + +[REMOVE] Move defineClientLoader/defineClientAction to @remix-run/react package diff --git a/packages/remix-cloudflare/CHANGELOG.md b/packages/remix-cloudflare/CHANGELOG.md index 6cf735c94c6..4868d2e07d0 100644 --- a/packages/remix-cloudflare/CHANGELOG.md +++ b/packages/remix-cloudflare/CHANGELOG.md @@ -35,14 +35,18 @@ let loader1 = () => { return { a: 1, b: new Date() }; }; - let data1 = useLoaderData(); - // ^? {a: number, b: Date} + function Component() { + let data1 = useLoaderData(); + // ^? {a: number, b: Date} + } let loader2 = () => { return json({ a: 1, b: new Date() }); // this opts-out of turbo-stream }; - let data2 = useLoaderData(); - // ^? JsonifyObject<{a: number, b: Date}> which is really {a: number, b: string} + function Component2() { + let data2 = useLoaderData(); + // ^? JsonifyObject<{a: number, b: Date}> which is really {a: number, b: string} + } ``` You can also continue to return totally custom responses with `Response` though this continues to be outside of the typesystem since the built-in `Response` type is not generic diff --git a/packages/remix-cloudflare/index.ts b/packages/remix-cloudflare/index.ts index d1463dbcaf7..a21c55b7516 100644 --- a/packages/remix-cloudflare/index.ts +++ b/packages/remix-cloudflare/index.ts @@ -13,9 +13,7 @@ export { createRequestHandler, createSession, unstable_defineLoader, - unstable_defineClientLoader, unstable_defineAction, - unstable_defineClientAction, defer, broadcastDevReady, logDevReady, diff --git a/packages/remix-deno/CHANGELOG.md b/packages/remix-deno/CHANGELOG.md index ce544550bda..ef0acfb1d91 100644 --- a/packages/remix-deno/CHANGELOG.md +++ b/packages/remix-deno/CHANGELOG.md @@ -35,14 +35,18 @@ let loader1 = () => { return { a: 1, b: new Date() }; }; - let data1 = useLoaderData(); - // ^? {a: number, b: Date} + function Component() { + let data1 = useLoaderData(); + // ^? {a: number, b: Date} + } let loader2 = () => { return json({ a: 1, b: new Date() }); // this opts-out of turbo-stream }; - let data2 = useLoaderData(); - // ^? JsonifyObject<{a: number, b: Date}> which is really {a: number, b: string} + function Component2() { + let data2 = useLoaderData(); + // ^? JsonifyObject<{a: number, b: Date}> which is really {a: number, b: string} + } ``` You can also continue to return totally custom responses with `Response` though this continues to be outside of the typesystem since the built-in `Response` type is not generic diff --git a/packages/remix-deno/index.ts b/packages/remix-deno/index.ts index 9de14b92d62..97fccb83d79 100644 --- a/packages/remix-deno/index.ts +++ b/packages/remix-deno/index.ts @@ -27,8 +27,6 @@ export { unstable_composeUploadHandlers, unstable_createMemoryUploadHandler, unstable_defineAction, - unstable_defineClientAction, - unstable_defineClientLoader, unstable_defineLoader, unstable_parseMultipartFormData, } from "@remix-run/server-runtime"; diff --git a/packages/remix-node/CHANGELOG.md b/packages/remix-node/CHANGELOG.md index d2f1d353fa2..0c5ee0b93bc 100644 --- a/packages/remix-node/CHANGELOG.md +++ b/packages/remix-node/CHANGELOG.md @@ -35,14 +35,18 @@ let loader1 = () => { return { a: 1, b: new Date() }; }; - let data1 = useLoaderData(); - // ^? {a: number, b: Date} + function Component() { + let data1 = useLoaderData(); + // ^? {a: number, b: Date} + } let loader2 = () => { return json({ a: 1, b: new Date() }); // this opts-out of turbo-stream }; - let data2 = useLoaderData(); - // ^? JsonifyObject<{a: number, b: Date}> which is really {a: number, b: string} + function Component2() { + let data2 = useLoaderData(); + // ^? JsonifyObject<{a: number, b: Date}> which is really {a: number, b: string} + } ``` You can also continue to return totally custom responses with `Response` though this continues to be outside of the typesystem since the built-in `Response` type is not generic diff --git a/packages/remix-node/index.ts b/packages/remix-node/index.ts index e1587d6dcbc..eaf64599f3c 100644 --- a/packages/remix-node/index.ts +++ b/packages/remix-node/index.ts @@ -25,9 +25,7 @@ export { createRequestHandler, createSession, unstable_defineLoader, - unstable_defineClientLoader, unstable_defineAction, - unstable_defineClientAction, defer, broadcastDevReady, logDevReady, diff --git a/packages/remix-react/CHANGELOG.md b/packages/remix-react/CHANGELOG.md index d85a3a54814..5c1bf4207b0 100644 --- a/packages/remix-react/CHANGELOG.md +++ b/packages/remix-react/CHANGELOG.md @@ -37,14 +37,18 @@ let loader1 = () => { return { a: 1, b: new Date() }; }; - let data1 = useLoaderData(); - // ^? {a: number, b: Date} + function Component() { + let data1 = useLoaderData(); + // ^? {a: number, b: Date} + } let loader2 = () => { return json({ a: 1, b: new Date() }); // this opts-out of turbo-stream }; - let data2 = useLoaderData(); - // ^? JsonifyObject<{a: number, b: Date}> which is really {a: number, b: string} + function Component2() { + let data2 = useLoaderData(); + // ^? JsonifyObject<{a: number, b: Date}> which is really {a: number, b: string} + } ``` You can also continue to return totally custom responses with `Response` though this continues to be outside of the typesystem since the built-in `Response` type is not generic diff --git a/packages/remix-react/future/single-fetch.d.ts b/packages/remix-react/future/single-fetch.d.ts index fa37a8a338b..ede86e5fe7d 100644 --- a/packages/remix-react/future/single-fetch.d.ts +++ b/packages/remix-react/future/single-fetch.d.ts @@ -1,4 +1,10 @@ -import type { MetaArgs, UIMatch, UNSAFE_MetaMatch } from "@remix-run/react"; +import type { + MetaArgs, + UIMatch, + UNSAFE_MetaMatch, + unstable_ClientLoader as ClientLoader, + unstable_ClientAction as ClientAction, +} from "@remix-run/react"; import type { unstable_Loader as Loader, unstable_Action as Action, @@ -10,9 +16,13 @@ import type { } from "react-router-dom"; declare module "@remix-run/react" { - export function useLoaderData(): Serialize; + export function useLoaderData< + T extends Loader | ClientLoader + >(): T extends Loader ? Serialize : Awaited>; - export function useActionData(): Serialize | undefined; + export function useActionData(): + | (T extends Action ? Serialize : Awaited>) + | undefined; export function useRouteLoaderData( routeId: string diff --git a/packages/remix-react/index.tsx b/packages/remix-react/index.tsx index ecb54165e15..f8dda53497a 100644 --- a/packages/remix-react/index.tsx +++ b/packages/remix-react/index.tsx @@ -111,6 +111,14 @@ export { ScrollRestoration } from "./scroll-restoration"; export type { RemixServerProps } from "./server"; export { RemixServer } from "./server"; +export type { + ClientAction as unstable_ClientAction, + ClientLoader as unstable_ClientLoader, +} from "./single-fetch"; +export { + defineClientAction as unstable_defineClientAction, + defineClientLoader as unstable_defineClientLoader, +} from "./single-fetch"; export type { FutureConfig as UNSAFE_FutureConfig, diff --git a/packages/remix-react/single-fetch.tsx b/packages/remix-react/single-fetch.tsx index a3bd1bed8c3..880ce796b87 100644 --- a/packages/remix-react/single-fetch.tsx +++ b/packages/remix-react/single-fetch.tsx @@ -1,5 +1,7 @@ import * as React from "react"; import type { + ActionFunctionArgs as RRActionArgs, + LoaderFunctionArgs as RRLoaderArgs, unstable_DataStrategyFunction as DataStrategyFunction, unstable_HandlerResult as HandlerResult, } from "@remix-run/router"; @@ -10,6 +12,9 @@ import { import type { UNSAFE_SingleFetchResult as SingleFetchResult, UNSAFE_SingleFetchResults as SingleFetchResults, + unstable_Action, + unstable_Loader, + unstable_Serialize, } from "@remix-run/server-runtime"; import { UNSAFE_SingleFetchRedirectSymbol as SingleFetchRedirectSymbol } from "@remix-run/server-runtime"; import type { @@ -24,6 +29,23 @@ import { escapeHtml } from "./markup"; import type { RouteModules } from "./routeModules"; import invariant from "./invariant"; +// clientLoader +type ClientLoaderArgs = RRLoaderArgs & { + serverLoader: () => Promise>; +}; +export type ClientLoader = (args: ClientLoaderArgs) => unknown; +export let defineClientLoader = ( + clientLoader: T +): T & { hydrate?: boolean } => clientLoader; + +// clientAction +type ClientActionArgs = RRActionArgs & { + serverAction: () => Promise>; +}; +export type ClientAction = (args: ClientActionArgs) => unknown; +export let defineClientAction = (clientAction: T): T => + clientAction; + interface StreamTransferProps { context: EntryContext; identifier: number; diff --git a/packages/remix-server-runtime/CHANGELOG.md b/packages/remix-server-runtime/CHANGELOG.md index c633f0d08a8..67cdb1fbe83 100644 --- a/packages/remix-server-runtime/CHANGELOG.md +++ b/packages/remix-server-runtime/CHANGELOG.md @@ -37,14 +37,18 @@ let loader1 = () => { return { a: 1, b: new Date() }; }; - let data1 = useLoaderData(); - // ^? {a: number, b: Date} + function Component() { + let data1 = useLoaderData(); + // ^? {a: number, b: Date} + } let loader2 = () => { return json({ a: 1, b: new Date() }); // this opts-out of turbo-stream }; - let data2 = useLoaderData(); - // ^? JsonifyObject<{a: number, b: Date}> which is really {a: number, b: string} + function Component2() { + let data2 = useLoaderData(); + // ^? JsonifyObject<{a: number, b: Date}> which is really {a: number, b: string} + } ``` You can also continue to return totally custom responses with `Response` though this continues to be outside of the typesystem since the built-in `Response` type is not generic diff --git a/packages/remix-server-runtime/index.ts b/packages/remix-server-runtime/index.ts index 2840bdc6a33..7a4d4cf9c14 100644 --- a/packages/remix-server-runtime/index.ts +++ b/packages/remix-server-runtime/index.ts @@ -9,9 +9,7 @@ export { defer, json, redirect, redirectDocument } from "./responses"; export { SingleFetchRedirectSymbol as UNSAFE_SingleFetchRedirectSymbol, defineLoader as unstable_defineLoader, - defineClientLoader as unstable_defineClientLoader, defineAction as unstable_defineAction, - defineClientAction as unstable_defineClientAction, } from "./single-fetch"; export type { Loader as unstable_Loader, diff --git a/packages/remix-server-runtime/single-fetch.ts b/packages/remix-server-runtime/single-fetch.ts index 18381f00c61..7571c8478df 100644 --- a/packages/remix-server-runtime/single-fetch.ts +++ b/packages/remix-server-runtime/single-fetch.ts @@ -533,7 +533,7 @@ type DataFunctionReturnValue = // 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 -export type Serialize = +export type Serialize = Awaited> extends TypedDeferredData ? D : Awaited> extends TypedResponse> ? SerializeFrom : Awaited>; @@ -569,15 +569,6 @@ export type Loader = ( ) => MaybePromise; export let defineLoader = (loader: T): T => loader; -// clientLoader -type ClientLoaderArgs = RRLoaderArgs & { - serverLoader: () => Promise>; -}; -type ClientLoader = (args: ClientLoaderArgs) => MaybePromise; -export let defineClientLoader = ( - clientLoader: T -): T & { hydrate?: boolean } => clientLoader; - // action type ActionArgs = RRActionArgs & { // Context is always provided in Remix, and typed for module augmentation support. @@ -588,11 +579,3 @@ export type Action = ( args: ActionArgs ) => MaybePromise; export let defineAction = (action: T): T => action; - -// clientAction -type ClientActionArgs = RRActionArgs & { - serverAction: () => Promise>; -}; -type ClientAction = (args: ClientActionArgs) => MaybePromise; -export let defineClientAction = (clientAction: T): T => - clientAction;