【发布时间】:2021-02-11 23:04:13
【问题描述】:
项目结构说明
在名为mylib 的库中,我有一个手写的 API 声明文件 src/mylib.d.ts。手动编写它是有原因的:我想先设计一个 API,然后再实现它(而带有 --declaration 标志的 tsc 则相反 - 它从实现中生成一个 API 声明)。
src/mylib.d.ts的内容:
declare module "mylib" {
export interface Animal {
walk(): void;
}
export class Dog implements Animal {
constructor(name: string);
walk(run?: string): void;
bow(): void;
}
export function randomAnimal(): Animal;
export const version: string;
}
在包构建阶段,此文件可以复制为 dist/index.d.ts(由 package.json 中的 "types":"./dist/index.d.ts" 设置引用)或仅发布为 @types/mylib .
API实现代码位于src/api.ts:
import * as mylib from "mylib";
import { Cat, Mouse } from "./other-animals"
import { logger } from "./logger"
export class Dog implements mylib.Dog {
walk(run?: string): void {
logger(`I'm a dog and i ${run ? "run" : "walk"}.`);
}
bow(): void {
logger("bow-wow!");
}
}
export function randomAnimal(name?: string): mylib.Animal {
if (name) console.log("you passed name param. It wasn't documented but ok");
// logger(mylib.version); //if you decomment this line, the bundler will
// fail with error because "mylib" module doesnt really exists yet. It's OK because in
// library source code i reference `mylib.d.ts` only for type imports.
// Or we can just add "paths": { "baseUrl": "src", "mylib": ["./api.ts"] } to tsconfig.json so
// bundler will use it to resolve module.
return new Dog();
}
export const version = "1.0.0";
export const undocumentedVar = 123;
此文件是捆绑程序的入口点:esbuild src/api.ts --bundle --outfile=dist/index.js --format=esm。
因此,npm tarball 中会有 3 个文件:dist/index.js、dist/index.d.ts 和 package.json强>
问题
问题在于 mylib.d.ts 中声明的所有内容都独立于它的实现。例如,我们可以从 api.ts 中删除 randomAnimal 并且项目仍然可以编译而没有任何错误。
我目前对这个问题的解决方案是下一个:我将这行添加到 src/api 的末尾:
import * as api from "./api";
const test: typeof import("mylib") = api;
然后我使用 --noEmit 和 "files": ["src/api.ts"] 选项运行 tsc。
如果声明和实现之间存在不一致,我会看到一个错误。
这是一个非常有效的解决方案,但问题是:有什么方法可以做得更好吗?例如,不创建额外的未导出常量?
【问题讨论】:
标签: typescript api-design