Summary
Issue #662 fixed the @cloudflare/workers-types/experimental import. In v2.1.4, the Queue type mismatch is resolved, but WorkersKvStore still causes a TypeScript error for projects using wrangler-generated types (wrangler types / @cloudflare/vite-plugin).
The generated worker-configuration.d.ts re-declares KVNamespace under a different module path. TypeScript treats these as nominally distinct types even though they are structurally identical.
Affected versions
@fedify/cfworkers: 2.1.4
wrangler: 4.80.0
@cloudflare/vite-plugin: 1.30.0
@cloudflare/workers-types: 4.20260405.1
Error example
server/worker/federation/fedify.ts(26,28): error TS2345:
Argument of type 'KVNamespace<string>' is not assignable to parameter of type
'import(".../node_modules/@cloudflare/workers-types/index").KVNamespace<string>'.
Types of property 'get' are incompatible.
Note: WorkersMessageQueue(env.QUEUE_BINDING) compiles cleanly in v2.1.4. Only WorkersKvStore(env.KV_BINDING) still errors.
Root cause
There are two sources of Cloudflare runtime types:
| Source |
Loaded via |
Module path |
@cloudflare/workers-types (npm) |
@fedify/cfworkers dependency |
node_modules/@cloudflare/workers-types/index |
worker-configuration.d.ts (generated) |
wrangler types or @cloudflare/vite-plugin |
local file |
Both define structurally identical KVNamespace, but TypeScript's module-scoped type identity means KVNamespace from source A is not assignable to KVNamespace from source B.
This is not an experimental vs standard entrypoint issue (that was #662). This is a package types vs generated types identity mismatch that affects any project using wrangler types or @cloudflare/vite-plugin for type generation.
Why #662's fix doesn't fully cover this case
The fix in #662 (commit 7b2bdff) changed the import from @cloudflare/workers-types/experimental to the standard @cloudflare/workers-types entrypoint. This helps projects that configure their tsconfig to include @cloudflare/workers-types directly (both sides share the same module path), and fully resolved the Queue type mismatch.
However, KVNamespace still mismatches because Cloudflare's recommended workflow (wrangler types) generates a standalone worker-configuration.d.ts that re-declares KVNamespace with a different module identity.
Proposed fix: use a structural (duck-typed) interface for WorkersKvStore
Instead of importing the concrete KVNamespace type from @cloudflare/workers-types:
// current (2.1.4)
import { KVNamespace } from "@cloudflare/workers-types";
class WorkersKvStore implements KvStore {
constructor(namespace: KVNamespace<string>) { ... }
}
Define a minimal structural interface for what the code actually uses:
// proposed
interface KVNamespaceLike {
getWithMetadata<Metadata = unknown>(
key: string,
options: KVNamespaceGetOptions<"json">
): Promise<KVNamespaceGetWithMetadataResult<unknown, Metadata>>;
put(key: string, value: string, options?: KVNamespacePutOptions): Promise<void>;
delete(key: string): Promise<void>;
list<Metadata = unknown>(options?: KVNamespaceListOptions): Promise<KVNamespaceListResult<Metadata>>;
}
class WorkersKvStore implements KvStore {
constructor(namespace: KVNamespaceLike) { ... }
}
This approach:
- Accepts any object that structurally matches (wrangler-generated,
@cloudflare/workers-types, or runtime)
- Could eliminate
@cloudflare/workers-types as a peer dependency for KV
- Follows the same pattern Fedify uses elsewhere (e.g.
KvStore, MessageQueue are structural interfaces)
- Matches what was apparently already done for
Queue (which now works without @ts-expect-error)
Current workaround
// @ts-expect-error — @fedify/cfworkers imports KVNamespace from @cloudflare/workers-types; wrangler/vite generates its own nominal KVNamespace
kv: new WorkersKvStore(env.FEDIFY_KV),
Related
Summary
Issue #662 fixed the
@cloudflare/workers-types/experimentalimport. In v2.1.4, theQueuetype mismatch is resolved, butWorkersKvStorestill causes a TypeScript error for projects using wrangler-generated types (wrangler types/@cloudflare/vite-plugin).The generated
worker-configuration.d.tsre-declaresKVNamespaceunder a different module path. TypeScript treats these as nominally distinct types even though they are structurally identical.Affected versions
@fedify/cfworkers: 2.1.4wrangler: 4.80.0@cloudflare/vite-plugin: 1.30.0@cloudflare/workers-types: 4.20260405.1Error example
Note:
WorkersMessageQueue(env.QUEUE_BINDING)compiles cleanly in v2.1.4. OnlyWorkersKvStore(env.KV_BINDING)still errors.Root cause
There are two sources of Cloudflare runtime types:
@cloudflare/workers-types(npm)@fedify/cfworkersdependencynode_modules/@cloudflare/workers-types/indexworker-configuration.d.ts(generated)wrangler typesor@cloudflare/vite-pluginBoth define structurally identical
KVNamespace, but TypeScript's module-scoped type identity meansKVNamespacefrom source A is not assignable toKVNamespacefrom source B.This is not an
experimentalvsstandardentrypoint issue (that was #662). This is a package types vs generated types identity mismatch that affects any project usingwrangler typesor@cloudflare/vite-pluginfor type generation.Why #662's fix doesn't fully cover this case
The fix in #662 (commit 7b2bdff) changed the import from
@cloudflare/workers-types/experimentalto the standard@cloudflare/workers-typesentrypoint. This helps projects that configure their tsconfig to include@cloudflare/workers-typesdirectly (both sides share the same module path), and fully resolved theQueuetype mismatch.However,
KVNamespacestill mismatches because Cloudflare's recommended workflow (wrangler types) generates a standaloneworker-configuration.d.tsthat re-declaresKVNamespacewith a different module identity.Proposed fix: use a structural (duck-typed) interface for
WorkersKvStoreInstead of importing the concrete
KVNamespacetype from@cloudflare/workers-types:Define a minimal structural interface for what the code actually uses:
This approach:
@cloudflare/workers-types, or runtime)@cloudflare/workers-typesas a peer dependency for KVKvStore,MessageQueueare structural interfaces)Queue(which now works without@ts-expect-error)Current workaround
Related