创建一个 TypeScript 库并使用 Node.js 中的 ES6 和 TypeScript
Create a TypeScript Library and use it from Node.js with ES6 and TypeScript
我想创建一个 TypeScript 库作为私有 npm 包,它可以在 Node.js 中使用(包括 6.x)
使用带有 @types
支持的 ES6 和 TypeScript。
库的目标是从 express
扩展 Request
类型并提供额外的属性。
我创建了一个新的 Node.js 项目并添加了这个 tsconfig.json
:
{
"compilerOptions": {
"target": "es2015",
"module": "commonjs",
"sourceMap": true,
"declaration": true,
"outDir": "./dist",
"strict": true,
"types": ["mocha"]
}
}
这些是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"
}
}
我的文件夹结构是这样的:
- dist
- src
- http
- security
- test
我在 src/http
中创建了一个新的 TypeScript 文件 AuthenticatedRequest.ts
:
import {Request} from "express";
import {UserReference} from "../security/UserReference";
export interface AuthenticatedRequest extends Request {
user: UserReference
}
src/security
包含一个 UserReference.ts
:
import {Claim} from "./Claim";
export interface UserReference {
claims: Claim[];
}
和一个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
看起来像这样:
export interface IClaim {
type: string,
value: string
}
在 test
中,我创建了 AuthenticatedRequestTests.js
(纯 ES6,这里没有 TypeScript 来验证代码完成和 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();
});
});
现在我有几个问题:
- 这是解决此问题的预期 TypeScript 方法吗?
- 是否可以只使用
require("../dist/security/Claim");
而不是 require("../dist/security/Claim").Claim;
?
- 而不是使用此
jsdoc
语句 /** @type {AuthenticatedRequest} */
我想使用 /** @type {myLib.http.AuthenticatedRequest} */
我还创建了一个用于集成的本地测试项目,并通过 npm link
安装了我的库。
但不是使用
const Claim = require("@scope/my-lib/security/Claim").Claim;
我必须用
const Claim = require("@scope/my-lib/dist/security/Claim").Claim;
如何去掉此处的 dist
文件夹名称?
另外,在集成测试项目中对AuthenticatedRequest
使用jsdoc
注释,出现找不到类型的错误:
package.json
应该有一个名为 types
(或 typings
)的字段告诉您的库使用者您的项目的类型定义在哪里。如果它们是由 TypeScript 生成并保存到 dist/index.d.ts
,那么这就是应该使用的路径。
"types": "./dist/index.d.ts"
应该有一个名为 files
的字段,其中包含将交付给最终用户的 files/directories 数组。
运行 测试
Is this the expected TypeScript way to solve this?
如果您使用 TypeScript 开发库,则没有理由不使用 TypeScript 进行测试。那里有兼容 TypeScript 的测试运行器(ts-jest
曾经很流行,现在 Jest 能够开箱即用地理解 TypeScript)。
Is it possible to just use require("../dist/security/Claim");
instead of require("../dist/security/Claim").Claim;
?
使用 TypeScript,可以使用几种语法。您可以使用默认导出导出 Claim
并执行:
import Claim from "../dist/security/Claim";
或:
const Claim = require("../dist/security/Claim");
Instead of using this jsdoc statement /** @type {AuthenticatedRequest} */
I would like to use /** @type {myLib.http.AuthenticatedRequest} */
.
您将需要一个导入类型。他们看起来像这样:
/**
* @type {import('path/to/AuthenticatedRequest')}
*/
const req {}
路径可以是相对路径也可以是绝对路径。如果你想把本地代码库当作是从 npm 安装的,你可以在你的测试目录中创建另一个 package.json
文件并使用相对路径来解析你的库模块。
"dependencies": {
"my-library": "../path/to/the/root"
}
Also, using the jsdoc comment for AuthenticatedRequest
in the integration test project, I get the error that the type cannot be found:
导入类型也解决了这个问题。除非一个类型不在全局范围内,否则您需要先导入它才能使用它。请改用 import('path/to/AuthenticatedRequest')
。
发生了一些事情。如果您可以创建一个 public 存储库来展示您的问题,我相信我们可以更轻松地帮助您解决这些问题。
对于你问题的一部分,我有一个备选答案。你问
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?
正如 Karol 指出的那样,您可以在 package.json
中使用 files
,这样当您的库发布时,您可以将 dist
目录作为包根目录发送(plus package.json
, README, etc).这是一个很好的、既定的模式,但有一些缺点:从 github:
而不是 NPM 安装包将不起作用,npm link
也不会用于本地开发。
从最近的 Node 版本开始,您可以使用 the exports
property 代替:
{
"exports": {
"./": "./dist/"
}
}
现在,require("my_lib/security/Claim")
解析为 node_modules/my_lib/dist/security/Claim
。如果 Typescript 自动处理这个会很棒,但据我所知,您还必须在 tsconfig.json
中指定 baseUrl
和 paths
,至少现在是这样。
我想创建一个 TypeScript 库作为私有 npm 包,它可以在 Node.js 中使用(包括 6.x)
使用带有 @types
支持的 ES6 和 TypeScript。
库的目标是从 express
扩展 Request
类型并提供额外的属性。
我创建了一个新的 Node.js 项目并添加了这个 tsconfig.json
:
{
"compilerOptions": {
"target": "es2015",
"module": "commonjs",
"sourceMap": true,
"declaration": true,
"outDir": "./dist",
"strict": true,
"types": ["mocha"]
}
}
这些是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"
}
}
我的文件夹结构是这样的:
- dist
- src
- http
- security
- test
我在 src/http
中创建了一个新的 TypeScript 文件 AuthenticatedRequest.ts
:
import {Request} from "express";
import {UserReference} from "../security/UserReference";
export interface AuthenticatedRequest extends Request {
user: UserReference
}
src/security
包含一个 UserReference.ts
:
import {Claim} from "./Claim";
export interface UserReference {
claims: Claim[];
}
和一个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
看起来像这样:
export interface IClaim {
type: string,
value: string
}
在 test
中,我创建了 AuthenticatedRequestTests.js
(纯 ES6,这里没有 TypeScript 来验证代码完成和 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();
});
});
现在我有几个问题:
- 这是解决此问题的预期 TypeScript 方法吗?
- 是否可以只使用
require("../dist/security/Claim");
而不是require("../dist/security/Claim").Claim;
? - 而不是使用此
jsdoc
语句/** @type {AuthenticatedRequest} */
我想使用/** @type {myLib.http.AuthenticatedRequest} */
我还创建了一个用于集成的本地测试项目,并通过 npm link
安装了我的库。
但不是使用
const Claim = require("@scope/my-lib/security/Claim").Claim;
我必须用
const Claim = require("@scope/my-lib/dist/security/Claim").Claim;
如何去掉此处的 dist
文件夹名称?
另外,在集成测试项目中对AuthenticatedRequest
使用jsdoc
注释,出现找不到类型的错误:
package.json
应该有一个名为
types
(或typings
)的字段告诉您的库使用者您的项目的类型定义在哪里。如果它们是由 TypeScript 生成并保存到dist/index.d.ts
,那么这就是应该使用的路径。"types": "./dist/index.d.ts"
应该有一个名为
files
的字段,其中包含将交付给最终用户的 files/directories 数组。
运行 测试
Is this the expected TypeScript way to solve this?
如果您使用 TypeScript 开发库,则没有理由不使用 TypeScript 进行测试。那里有兼容 TypeScript 的测试运行器(
ts-jest
曾经很流行,现在 Jest 能够开箱即用地理解 TypeScript)。Is it possible to just use
require("../dist/security/Claim");
instead ofrequire("../dist/security/Claim").Claim;
?使用 TypeScript,可以使用几种语法。您可以使用默认导出导出
Claim
并执行:import Claim from "../dist/security/Claim";
或:
const Claim = require("../dist/security/Claim");
Instead of using this jsdoc statement
/** @type {AuthenticatedRequest} */
I would like to use/** @type {myLib.http.AuthenticatedRequest} */
.您将需要一个导入类型。他们看起来像这样:
/** * @type {import('path/to/AuthenticatedRequest')} */ const req {}
路径可以是相对路径也可以是绝对路径。如果你想把本地代码库当作是从 npm 安装的,你可以在你的测试目录中创建另一个
package.json
文件并使用相对路径来解析你的库模块。"dependencies": { "my-library": "../path/to/the/root" }
Also, using the jsdoc comment for
AuthenticatedRequest
in the integration test project, I get the error that the type cannot be found:导入类型也解决了这个问题。除非一个类型不在全局范围内,否则您需要先导入它才能使用它。请改用
import('path/to/AuthenticatedRequest')
。
发生了一些事情。如果您可以创建一个 public 存储库来展示您的问题,我相信我们可以更轻松地帮助您解决这些问题。
对于你问题的一部分,我有一个备选答案。你问
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?
正如 Karol 指出的那样,您可以在 package.json
中使用 files
,这样当您的库发布时,您可以将 dist
目录作为包根目录发送(plus package.json
, README, etc).这是一个很好的、既定的模式,但有一些缺点:从 github:
而不是 NPM 安装包将不起作用,npm link
也不会用于本地开发。
从最近的 Node 版本开始,您可以使用 the exports
property 代替:
{
"exports": {
"./": "./dist/"
}
}
现在,require("my_lib/security/Claim")
解析为 node_modules/my_lib/dist/security/Claim
。如果 Typescript 自动处理这个会很棒,但据我所知,您还必须在 tsconfig.json
中指定 baseUrl
和 paths
,至少现在是这样。