fix(types): type fastify.jwt as namespace map when namespaces are declared - #422
Merged
Eomm merged 2 commits intoJul 26, 2026
Merged
Conversation
…lared
When the plugin is registered with the `namespace` option, `fastify.jwt`
is a namespace -> JWT map at runtime, but the type declaration hardcoded
it as `JWT`. Since declaration merging cannot override a conflicting
property type, users had no way to fix it on their side.
Type the decorator with a new `JwtDecorator` conditional type: it stays
`JWT` by default and resolves to `Record<Namespaces, JWT>` when users
declare their registered namespaces via the existing `FastifyJWT`
declaration-merging interface:
declare module '@fastify/jwt' {
interface FastifyJWT {
namespaces: 'auth' | 'admin'
}
}
Non-namespace users are unaffected. Adds tstyche coverage for the
namespace map shape and documents the pattern in the README.
Closes fastify#395
Eomm
approved these changes
Jul 26, 2026
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #395 (also addresses the
fastify.jwthalf of #321).Problem
When registering the plugin with the
namespaceoption,fastify.jwtbecomes a{ [namespace]: JWT }map at runtime (index.js), but the type declaration hardcodesFastifyInstance.jwtasJWT. Because TypeScript declaration merging cannot override a conflicting property type, users have no way to correct this on their side —app.jwt.myNamespace.sign(...)always fails to typecheck even though it works at runtime.Fix
Types-only, no runtime change.
fastify.jwtis now typed with a new exportedJwtDecoratorconditional type. It defaults toJWT, so existing non-namespace users are completely unaffected. Namespace users declare their registered namespaces through the existingFastifyJWTdeclaration-merging interface (the same mechanism already used forpayload/user):The conditional uses
[Namespaces] extends [string]to avoid distributing over the union (Record<'auth', JWT> | Record<'admin', JWT>would be wrong).Note on #397: the registration-scoped types rework will touch
types/index.d.tstoo, but it is blocked on unmerged fastify core work and explicitly keeps namespaced decorators on declaration-merging helpers, so this interim non-breaking fix is complementary rather than competing.Tests
New
types/namespace.tst.tsasserts the map shape (Record<'auth' | 'admin', JWT>), per-namespaceJWTmethods, and negatives: the single-decorator members (sign/verify/decode) and undeclared namespaces are not present. tstyche checks test files in isolation, so the augmentation does not affect the existing default-mode assertions intypes/index.tst.ts.README: documented the pattern in the Namespace → TypeScript section.
Checklist
npm run test— lint clean, 176/176 unit tests (100% coverage), 35/35 type assertions