Sunday, 27 January 2019

Create a TypeScript Library and use it from Node.js with ES6 and TypeScript

I want to create a TypeScript library as private npm package which can be used in Node.js (including 6.x) using ES6 with @types support and TypeScript.

The goal of the library is to extend the Request type from express and provide additional properties.

I created a new Node.js project and add this tsconfig.json:

{
  "compilerOptions": {
    "target": "es2015",
    "module": "commonjs",
    "sourceMap": true,
    "declaration": true,
    "outDir": "./dist",
    "strict": true,
    "types": ["mocha"]
  }
}

These are the relevant parts of the package.json:

{
  "name": "@myscope/my-lib",
  "main": "dist",
  "scripts": {
    "build": "rm -rf ./dist && ./node_modules/.bin/tsc",
    "test": "./node_modules/.bin/mocha test"
  },
  "private": true,
  "dependencies": {
    "joi": "11.4.0"
  },
  "devDependencies":  {
    "mocha": "^5.2.0",
    "express": "^4.16.4",
    "@types/express": "^4.16.1",
    "@types/joi": "^14.3.0",
    "@types/mocha": "^5.2.5",
    "typescript": "^3.2.4"
  }
}

My folder structure is this:

- dist
- src
  - http
  - security
- test

I created a new TypeScript file AuthenticatedRequest.ts in src/http:

import {Request} from "express";
import {UserReference} from "../security/UserReference";

export interface AuthenticatedRequest extends Request {
  user: UserReference
}

src/security contains a UserReference.ts:

import {Claim} from "./Claim";

export interface UserReference {
  claims: Claim[];
}

and a Claim.ts:

import {IClaim} from "./IClaim";

export class Claim implements IClaim {
  type: string;
  value: string;

  constructor(type: string, value: string) {
    this.type = type;
    this.value = value;
  }
}

IClaim.ts looks like this:

export interface IClaim {
  type: string,
  value: string
}

In test, I created AuthenticatedRequestTests.js (plain ES6, no TypeScript here to validation code completion and usage from ES6):

'use strict';

const assert = require('assert');
const Claim = require("../dist/security/Claim").Claim;

describe('req', () => {
  it('should ', done => {
    /** @type {AuthenticatedRequest} */
    const req = {};
    req.user = { claims: [new Claim('tenantId', '123')] };
    assert.equal(req.user.claims[ 0 ].type, 'tenantId');
    assert.equal(req.user.claims[ 0 ].value, '123');
    return done();
  });
});

Now I have sevaral questions:

  • Is this the expected TypeScript way to solve this?
  • Is it possible to just use require("../dist/security/Claim"); instead of require("../dist/security/Claim").Claim;?
  • Instead of using this jsdoc statement /** @type {AuthenticatedRequest} */ I would like to use /** @type {myLib.http.AuthenticatedRequest} */

I also created a local test project for integration and installed my library via npm link.

But instead of using

const Claim = require("@scope/my-lib/security/Claim").Claim; I have to use

const Claim = require("@scope/my-lib/dist/security/Claim").Claim;

How can I get rid of the dist folder name here?

Also, using the jsdoc comment for AuthenticatedRequest in the integration test project, I get the error that the type cannot be found:

enter image description here



from Create a TypeScript Library and use it from Node.js with ES6 and TypeScript

No comments:

Post a Comment