Replies: 10 comments 8 replies
-
Some demo: |
Beta Was this translation helpful? Give feedback.
-
Somewhat related: microsoft/TypeScript: Type annotation for all exports in the module I wonder if it would be possible to have e.g. // Internal Remix code
interface EntryRouteModule<LoaderData = Response | AppData> {
CatchBoundary?: CatchBoundaryComponent;
ErrorBoundary?: ErrorBoundaryComponent;
default?: RouteComponent;
handle?: RouteHandle;
links?: LinksFunction;
meta?: MetaFunction | HtmlMetaDescriptor;
action?: ActionFunction;
headers?: HeadersFunction | { [name: string]: string };
loader?: LoaderFunction<LoaderData>;
} Then, in a route // routes/products.tsx
import type { EntryRouteModule } from 'Remix'
import { useLoaderData } from 'Remix';
export implements EntryRouteModule<Product[]>;
// this is typed correctly because of the line above
export const loader = async () => {
return {
products: await productsQuery()
}
export default function ProductsRoute() {
// Have TypeScript figure this out automatically somehow:
// useLoaderData now knows that `LoaderData === Product[]`. There is no need to `useLoaderData<Product[]>`
const {products} = useLoaderData()
return <ProductTable products={products} />
} |
Beta Was this translation helpful? Give feedback.
-
Excellent proposal. This could also work to const loader: LoaderFunction = () => 'foo'
const data = useLoaderData<InferLoaderData<typeof loader>> |
Beta Was this translation helpful? Give feedback.
-
I post issue #1703. We can use two generics instead one. |
Beta Was this translation helpful? Give feedback.
-
I believe this would help ensuring type safety between server and client better! However, the proposed type has inconvenience when a loader also returns type LoaderData = {
products: Product[]
}
// Type Error for `loader` because LoaderData != Response.
// You can instead write `LoaderFunction<LoaderData | Response>`, but it's kind of redundant.
export const loader: LoaderFunction<LoaderData> = async ({params}) => {
// Conditionally return with specific header
if (params.archived) {
return json(await archivedProducts(), {headers: {'Cache-Control': 'public, max-age=31536000, immutable'}})
}
return {
products: await productsQuery()
}
}
export default function ProductsRoute() {
const {products} = useLoaderData<LoaderData>()
return <ProductTable products={products} />
} I think -export interface LoaderFunction {
- (args: DataFunctionArgs): Promise<Response> | Response | Promise<AppData> | AppData;
-}
+interface BetterLoaderFunction<T = AppData> {
+ (args: DataFunctionArgs): T | Response | Promise<T | Response>;
+} |
Beta Was this translation helpful? Give feedback.
-
I believe export interface ActionFunction<T = AppData> {
(args: DataFunctionArgs): T | Response | Promise<T | Response>;
} |
Beta Was this translation helpful? Give feedback.
-
@na2hiro export const loader: LoaderFunction<LoaderData | Response> Technically its always a response what you return. However, you want the data returned and used by client to be as type-safe as possible. Forcing The point of this proposal is just to eliminate the need of typing |
Beta Was this translation helpful? Give feedback.
-
Here’s a comment from Ryan explaining why actions and loaders can’t be generics #1254 (comment) |
Beta Was this translation helpful? Give feedback.
-
Thank you @sergiodxa. I think we can build a generics types for loader function in some package, like |
Beta Was this translation helpful? Give feedback.
-
We've got official improvements for the typing of #3276 https://github.com/remix-run/remix/releases/tag/remix%401.6.5 |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Change:
To:
Promise<A> | Promise<B>
is equivalent toPromise<A | B>
T
(= Response | AppData)Side-note:
Currently,
AppData = any
. Usingany
in an union, will always reduce toany
. So actually,Promise<AppData>
will reduce toany
due toAppData
in the union. You won't ever seePromise<AppData>
. So given current typing, even without the above improvements, you can removePromise<AppData>
.Beta Was this translation helpful? Give feedback.
All reactions