cloudflarecloudflare-workerscloudflare-appswranglercloudflare-kv

How to import Cloudflare KV Namespace Variable?


I'm using KV namespace defined in cargo.toml by adding to it the lines

kv_namespaces = [
  { binding = "SITE_DATA", id = "<test-site-id>" }
]

When I try to import the SITE_DATA variable in my Worker script as shown, and I run wrangler publish or wrangler build, I get the error

[tsl] ERROR in /home/x/test/src/handlers/foo.ts(1,29)
      TS2306: File '/home/x/test/node_modules/@cloudflare/workers-types/index.d.ts' is not a module.
ts-loader-default_e3b0c44298fc1c14

Why is this error happening, and how do we properly import SITE_DATA so that we can do things like SITE_DATA.put("data", data)?

src/handlers/foo.ts

import { KVNamespace } from '@cloudflare/workers-types'

declare const SITE_DATA: KVNamespace

export const Foo = async () => {
  const data = {
    title: 'Hello World',
  }
  SITE_DATA.put('posts', JSON.stringify(data))

  return new Response("ok")
}

Based on https://levelup.gitconnected.com/create-a-api-on-the-edge-using-typescript-and-cloudflare-workers-e71fea7fc1b6

tsconfig.json

{
  "compilerOptions": {
    "outDir": "./dist",
    "module": "commonjs",
    "target": "esnext",
    "lib": ["esnext"],
    "alwaysStrict": true,
    "strict": true,
    "preserveConstEnums": true,
    "moduleResolution": "node",
    "sourceMap": true,
    "esModuleInterop": true,
    "types": [
      "@cloudflare/workers-types",
      "@types/jest",
      "@types/service-worker-mock"
    ]
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist", "test"]
}

Solution

  • Wrangler will look for a wrangler.toml unless told otherwise. cargo.toml means nothing in this context, given it isn't a rust project.

    once you've renamed your config file to wrangler.toml (or modified your build script to point to cargo.toml in despite of the least astonishement principle) you'll need to declare your globals in an ambient module src/bindings.d.ts

    declare global  {
        const WHATEVER: string;
        const SITE_DATA: KVNamespace;
    }
    

    You shouldn't explicitly import workers types. Having it on tsconfig will already let your IDE take advantage of the definitions.

    When in module format, workers won't put your bindings on the global scope. They will come as properties for the env argument. No ambient declaration is due.

    export default  {
       fetch:(request, env, ctx) {
           // Here, env.SITE_DATA  is a KVNamespace
       }
    }