index.d.ts type definitions being ignored by tsc when compiling - node.js

I have an Express app built in TypeScript that I'm attempting to compile using the tsc CLI tool.
An issue that I'm facing, however, is that tsc seems to ignore the index.d.ts file that I've created and used to mutate the Express Request object.
This is my index.d.ts file:
declare global{
namespace Express{
export interface Request{
foo: string;
}
}
}
This allows me to do stuff like this inside my controller's requests without TypeScript spitting out a does not exist error:
export const example = async (req: Request) => {
const { foo } = req;
// Outputs "bar". This works completely fine in development.
console.log(foo);
};
I'm running the following command to build my app:
tsc ./Main.ts --outdir build
Which results in the following error multiple times across every controller that uses it:
error TS2339: Property 'foo' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'.

Try adding an empty export to your index.d.ts file:
export {};
declare global{
namespace Express{
export interface Request{
foo: string;
}
}
}

Related

Node Js and Typescript call global function with parameters

I have a logger function in logger.ts
export const Logger=(message:string, module?:string, method?:string)=>{
console.log(`${module} ${message}`)
}
In types/global.d.ts
declare global {
var Log: any;
}
export {}
In index.ts
import { Logger } from './src/utils/logger';
global.Log=Logger;
global.Log("Hello world");
It works without any problem. But in global.Log i can't see the parameters and intellisense not working.
How can I see parameters for global.Log?
I believe Intellisense is not working because the variable Log is of any type. Try defining global as below:
declare global {
var Log: (message: string, module?: string, method?: string) => void;
}
export {};
Intellisense will need a specific type (not any or unknown) in order to suggest parameters.
Also, there is no need to prefix Log with global (i.e. global.Log) as Log is in the global context (accessible from anywhere), and it is not possible to use global.Log - global is not a variable.

Solved - Mocha cannot find global types

I wrote small node app with express and made global interface "LocalUser" which is essentially express response but predefined locals. Instead of importing it everywhere, I've decided to create global type
declare global {
export interface LocalUser extends express.Response {
locals: UsersTokens;
}
}
For some reason, mocha does not like it and send me
TSError: тип Unable to compile TypeScript:
src/router/index.ts(40,44): error TS2304: Cannot find name 'LocalUser'.
Minimal code to reproduce it:
constructor() {
this.app = express();
}
this.app.all('*', function (_req, res: LocalUser) {
const { message, code, name, status } = new NotFoundError();
res.status(status).json({ message, code, name });
});
this.server = http.createServer(this.app);
this.server.listen(getConfig().httpPort, () => {
console.log(`Listening on ${getConfig().httpPort}`);
});
Node: "18.7.0"
Mocha: "^10.0.0",
Its my first ever time using global interfaces. Is this just a normal behaviour ? Whole app is working like it should and works in js but only mocha has problems
Edit: I just removed global export. Couldn't figure out, how to properly export global interfaces

type 'typeof globalThis' has no index signature

i get this error whenever i try to add a function to the global nodejs global namsepace in a TypeScript environment.
Element implicitly has an 'any' type because type 'typeof globalThis'
has no index signature
declaring the global namespace
declare global {
namespace NodeJS {
interface Global {
signin(): string[]
}
}
}
so if i try this
global.signin = () => {}
it returns a
Element implicitly has an 'any' type because type 'typeof globalThis'
has no index signature
I was having a similar issue and I found that node's global typings were changed recently-ish; you can now override them by doing:
// global.d.ts
declare global {
function someFunction(): string;
var someVariable: string;
}
Note: this will not work with let or const you must use var.
// index.ts
global.someFunction = () => "some value";
global.someVariable = "some value";
Below is an example for Node v16
// globals.d.ts
declare module globalThis {
var signin: () => string[];
}
You should declare a global declared as interface in global.d.ts like this:
export interface global {}
declare global {
var signin: ()=>string[]
}
The vscode gives correct code hints
You have to use the var keyword in declare global, and remove namespace NodeJS {.
Like this:
//globals.d.ts
import type { EventEmitter } from "events";
declare global {
var myGlobal: EventEmitter;
}
/// <reference path="globals.d.ts" />
//index.ts
// reference needs to be at top of file
import { EventEmitter } from "events";
global.myGlobal = new EventEmitter();
global.myGlobal // EventEmitter type: EventEmitter
window.myGlobal // EventEmitter type: EventEmitter
Or if you don't have any imports in the .d.ts file:
//namedoesntmatter.d.ts
declare var a: string;
//index.ts
global.a = "Hello"
global.a //Hello type: string
window.a //Hello type: string
I had the same problem with a svelte.kit app. my database module use a global variable to store the dbClient as a promise. VSCode stop complain when the global.d.ts file had this content.
import type { MongoClient } from 'mongodb'
declare global {
namespace globalThis {
var _mongoClientPromise: Promise<MongoClient>
}
}
This is how I solved with Node.js V16+
// global.d.ts
export declare global {
declare module globalThis {
var MyVar: object;
}
}
I too had the same issue. Fixed it by the below code.
declare global {
function signin(): Promise<string[]>
}
in my own case i didn't quite realize until later that the global namespace i declared was case sensitive.
instead of this. before my question was edited it was namespace NODEJS
declare global {
namespace NODEJS {
interface Global {
signin(): string[]
}
}
}
it was supposed to be this
declare global {
namespace NodeJS {
interface Global {
signin(): string[]
}
}
}
pay attention to NODEJS and NodeJS. After i made these changes, typescript was cool with it and it work the way i expected it to.
I tried everything I found here, but nothing worked.Even stranger, VSCode showed NO TypeScript errors, but running tsc still threw:
TS7017: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature.
After hours, I realised I forgot an "include": [ "src/app.ts" ] line in my tsconfig.json file.
Note to future self and for those who may have made the same mistake:
If you have explicitly provided one or more files in TypeScript's config with include, and that does not include the *.d.ts file, where you declared your globals, the build will fail with this error, even if VSCode shows no error (because it sees the global declaration, but TypeScript won't).
just declare variable by var keyword. like this:
// eslint-disable-next-line no-var
var hello = () => { console.log("hello world"); };
// eslint-disable-next-line no-var
var hi: () => number;
globalThis.hello();
globalThis.hi = () => 143;
You can declare variables in .d.ts files, too.

How can I use packages that extend `koa.Request` in TypeScript?

I am trying to use koa-tree-router and koa-bodyparser at the same time, but I keep getting TypeScript errors:
export const userLoggingRouter = new KoaTreeRouter<any, DefaultContext>();
userLoggingRouter.post('/logs/action', (ctx) => {
const logEntries = ctx.request.body;
const user = ctx.state.user;
// ...
});
error TS2339: Property 'body' does not exist on type 'Request'.
I have #types/koa-bodyparser installed, and it contains the following definition:
import * as Koa from 'koa';
declare module 'koa' {
interface Request {
body: string | Record<string, unknown>;
rawBody: string;
}
}
But it doesn't seem to do anything. I found this question, but importing koa-bodyparser directly also does not do anything. How do I get TypeScript to recognize the extended Request type?
Edit: Creating a .d.ts file inside my project containing the following:
import {Request} from "koa";
declare module "koa" {
interface Request {
body: any;
}
}
Made the compile error go away, but this seems like an inelegant solution because I would have to copy over type information for every package that modifies koa.Request.
This was happening because I was using Yarn PnP and I had two different versions of #types/koa installed. Once I added a resolutions field to my package.json that forced all of the other TypeScript definitions to use the same version of #types/koa, everything worked.

Create .d.ts for both a module.exports = function and some interfaces

I have a javascript code similar to this:
module.exports = function foo(language, platform, milliseconds) {
// some code
}
This code should be placed in a module ("mymodule") that will be imported through npm.
I want to create the corrisponding .d.ts file.
I have something like this:
declare module 'mymodule' {
export type Language = 'it' | 'es' | 'de';
export type Platform = 'linux' | 'winzoz';
export function foo(language: Language, platform: Platform, milliseconds?: number): void;
}
But of course it did not work. I tried:
declare module 'mymodule' { export default function foo(myparams: Types): void; }
But this did not work, because I am using module.exports = function f() and not a default export
declare module 'mymodule' { function foo(myparams: Types): void; export = foo; }
But this did not work, because it says that I should use esModuleInterop or use an ugly import foo = require('mymodule'). It does not include the interfaces that I want to export, too.
How can I solve these problems?

Resources