[英]How to merge typescript module defintions
I have a JavaScript module that has a custom .d.ts
file.我有一个带有自定义
.d.ts
文件的 JavaScript 模块。 Lets call the module Foobar
:让我们调用模块
Foobar
:
foobar.js foobar.js
function foobar (opts) {
this.register = plugin => {
plugin(this)
}
this.decorate = (prop, value) => {
this[prop] = value
}
return this
}
export default foobar
foobar.d.ts foobar.d.ts
export interface FoobarPlugin {
(inst: FoobarInst): void
}
export interface FoobarInst {
register(plugin: FoobarPlugin): void
decorate(prop: string, value: any): void
}
export default function foobar (): FoobarInst
I also have plugin:我也有插件:
fuzzbuzz.js fuzzbuzz.js
function fuzzbuzz (inst) {
inst.decorate('fuzzbuzz', true)
}
export default fuzzbuzz
fuzzbuzz.d.ts fuzzbuzz.d.ts
import { FoobarInst } from '../foobar/foobar'
export default function fuzzbuzz (inst: FoobarInst): void
I load the plugin into my module:我将插件加载到我的模块中:
index.ts索引.ts
import foobar from './foobar/foobar'
import fuzzbuzz from './fuzzbuzz/fuzzbuzz'
const inst = foobar()
inst.register(fuzzbuzz)
inst.fuzzbuzz // -> true
What do I need to add to fuzzbuzz.d.ts in order to update the FoobarInst type definition?我需要向 fuzzbuzz.d.ts 添加什么才能更新 FoobarInst 类型定义?
I have tried variations of:我尝试了以下变体:
declare module foobar {
interface FoobarInst {
fuzzbuzz: boolean
}
}
My tsconfig.json
looks like:我的
tsconfig.json
看起来像:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"strict": true,
"esModuleInterop": true
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
}
}
Thank you for any help you can provide!感谢您提供任何帮助!
What you are looking for is module augmentation .您正在寻找的是模块扩充。 I think, an
import
statement is missing in fuzzbuzz.d.ts
to let TS recognize, that the given declarations extend/augment an already existing "foobar"
module:我认为,
fuzzbuzz.d.ts
缺少一个import
语句让 TS 认识到,给定的声明扩展/增强了一个已经存在的"foobar"
模块:
fuzzbuzz.d.ts: fuzzbuzz.d.ts:
import { FoobarOpts } from "foobar"; // can be any import, preferrably one of "foobar"
declare module "foobar" {
// your module extensions
}
The plugin extensions have to be statically analyzable by the compiler.插件扩展必须可由编译器静态分析。 That means, you cannot make TS augment the
foobar
as soon as foobar.register(fuzzbuzz)
is called or via dynamic import.这意味着,一旦
foobar.register(fuzzbuzz)
被调用或通过动态导入,你就不能让 TS 增加foobar
。
Instead, the module is seen as augmented, when fuzzbuzz.d.ts
is included as input for the compilation either by module resolution or automatic inclusion of .ts
/ .d.ts
files in the project directory.相反,当
fuzzbuzz.d.ts
通过模块解析或自动包含.ts
/ .d.ts
文件在项目目录中作为编译输入包含时,模块被视为增强的。 Therefore, it makes sense to place the type augmentation and foobar.register(fuzzbuzz)
in one module, so that types and run-time code are in sync.因此,将类型增强和
foobar.register(fuzzbuzz)
放在一个模块中是foobar.register(fuzzbuzz)
,以便类型和运行时代码同步。 A minimal example:一个最小的例子:
foobar.ts: foobar.ts:
declare module "foobar" {
// Plugin gets the options and possibly some internal "foobar" state
type Plugin = (opts: FoobarOpts, state: {}) => void;
interface FoobarOpts {
foo: string;
bar: number;
}
export default function foobar(opts: FoobarOpts): void;
function register(plugin: Plugin): void;
}
my-plugin.ts:我的插件.ts:
import { register, Plugin, FoobarOpts } from "foobar";
const fuzzBuzzPlugin: Plugin = (opt: FoobarOpts, state) => {
opt.fuzzbuzz; // fuzzbuzz available now.
};
// set type augmentation...
declare module "foobar" {
export interface FoobarOpts {
fuzzbuzz: boolean;
}
}
// ... and run-time plugin extension in one module, so they go hand in hand
register(fuzzBuzzPlugin);
client.ts:客户端.ts:
import foobar from "foobar";
foobar({ bar: 42, foo: "buh", fuzzbuzz: true }); // works with fuzzbuzz
Thank you @ford04 for a great reply.谢谢@ford04 的精彩回复。 With the links provided I was able to solve my specific goal.
通过提供的链接,我能够解决我的特定目标。
The important detail with my scenario is both foobar
and fuzzbuzz
are authored in JavaScript, and have custom .d.ts
definition files.我的场景的重要细节是
foobar
和fuzzbuzz
都是用 JavaScript 编写的,并且具有自定义的.d.ts
定义文件。 Additionally, the foobar
module does not use declare module
but instead an export default
on the singular function the module natively exports.此外,
foobar
模块不使用declare module
,而是使用模块本机导出的单一函数的export default
。
The solution code is:解决代码是:
| - node_modules \
| - foobar \
| - foobar.js
| - foobar.d.ts
| - package.json
| - fuzzbuzz \
| - fuzzbuzz.js
| - fuzzbuzz.d.ts
| - package.json
| - index.ts
| - package.json
foobar.js foobar.js
function foobar (opts) {
this.register = plugin => {
plugin(this)
}
this.decorate = (prop, value) => {
this[prop] = value
}
return this
}
export default foobar
foobar.d.ts foobar.d.ts
export interface FoobarPlugin {
(inst: FoobarInst): void
}
export interface FoobarInst {
register(plugin: FoobarPlugin): void
decorate(prop: string, value: any): void
}
export default function foobar (): FoobarInst
foobar/package.json foobar/package.json
{
"main": "foobar.js",
"types": "foobar.d.ts",
}
fuzzbuzz.js fuzzbuzz.js
function fuzzbuzz (inst) {
inst.decorate('fuzzbuzz', true)
}
export default fuzzbuzz
fuzzbuzz.d.ts fuzzbuzz.d.ts
import { FoobarInst } from 'foobar'
declare module "foobar" {
interface FoobarInst {
fuzzbuzz: boolean
}
}
export default function fuzzbuzz (inst: FoobarInst): void
fuzzbuzz/package.json fuzzbuzz/package.json
{
"main": "fuzzbuzz.js",
"types": "fuzzbuzz.d.ts",
}
index.ts索引.ts
import foobar from 'foobar'
import fuzzbuzz from 'fuzzbuzz'
const inst = foobar()
inst.register(fuzzbuzz)
inst.fuzzbuzz // -> true and no type error!
Important Details重要细节
Specify the type definitions in package.json
在
package.json
指定类型定义
declare module '<library>'
will merge declarations even if the <library>
does not use declare module
explicitly (I believe it is still considered a module by TypeScript regardless).即使
<library>
没有明确使用declare module
declare module '<library>'
也会合并声明(我相信无论如何它仍然被 TypeScript 视为一个模块)。
This prototype augmentation / decoration is error prone in the sense that just by importing fuzzbuzz
into index.ts
will cause the types to merge...even if you do not call .register(fuzzbuzz)
.这种原型增强/装饰很容易出错,因为仅通过将
fuzzbuzz
导入index.ts
将导致类型合并……即使您不调用.register(fuzzbuzz)
。 @ford04 answer provides more context on this Therefore, it makes sense to place the type augmentation and foobar.register(fuzzbuzz) in one module, so that types and run-time code are in sync. @ford04 回答提供了更多关于此的上下文因此,将类型增强和 foobar.register(fuzzbuzz) 放在一个模块中是有意义的,以便类型和运行时代码同步。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.