declare global variable in seperate file nodejs+typescript - node.js

I am new to typescript and this might be a noob question.
I want to extend global variable provided by nodejs.
As per this blog I wrote this code and it is working
declare global {
namespace NodeJS {
interface Global {
appRoot: string;
}
}
}
import path from "path";
global.appRoot = path.join(__dirname,'../');
console.log(global.appRoot)
but I want to take this global to separate file and if I move this to a new global.d.ts file
I dont know what to export
I am getting this error
Augmentations for the global scope can only be directly nested in
external modules or ambient module declarations.
if do this
declare module NodeJS {
export interface Global {
appRoot: string;
}
}
I get this error
Property 'appRoot' does not exist on type 'Global & typeof globalThis'.
Property 'appRoot' does not exist on type 'Global & typeof globalThis'.

Which version of global declaration works always seems to depend on project setup. In your case, the following global.d.ts should work:
export {}; // make the file a module, to get rid of the warning
declare global {
namespace NodeJS {
interface Global {
appRoot: string;
}
}
}
Also make sure that only either one of the definitions is present.

Related

Cannot find module when using type from another module in class-validator

I'm using typescript on both frontend and backend, so I wanted to create a "shared types" package for them. For the backend I'm using nest.js and I recently ran into an issue with the class-validator package.
In my shared types package I created the following enum-like type (since enums itself don't seem to be working if they are being used from a node module):
export const MealTypes = {
BREAKFAST: 'Breakfast',
LUNCH: 'Lunch',
DINNER: 'Dinner',
SNACK: 'Snack'
} as const;
export type ObjectValues<T> = T[keyof T];
export type MealType = ObjectValues<typeof MealTypes>;
I've installed the module locally using npm i and I'm able to import the type in my backend like this:
import { MealType, MealTypes } from '#r3xc1/shared-types';
Since I am not able to use this constant for the IsEnum class validator, I wrote my own:
#ValidatorConstraint({ name: 'CheckEnum', async: false })
export class CheckEnumValidator implements ValidatorConstraintInterface {
validate(value: string | number, validationArguments: ValidationArguments) {
return Object.values(validationArguments.constraints[0]).includes(value);
}
defaultMessage(args: ValidationArguments) {
return `Must be of type XYZ`;
}
}
and then I'm using it in a DTO class like this:
export class CreateMealDTO {
#Validate(CheckEnumValidator, [MealTypes])
#IsNotEmpty()
meal_type: MealType;
}
But as soon as I add the #Validate(...) I get the following error on start:
Error: Cannot find module '#r3xc1/shared-types'
It only does this, if I am passing a type that has been imported from a node module into a validator. It also happens with other validators like IsEnum.
I'm not really sure why this error is happening and I appreciate any hints or help!

how to remove Individual declarations in merged declaration must be all exported or all local.ts error?

I am implementing a redux store and I am pretty sure this is not a redux issue, in my store file, dog.store.ts I am exporting the store initial state:
export interface IDogState{
dog:number;
}
export const INITIAL_DOG_STATE:IDogState = {
dog:0
}
to later import it in my store.ts file:
import { IDogState,dogReducer,INITIAL_DOG_STATE } from "./redux/stores/dog.store";
this is where I get the error:
Individual declarations in merged declaration 'INITIAL_DOG_STATE' must
be all exported or all local.ts(2395)
Binding element 'INITIAL_DOG_STATE' implicitly has an 'any' type.
this was not an issue not long ago, I wonder if it is because a change in typescript or Angular compiler configuration.

Extending class from external 3rd party typescript module

Hello I have a problem with overwriting types
I want overwrite a type from a libary that adds a property to an other library's typings, the line is: https://github.com/discord-akairo/discord-akairo/blob/e092ce4e0c9e749418601476bcd054a30a262785/src/index.d.ts#L14
and in my code I declare it like this:
declare module 'discord.js' {
export interface Message {
util?: KopekUtil;
}
}
KopekUtil is extending the CommandUtil and the error i get is:
TS2717: Subsequent property declarations must have the same type. Property 'util' must be of type 'CommandUtil', but here has type 'KopekUtil'. index.d.ts(16, 13): 'util' was also declared here.
You mentioned trying to extend Command util class like so
export class KopekUtil extends CommandUtil{
constructor(handler, message: Message | CommandInteraction) {
super(handler, <Message>message);
}
send(options:string | MessageOptions , reply? : boolean){
//your logic
}
}
But I'm afraid it's not possible to overwrite a class that comes from external typescript module.
Although you can introduce a new method in class from external module or extend one of existing methods using object protoype.
The right way to do that
util.js
declare module 'discord-akairo'{
export interface CommandUtil {
mySendMethod(options:string | MessageOptions , reply?:any) : boolean
}
};
CommandUtil.prototype.mySendMethod = function (options:string | MessageOptions , reply?:any) : boolean{
return true;
}
Typescript now merges interfaces and you can use your extension
const message = new Message(new Client(),{},new TextChannel(new Guild(new Client(),{})))
message.util.mySendMethod("hello")

extend express request object with sequelize model using typescript 2

I have some models, such as:
import * as Sequelize from 'sequelize'; // !
export interface UserAttributes {
id?: number;
email?: string;
googleToken?: string;
}
export interface UserInstance extends Sequelize.Instance<UserInstance, UserAttributes>, UserAttributes {
}
export interface UserModel extends Sequelize.Model<UserInstance, UserAttributes> {
}
// ... model definition
I need use import statement to use generic type Sequelize.Instance<TInstance, TAttributes>
I wright some middleware to add user instance to request object (or req.session object, doesn't metter)
Then I need typescript to know my new extending, for this I have file src/_extra.ts with content:
/// <reference path="./models/db.ts" /> -- also does not work
declare namespace Express {
export interface Request {
oauthClient: Googleapis.auth.OAuth2; // Googleapis is namespace
user?: UserInstance; // or ContactsProject.Models.UserInstance;
}
export interface Session {/* ... some same */}
}
I need to import my UserInstance type from my model file. Imports break all my _extra namespace definitions, inside namespace I can't use imports.
I have tried create namespace ContactsProject, but I getting same problem: if I use imports, typescript don't see my namespace, if I don't, I cant define my UserInstance type.
Sequelize doesn't declare namespaces.
I just want import some generic type in my namespace.
I use typescript Version 2.0.3.
When you use an import statement in a file, TypeScript treats it as a module. Therefor any namespace you declare inside it will not be global anymore, but local to that module.
Import your interface, and then wrap the namespace declaration in a declare global { ... }.

Exception with type definition for random-string module

I am trying to write a .d.ts for random-string.
I have this code:
declare module "random-string" {
export function randomString(opts?: Object): string;
}
I am able to import the module no problem then with:
import randomString = require('random-string');
and invoke:
console.log(randomString); // --> [Function: randomString]
However, this doesn't work with or without an argument:
console.log(randomString({length: 10});
console.log(randomString());
I get this error from tsc:
error TS2088: Cannot invoke an expression whose type lacks a call signature.
I looked in the source for random-string and found this code for the method I am trying to interface with:
module.exports = function randomString(opts) {
// Implementation...
};
I managed to write a .d.ts for the CSON module, no problem, but that was exporting a 'class' rather than a function directly. Is that significant?
Your declaration says there is a module named random-string with a function named randomString within it...
So your usage should be:
console.log(randomString.randomString({ length: 10 }));
console.log(randomString.randomString());
If the module does actually supply the function directly, you should adjust your definition to do the same:
declare module "random-string" {
function randomString(opts?: Object): string;
export = randomString;
}
This would allow you to call it as you do in your question.

Resources