-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: correctly infer deferred types for top-level promises (#7104)
- Loading branch information
Showing
4 changed files
with
77 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@remix-run/server-runtime": patch | ||
--- | ||
|
||
correctly infer deferred types for top-level promises |
88 changes: 45 additions & 43 deletions
88
packages/remix-server-runtime/__tests__/serialize-test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,54 @@ | ||
import type { SerializeFrom } from "../index"; | ||
import { defer, json } from "../index"; | ||
import type { IsNever } from "./utils"; | ||
import { isEqual } from "./utils"; | ||
|
||
describe("SerializeFrom", () => { | ||
it("infers types", () => { | ||
isEqual<SerializeFrom<string>, string>(true); | ||
isEqual<SerializeFrom<number>, number>(true); | ||
isEqual<SerializeFrom<boolean>, boolean>(true); | ||
isEqual<SerializeFrom<String>, String>(true); | ||
isEqual<SerializeFrom<Number>, Number>(true); | ||
isEqual<SerializeFrom<Boolean>, Boolean>(true); | ||
isEqual<SerializeFrom<null>, null>(true); | ||
|
||
isEqual<IsNever<SerializeFrom<undefined>>, true>(true); | ||
isEqual<IsNever<SerializeFrom<Function>>, true>(true); | ||
isEqual<IsNever<SerializeFrom<symbol>>, true>(true); | ||
|
||
isEqual<SerializeFrom<[]>, []>(true); | ||
isEqual<SerializeFrom<[string, number]>, [string, number]>(true); | ||
isEqual<SerializeFrom<[number, number]>, [number, number]>(true); | ||
|
||
isEqual<SerializeFrom<ReadonlyArray<string>>, string[]>(true); | ||
isEqual<SerializeFrom<ReadonlyArray<Function>>, null[]>(true); | ||
|
||
isEqual<SerializeFrom<{ hello: "remix" }>, { hello: "remix" }>(true); | ||
isEqual< | ||
SerializeFrom<{ data: { hello: "remix" } }>, | ||
{ data: { hello: "remix" } } | ||
>(true); | ||
}); | ||
it("infers basic types", () => { | ||
isEqual< | ||
SerializeFrom<{ | ||
hello?: string; | ||
count: number | undefined; | ||
date: Date | number; | ||
isActive: boolean; | ||
items: { name: string; price: number; orderedAt: Date }[]; | ||
}>, | ||
{ | ||
hello?: string; | ||
count?: number; | ||
date: string | number; | ||
isActive: boolean; | ||
items: { name: string; price: number; orderedAt: string }[]; | ||
} | ||
>(true); | ||
}); | ||
|
||
it("infers type from json responses", () => { | ||
let loader = () => json({ hello: "remix" }); | ||
isEqual<SerializeFrom<typeof loader>, { hello: string }>(true); | ||
it("infers deferred types", () => { | ||
let get = (): Promise<Date> | undefined => { | ||
if (Math.random() > 0.5) return Promise.resolve(new Date()); | ||
return undefined; | ||
}; | ||
let loader = async () => | ||
defer({ | ||
critical: await Promise.resolve("hello"), | ||
deferred: get(), | ||
}); | ||
isEqual< | ||
SerializeFrom<typeof loader>, | ||
{ | ||
critical: string; | ||
deferred: Promise<string> | undefined; | ||
} | ||
>(true); | ||
}); | ||
|
||
let asyncLoader = async () => json({ hello: "remix" }); | ||
isEqual<SerializeFrom<typeof asyncLoader>, { hello: string }>(true); | ||
}); | ||
it("infers types from json", () => { | ||
let loader = () => json({ data: "remix" }); | ||
isEqual<SerializeFrom<typeof loader>, { data: string }>(true); | ||
|
||
it("infers type from defer responses", () => { | ||
let loader = async () => defer({ data: { hello: "remix" } }); | ||
isEqual<SerializeFrom<typeof loader>, { data: { hello: string } }>(true); | ||
}); | ||
let asyncLoader = async () => json({ data: "remix" }); | ||
isEqual<SerializeFrom<typeof asyncLoader>, { data: string }>(true); | ||
}); | ||
|
||
// Special case that covers https://github.com/remix-run/remix/issues/5211 | ||
it("infers type from json responses containing a data key", () => { | ||
let loader = async () => json({ data: { hello: "remix" } }); | ||
isEqual<SerializeFrom<typeof loader>, { data: { hello: string } }>(true); | ||
}); | ||
it("infers type from defer", () => { | ||
let loader = async () => defer({ data: "remix" }); | ||
isEqual<SerializeFrom<typeof loader>, { data: string }>(true); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters