I'm in need of sharing some TypeScript types between my React client and my Express REST API in order to keep the code clean and DRY. Since this is a private proejct I wouldn't share these types through the @types repository, so I've followed the guide on the TypeScript website and this is the result...
Everything is working just fine in the React client: I've installed the types as a dev dependency and used them flawlessly.
In the Express API I get this error and I presume it has something to do with how I structured my package.
What am I doing wrong? As ignorant as I am I'd suppose it's related with how the modules are loaded, but I can't figure out precisely what may be causing the error.
> cross-env NODE_ENV=production node dist/index.js
internal/modules/cjs/loader.js:834
throw err;
^
Error: Cannot find module '@revodigital/suiteods-types'
How I import the module inside the API code
import { AuthEntity, Roles } from '@revodigital/suiteods-types';
@Model()
export class AuthEntityModel implements AuthEntity {
/* ... */
role: Roles;
/* ... */
}
suiteods-types
|_index.d.ts
|_package.json
|_README.md
|_tsconfig.json
index.d.ts
export = Ods;
export as namespace Ods;
declare namespace Ods {
/* ... */
interface AuthEntity extends DomainObject {
email: string;
password: string;
role: Roles;
instanceId: string;
}
enum Roles {
BASE,
STUDENT,
BUSINESS,
INSTRUCTOR,
ADMIN
}
/* ... */
}
package.json
{
"name": "@revodigital/suiteods-types",
"version": "0.1.1",
"description": "Type declarations for suiteods project",
"types": "index.d.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Revo Digital",
"license": "ISC",
"repository": {
"type": "git",
"url": "git+https://github.com/revodigital/suiteods-types.git"
},
"bugs": {
"url": "https://github.com/revodigital/suiteods-types/issues"
},
"homepage": "https://github.com/revodigital/suiteods-types#readme"
}
tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts"
]
}
updated and complete index.d.ts
export = Ods;
export as namespace Ods;
declare namespace Ods {
type IdType = 'Carta Identità' | 'Passaporto' | 'Patente'
type ODSModule = 'SCUOLA' | 'OPERATORI' | 'DRONI' | 'ODS_ROOT'
type Role = 'BASE' | 'STUDENTE' | 'ISTRUTTORE' | 'AMMINISTRATORE' | 'UTENTE_AZIENDALE'
type UserScope = 'INTERNAL' | 'WHOLE'
interface Address {
street: string;
city: string;
province: string;
CAP: string;
}
interface Credentials {
email: string;
password: string;
}
interface LoggedEntity {
authEntity: AuthEntity;
baseUser: BaseUser;
}
interface ModulesInstancesMap {
SCUOLA: string;
OPERATORI: string;
DRONI: string;
ODS_ROOT: string;
}
interface MultiTenantController {
}
interface Tenant {
_id: string;
role: Role | ODSModule;
}
interface TenantInfo {
tenant: Tenant;
relativeGodRole: Role;
}
interface AuthEntity extends DomainObject {
email: string;
password: string;
role: Role;
instanceId: string;
}
interface BaseUser extends DomainObject {
firstName: string;
lastName: string;
phone: string;
address: Address;
scope: UserScope;
}
interface BelongsToModule {
module: ODSModule;
}
interface Business extends DomainObject {
businessName: string;
pIva: string;
tel: string;
pec: string;
recipientCode: string;
address: Address;
}
interface DomainObject {
_id: string;
}
interface HasTenant {
tenantInfo: TenantInfo;
}
interface Instructor extends BaseUser {
licenseCode: string;
}
interface InternalWholeSuiteUser extends BaseUser {
modulesInstancesMap: ModulesInstancesMap;
}
interface InternalModuleUser extends BaseUser, BelongsToModule {
moduleInstanceId: string;
}
interface School extends Business, HasTenant {
cApr: number;
}
interface Student extends BaseUser {
stateIssuedIdNumber: string;
stateIssuedIsType: IdType;
job: string;
businessId?: string;
}
}
In addition to the precious @Paleo edits, adding an index.js file with the content that follows solved the issue.
index.js
module.exports = {};
Updated file structure
suiteods-types
|_index.d.ts
|_index.js
|_package.json
|_README.md
|_tsconfig.json
See GitHub repo for full code.
npm init
index.d.ts
filetsconfig.json
(see my question above for an example)index.js
containing only module.exports = {}
dependency
, so `npm i --save @yourscope/yourpkg