Reputation: 73808
I want to extend fastify
request object to include information about the session.
According to the documentation, this should be enough:
declare module "fastify" {
interface Session {
user_id: string
other_key: your_prefer_type
id?: number
}
}
However, if I do it that way, then all my type imports start failing.
src/factories/createServer.ts:189:19 - error TS2349: This expression is not callable.
Type 'typeof import("fastify")' has no call signatures.
189 const fastify = Fastify({
If I do something like this,
declare module "fastify" {
import Fastify from 'fastify';
interface Session {
user_id: string
other_key: your_prefer_type
id?: number
}
export = Fastify;
}
Then the default import works, but all other imports break, e.g.
src/factories/createServer.ts:11:8 - error TS2305: Module '"fastify"' has no exported member 'FastifyRequest'.
11 type FastifyRequest,
What am I doing wrong here?
Upvotes: 2
Views: 2173
Reputation: 33
In a custom-material.d.ts file :
import "@mui/material/Typography";
declare module '@mui/material/Typography' {
interface TypographyPropsVariantOverrides {
h1Bold: true;
}
}
This extends TypographyPropsVariantOverrides
on the actual module.
Upvotes: 1
Reputation: 73808
My mistake was that I added these declarations to fastify.d.ts
file.
If this happens to you, just rename the file to something that is not the exact name of the module, e.g. my-fastify.d.ts
.
Upvotes: 2
Reputation: 53205
There is a not so known difference between non-module / global script declaration, and a classic module:
The JavaScript specification declares that any JavaScript files without an
export
or top-levelawait
should be considered a script and not a module.Inside a script file variables and types are declared to be in the shared global scope
What very probably happens in your first attempt, is that you placed the declaration in a file with no import/export statement. Therefore TS considered it as a global declaration, which overwrites the default export of "fastify"
module.
// /src/globalDeclaration.d.ts
// NO top-level import/export
// Global declaration type
declare module "fastify" {
interface Session {
user_id: string;
other_key: boolean; // your_prefer_type
id?: number;
}
}
// /src/index.ts
import Fastify from "fastify";
const fastify = Fastify(); // Error: Type 'typeof import("fastify")' has no call signatures.ts(2349)
Demo on CodeSandbox: https://codesandbox.io/s/peaceful-resonance-fc1swm?file=/src/index.ts
To fix the issue, then as suggested in the TS docs:
If you have a file that doesn’t currently have any imports or exports, but you want to be treated as a module, add the line:
export {};
which will change the file to be a module exporting nothing.
So let's add the empty export (could be anywhere in the file) to turn the declaration into a module augmentation only.
But then make sure to explicitly import the file, even if there is nothing to "import from" it: we just want TS to perform the side effect of augmenting the module.
// /src/moduleAugmentation.d.ts
export {}; // Make an import or export to turn the file into a module augmentation only
declare module "fastify" {
interface Session {
user_id: string;
other_key: boolean; // your_prefer_type
id?: number;
}
}
// /src/index.ts
import Fastify, { FastifyRequest } from "fastify";
import fastifySession from "@fastify/session";
import fastifyCookie from "@fastify/cookie";
import "./moduleAugmentation"; // Now we have to explicitly import the module augmentation file, even just for its side effect
const fastify = Fastify();
fastify.register(fastifyCookie);
fastify.register(fastifySession, {
secret: "a secret with minimum length of 32 characters"
});
fastify.addHook("preHandler", (request, reply, next) => {
const b = request.session.other_key;
// ^? (property) Session.other_key: boolean
next();
});
Demo on CodeSandbox: https://codesandbox.io/s/inspiring-phoebe-ly086x?file=/src/index.ts
Upvotes: 10