Your brand-new Shopify app template ships with a TypeScript error (and the one-line fix)
Run this today:
shopify app init # choose Remix
cd your-app && npm install && npx tsc --noEmit
...and there's a good chance you'll be greeted by this wall:
app/shopify.server.ts: error TS2322: Type 'PrismaSessionStorage<PrismaClient<...>>' is not assignable to type 'SessionStorage'.
Types of property 'storeSession' are incompatible.
...
Types have separate declarations of a private property 'compressedScopes'.
You haven't written a single line of code yet. Welcome to Shopify app development.
What's actually happening
That last line is the tell: "separate declarations of a private property" means TypeScript is comparing two different copies of the same class from two different places in node_modules. Check it:
npm ls @shopify/shopify-api
On a fresh template you'll see two versions. As of this writing:
@shopify/shopify-app-session-storage-prisma@8depends on@shopify/shopify-api@^12@shopify/shopify-app-remix@4bundles@shopify/shopify-api@^13
Those ranges don't overlap, so npm installs both - one at the top level, one nested under shopify-app-remix. Your PrismaSessionStorage is built against v12's Session class; the shopifyApp() config expects v13's. Same class name, different declarations, TypeScript (correctly) refuses.
Things that don't fix it
npm dedupe- can't collapse a genuine semver conflict. Tried it, still duplicated.- Deleting
node_modulesand reinstalling - same resolution, same result. as anyon the session storage - compiles, and now you've turned off type checking on the exact seam where your auth sessions live.
The one-line fix
npm install @shopify/shopify-app-session-storage-prisma@^9
v9 peers against @shopify/shopify-api@^13. The nested copy disappears, and:
npm ls @shopify/shopify-api # exactly ONE version
npx tsc --noEmit # green
The related mystery cast you'll see in older code
If you've read open-source Shopify apps, you may have seen billing plan names cast like this:
await billing.require({
plans: [MONTHLY_PLAN as never], // โ why??
...
});
Same root cause. With two @shopify/shopify-api copies, billing plan-name type inference breaks, and as never was the workaround that let people ship. With a single copy, the cast is unnecessary (though harmless).
Why I'm writing this down
I'm building ApprovedKit - a Shopify app boilerplate extracted from a real production app (currently going through App Store review, and we're logging the whole review process live). While verifying that our modules apply cleanly to a fresh official template, we hit this exact error on a clean clone - which means every new Shopify app developer hits it too.
That's the kit's whole philosophy: every gotcha we hit becomes a documented fix at the exact line it matters. If that sounds useful, the early-access version is $99 for the first 30 seats.
Happy shipping - and run npm ls @shopify/shopify-api before you trust your types.
Comments
No comments yet. Start the discussion.