当其类型定义未声明模块时如何在 TypeScript 中导入库?
How to import a library in TypeScript when its type definitions do not declare a module?
PeerJS 有类型定义,但它们不作为模块导出。它们是某些名称空间下的类型声明。
我得到:[ts] File 'c:/Users/Vincas/Desktop/language-exchange/node_modules/@types/peerjs/index.d.ts' is not a module.
尝试导入时:import Peer from 'peerjs'
这尝试从类型定义导入,而不是模块本身,我如何在此处从模块导入?
来自 DefinitelyTyped 的文件在这里:https://github.com/DefinitelyTyped/DefinitelyTyped/blob/354cec620daccfa0ad167ba046651fb5fef69e8a/types/peerjs/index.d.ts
我暂时是这样解决的:
const PeerJS: typeof Peer = require('peerjs')
const peerjs = new PeerJS({ key: '**********' })
但是这比 import * as Peer from 'peerjs
或类似的东西要差很多......没有办法避免定义全局函数和全局名称空间吗?这对我来说是一种糟糕的做法。
包 @types/peerjs
中的注册类型声明被指定为全局变量。也就是说,它们将命名空间 PeerJs
和变量 Peer
的存在声明为全局声明(也称为 "ambient")。
declare var Peer: {
// ...
}
这表明它们应该与可分发库文件 "dist/peer.js" 一起使用,而不是与模块一起使用。如果将此文件直接包含到页面中,编译器应该能够知道这些全局变量可用。
但实际上,您想改用该模块。不幸的是,相同的声明是不兼容的,必须重写以保持一致性。存储库上的一个旧问题在不久前未解决(#176), and you seem to have created #386。您在这里的直觉似乎是正确的:理想情况下,必须有人调整这些
声明。在这种情况下,由于从库中导出的对象是 class,我们应该遵循 class module 模式。我们可以这样代替 declare var Peer
:
export = Peer;
declare class Peer {
constructor(id: string, options?: Peer.PeerJSOption);
constructor(options: Peer.PeerJSOption);
// remaining methods here ...
};
declare namespace Peer {
export interface PeerJSOption {
// ...
}
// ...
}
额外的接口类型放在同名的命名空间中,以便正确导出所有内容。
我亲手接下了这个任务:一个新文件"index.d.ts" was added to the repository, along with a few extra package.json fields, in this branch。这使得声明仅通过安装主要依赖项就可以工作,不需要其他包(特别是,你不应该添加“@types/peerjs”)。
您甚至可以自己尝试一下:
package.json:
{
"name": "test-peerjs-ts",
"version": "0.1.0",
"main": "index.ts",
"dependencies": {
"peerjs": "git+https://github.com/Enet4/peerjs.git#typescript-types"
}
}
index.ts:
import Peer = require('peerjs');
let peer = new Peer("id");
let peer2 = new Peer("id", {});
type DataConn = Peer.DataConnection;
您可能只会看到来自 webrtc
类型的一堆 TypeScript 错误,这些错误显然包含最新 TypeScript 编译器中已经可用的定义。尽管如此,编译过程仍会成功并产生良好的 JavaScript 代码:
"use strict";
exports.__esModule = true;
var Peer = require("peerjs");
var peer = new Peer("id");
var peer2 = new Peer("id", {});
PeerJS 有类型定义,但它们不作为模块导出。它们是某些名称空间下的类型声明。
我得到:[ts] File 'c:/Users/Vincas/Desktop/language-exchange/node_modules/@types/peerjs/index.d.ts' is not a module.
尝试导入时:import Peer from 'peerjs'
这尝试从类型定义导入,而不是模块本身,我如何在此处从模块导入?
来自 DefinitelyTyped 的文件在这里:https://github.com/DefinitelyTyped/DefinitelyTyped/blob/354cec620daccfa0ad167ba046651fb5fef69e8a/types/peerjs/index.d.ts
我暂时是这样解决的:
const PeerJS: typeof Peer = require('peerjs')
const peerjs = new PeerJS({ key: '**********' })
但是这比 import * as Peer from 'peerjs
或类似的东西要差很多......没有办法避免定义全局函数和全局名称空间吗?这对我来说是一种糟糕的做法。
包 @types/peerjs
中的注册类型声明被指定为全局变量。也就是说,它们将命名空间 PeerJs
和变量 Peer
的存在声明为全局声明(也称为 "ambient")。
declare var Peer: {
// ...
}
这表明它们应该与可分发库文件 "dist/peer.js" 一起使用,而不是与模块一起使用。如果将此文件直接包含到页面中,编译器应该能够知道这些全局变量可用。
但实际上,您想改用该模块。不幸的是,相同的声明是不兼容的,必须重写以保持一致性。存储库上的一个旧问题在不久前未解决(#176), and you seem to have created #386。您在这里的直觉似乎是正确的:理想情况下,必须有人调整这些
声明。在这种情况下,由于从库中导出的对象是 class,我们应该遵循 class module 模式。我们可以这样代替 declare var Peer
:
export = Peer;
declare class Peer {
constructor(id: string, options?: Peer.PeerJSOption);
constructor(options: Peer.PeerJSOption);
// remaining methods here ...
};
declare namespace Peer {
export interface PeerJSOption {
// ...
}
// ...
}
额外的接口类型放在同名的命名空间中,以便正确导出所有内容。
我亲手接下了这个任务:一个新文件"index.d.ts" was added to the repository, along with a few extra package.json fields, in this branch。这使得声明仅通过安装主要依赖项就可以工作,不需要其他包(特别是,你不应该添加“@types/peerjs”)。
您甚至可以自己尝试一下:
package.json:
{
"name": "test-peerjs-ts",
"version": "0.1.0",
"main": "index.ts",
"dependencies": {
"peerjs": "git+https://github.com/Enet4/peerjs.git#typescript-types"
}
}
index.ts:
import Peer = require('peerjs');
let peer = new Peer("id");
let peer2 = new Peer("id", {});
type DataConn = Peer.DataConnection;
您可能只会看到来自 webrtc
类型的一堆 TypeScript 错误,这些错误显然包含最新 TypeScript 编译器中已经可用的定义。尽管如此,编译过程仍会成功并产生良好的 JavaScript 代码:
"use strict";
exports.__esModule = true;
var Peer = require("peerjs");
var peer = new Peer("id");
var peer2 = new Peer("id", {});