ReScript:如何在类型参数中使用未包装多态变体实现缓存addAll绑定
Great question! You're right that directly using [@bs.unwrap] inside an array type parameter doesn't work in ReScript, but there's a clean way to model this without giving up mixed types or splitting your bindings. Here's how to do it:
Step 1: Define a Unwrappable Union Type
First, create a union type that covers both Request.t and string, and mark it with [@bs.unwrap]. This tells ReScript to directly emit the underlying value (no wrapper objects) when compiling:
type cacheable = [@bs.unwrap] [ `Request(Request.t) | `String(string) ]
Step 2: Bind addAll with the Union Type Array
Now you can use this union type as the array element type in your addAll binding. ReScript will automatically unwrap each element in the array to its raw JS value:
[@bs.send] external addAll: (Cache.t, array<cacheable>) => Js.Promise.t<unit> = "addAll"
Step 3: Consistent Binding for add (Optional)
To keep your API consistent, you can update your existing add binding to use the same cacheable type instead of repeating the union:
[@bs.send] external add: (Cache.t, cacheable) => Js.Promise.t<unit> = "add"
How It Works
When you use these bindings, ReScript compiles your code to clean, redundant-free JS. For example:
let exampleCache: Cache.t = ... let apiRequest = Request.make("/api/data") // Using addAll with mixed types addAll(exampleCache, [ `Request(apiRequest), `String("/static/styles.css") ])
Compiles to:
exampleCache.addAll([apiRequest, "/static/styles.css"]);
No extra wrapper objects or helper functions—exactly what you want for Service Worker cache operations.
Fallback Option (If Needed)
If for some reason the above approach doesn't work with your ReScript version, you can create a lightweight helper function to unwrap elements without significant JS overhead:
type cacheable = | Request(Request.t) | Url(string) let unwrap = (item: cacheable) => switch item { | Request(r) => r | Url(s) => s } [@bs.send] external addAllRaw: (Cache.t, array<'a>) => Js.Promise.t<unit> = "addAll" let addAll = (cache: Cache.t, items: array<cacheable>) => addAllRaw(cache, items->Js.Array.map(unwrap))
This adds a single map call, but it's minimal and maintains full type safety.
You don't need to sacrifice mixed type support or split your bindings—this approach keeps your code type-safe and generates clean JS output for Service Worker cache interactions.
内容的提问来源于stack exchange,提问作者Eleanor Holley

