Currently, I am in the process of transitioning an established Node.js project into a fully TypeScript-based system. In the past, there was a static Sql
class which contained sub-objects with MySQL helper functions. For instance, you could access functions like Sql.user.findById
. Additionally, the Sql
class included a query
function for executing raw MySQL queries without exposing the underlying MySQL connection.
My goal now is to organize this structure by creating a namespace called Sql
that houses the query
function and then introducing namespaces like Sql.User
in the files where the sub-classes were previously located, exporting functions such as findById
.
The challenge lies in figuring out how to nest these namespaces while still being able to access the query
function within the nested namespaces.
This is what my current setup looks like:
sql.ts
:
import * as connection from "./connection";
export * from "./queries/confirmEmail";
export * from "./queries/resetPassword";
export * from "./queries/user";
namespace Sql {
export function query( ...args: any[] ) {
return connection.query( args );
}
export class Errors {
static confirmCodeExpired = "45001";
static confirmCodeNonExistent = "45002";
static userAlreadyConfirmed = "45003";
}
}
./queries/resetPassword.ts
:
import "../sql";
namespace Sql.ResetPassword {
type InsertCodeArgs = {
code: string;
userid: number;
canChange: boolean;
}
export function insertCode( args: InsertCodeArgs, cb: Nodeback<void> ) {
Sql.query(
"CALL insert_reset_code( :code, :userid, :canChange );",
{
code: args.code,
userid: args.userid,
canChange: args.canChange ? 1 : 0
},
cb
);
}
export function removeCode( code: string, cb: Nodeback<void> ) {
Sql.query(
"DELETE FROM `resetcodes` WHERE `code` = :code;",
{ code: code },
cb
);
}
export function checkCodeValid( code: string, cb: Nodeback<boolean> ) {
Sql.query(
[
"SELECT NOW() <= `c`.`expires` AS `valid`, `c`.`canchange` as `canchange`, `u`.`id` AS `userid` FROM `resetcodes` AS `c` ",
"INNER JOIN `users` AS `u`",
"ON `u`.`id` = `c`.`userid`",
"WHERE `code` = :code LIMIT 1;"
].join( " " ),
{ code: code },
( err, data ) => {
if ( err ) return cb( err );
if ( !data || data.length === 0 ) return cb( null, null );
return cb( null, data[ 0 ].valid > 0, data[ 0 ].userid, data[ 0 ].canchange > 0 );
}
);
}
};
During compilation, I encounter several errors similar to the following:
src\sql\queries\resetPassword.ts(11,13): error TS2339: Property 'query' does not exist on type 'typeof Sql'.
Is there a way to reference the query function from the parent file? Importing { Sql } from "../sql" results in a duplicate definition of Sql
, leading to an error stating that
src/sql/sql.ts has no exported member "Sql"
.