Reputation: 1555
I'm converting an existing Node.js project to be fully TypeScript-based. I previously had a static Sql
class (an object with sub-objects containing MySQL helper functions). An example would be Sql.user.findById
. The Sql
class also had a query
function for executing raw MySQL queries without needing to expose the underlying MySQL connection.
What I would like now is a namespace named Sql
containing the query
function, and then in the files that used to contain the sub-classes, I would like namespaces such as Sql.User
that export functions like findById
.
The problem is, I can't figure out how to nest namespaces like this while being able to access query
in the nested namespaces.
Right now what I have is this:
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 );
}
);
}
};
When I try and compile, however, I get a number of errors that look like this:
src\sql\queries\resetPassword.ts(11,13): error TS2339: Property 'query' does not exist on type 'typeof Sql'.
How can I "backreference" the query function from the parent file? I can't import { Sql } from "../sql"
of course, because then Sql
is a duplicate definition, and I get an error that src/sql/sql.ts has no exported member "Sql"
.
Upvotes: 5
Views: 3706
Reputation: 1555
I solved my namespace referencing problem by alias-importing the parent namespace in the child namespace files:
import { Sql as sql } from "../sql";
...
namespace Sql.User {
export function ... {
sql.query(...);
}
}
This allows the Sql.User
namespace to use functions in the Sql
namespace from another file. I still don't know how to merge the namespaces into one so that Sql.User
and its siblings can be imported simply by importing sql.ts
. I need to create another question for that.
Upvotes: 5