Avoid Type '{}' is not assignable to type 'X' - node.js

I'm migrating JavaScript project to TypeScript.
Using a node module in TS such as URL is causing some trouble for me:
import nodeUrl = require('url');
// ...
// this worked fine in JS
nodeUrl.format({
// just for demonstration
x: this.getX(someObj),
y: this.getY(someObj)
});
Results in:
Type '{}' is not assignable to type 'string'
This is due to the definition of that module function. From #types/node/index.d.ts:
declare module "url" {
export interface Url {
href?: string;
protocol?: string;
auth?: string;
hostname?: string;
port?: string;
host?: string;
pathname?: string;
search?: string;
query?: string | any;
slashes?: boolean;
hash?: string;
path?: string;
}
export function parse(urlStr: string, parseQueryString?: boolean, slashesDenoteHost?: boolean): Url;
export function format(url: Url): string;
export function resolve(from: string, to: string): string;
}
My question is how do you avoid/fix this error without changing the declaration file?

Should be something like:
import nodeUrl = require('url');
declare module "url" {
export function format(url: Url): string;
export function format(x: any, y: any): string;
export function format(url: any): string;
}
More info about this can be found in Module Augmentation.

You could use an index signature:
export function format(url: {[index: string]: string}): string
This will make it so that format still requires an object with string keys and values, but the key names can be anything. Of course, you can mix and match the types to fit your needs.

Found another way to fix it:
nodeUrl.format(<any> {
// just for demonstration
x: this.getX(someObj),
y: this.getY(someObj)
});

Related

Argument of type '(req: Request, res: IResponse, next: NextFunction) => void' is not assignable to parameter of type 'PathParams' with express.js

I tried 2 solutions. One is to use module augmentation. Two is to import ExpressRequest and extend it.
First Solution:
id?: Types.ObjectId | undefined;
media?: string;
username?: string;
user?: User | null | undefined;
path: string;
cookies: any;
body: RequestBody;
params: RequestParams;
file: RequestFile;
files: object[] | [];
following: {username: string, following: string[], _id}[];
query: any;
but I get Errors:
Subsequent property declarations must have the same type. Property 'body' must be of type 'ReqBody', but here has type 'RequestBody'.ts(2717)
*Subsequent property declarations must have the same type. Property 'params' must be of type 'P', but here has type 'RequestParams'.ts(2717)
*Subsequent property declarations must have the same type. Property 'query' must be of type 'ReqQuery', but here has type 'any'.ts(2717)
when I change the types as it said I should do, I get Errors:
type ReqBody = /unresolved/ any
Cannot find name 'ReqBody'.ts(2304)
type P = /unresolved/ any
Cannot find name 'P'.ts(2304)
type ReqQuery = /unresolved/ any
Cannot find name 'ReqQuery'.ts(2304)
Second solution:
when I change this types to my own types TS tell me it has to be the ReqBody, 'P' and 'ReqQuery' types.
import { Request as ExpressRequest } from 'exess';
export interface Request extends ExpressRequest {
id?: Types.ObjectId | undefined;
media?: string;
username?: string;
user?: User | null | undefined;
path: string;
cookies: string[];
body: ReqBody;
params: P;
file: RequestFile;
files: object[] | [];
following: {username: string, following: string[], _id}[];
query: ReqQuery;
}
but I get the error:
Interface 'Request' incorrectly extends interface 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'. Types of property 'params' are incompatible. Type 'RequestParams' is not assignable to type 'ParamsDictionary'. Index signature for type 'string' is missing in type 'RequestParams'.

Query variable of 4 possible types

Typescript in my node server suggests four possible types of query:
string | QueryString.ParsedQs | string[] | QueryString.ParsedQs[]
How can I avoid that? I know there's a possible way of ignoring/parsing these types as it's the first time I receive it but I have no idea how to achieve that.
Argument of type 'string | ParsedQs | string[] | ParsedQs[]' is not assignable to parameter of type string.
I had the same problem with Express User.
I suggest you to override these types inside the file you calling them.
Example:
interface ExpressUser {
email: string;
firstname: string;
lastname: string;
password: string;
user_id: number;
}
declare global {
namespace Express {
interface User extends ExpressUser { }
}
}

How to set default values for DTO in nest js?

I want to set default values for a node in a DTO. So if the value for that node is not passed, a default value will be used. Although this is working, I want the node should be present, the values is optional.
import { IsNotEmpty, IsDefined } from "class-validator";
export class IssueSearch
{
#IsDefined()
search: string;
#IsNotEmpty()
length: number = 10;
#IsNotEmpty()
lastId: string = "0"
}
This doesn't serve my purpose. I want the url to be searched like so
http://base-url/folder?search=value
If the value is not passed it should not throw an error.
But if the param search is not there it should throw an error.
If you want to set a default value go to entity and set in the field for example in mongo db
export class DumpDoc extends Document {
#Prop()
title: string;
#Prop({ default: new Date() }) //set as default
createdAt: string;
}

util.inspect.defaultOptions in TypeScript

In node.d.ts its declared as
declare module "util" {
export function inspect(object: any, showHidden?: boolean, depth?: number | null, color?: boolean): string;
export function inspect(object: any, options: InspectOptions): string;
}
so I cant extend it
I tried
declare module 'util' {
export interface inspect {
defaultOptions: InspectOptions;
}
}
but it keeps erroring
Property 'defaultOptions' does not exist on type '{ (object: any, showHidden?: boolean, depth?: number, color?: boolean): string; (object: any, opt...'.
Use namespace to extend function.
And it already fixed in #types/node

Typescript: Method to implement an interface with 3 different signatures?

I am trying to wrap a function/method available in winston (node loggin framework), I have found its interface
interface LeveledLogMethod {
(msg: string, callback: LogCallback): LoggerInstance;
(msg: string, meta: any, callback: LogCallback): LoggerInstance;
(msg: string, ...meta: any[]): LoggerInstance;
}
I would like to implement a method called "error" that would take the above signatures.
I am only wrapping it, so I will be calling the winston function directly.
If anybody is familiar with winston, I basically have 2 loggers setup and all consumers go through my main loggging class and I use either the 1st logger or second logger depending on the loglevel so I need to wrap it.
You can use optional properties and types to add that to your function so it matches the interface.
For example:
interface LeveledLogMethod {
(msg: string, callback: () => void): string;
(msg: string, meta: any, callback: () => void): string;
(msg: string, ...meta: any[]): string;
}
let error: LeveledLogMethod = function (msg: string, b: () => void | any, c?: () => void): string {
return '';
}
Use 3 interfaces this way:
interface A {}
interface B {}
interface C {}
const variable: A|B|C = {};

Resources