如何configuration使用从PureScript编译的JavaScript模块的TypeScript项目?
TL; DR我想为编译的PureScript模块创buildTypeScripttypes,并将它们分发到我的npm包中。 我非常乐意手动维护这些types,我只是无法弄清楚我需要在tsconfig.json(up和downstream)和package.json中放置什么。
我有一个使用TypeScript CLI在PureScript中实现核心function的项目 ,所有这些最终都是通过npm作为JavaScript分发的。 我用一个更简单的布局创build了一个类似的项目 :
. ├── cli # TypeScript CLI project │ ├── main.ts │ └── tsconfig.json │ ├── output # Compiled PureScript modules │ └── People │ ├── externs.json │ └── index.js │ ├── src # PureScript source │ └── People.purs │ └── types # TypeScript types for PureScript modules └── People.d.ts
在src/People.purs
我定义了核心function:
module People where type Person = { name :: String } david :: Person david = { name: "David "}
在types/People.d.ts
我为PureScript模块定义了TypeScripttypes,所以我可以从TypeScript中安全地使用它们:
declare module "People" { export interface Person { name: string; } export const david: Person; }
最后,在cli/main.ts
,我想用我定义的TypeScripttypes导入已编译的PureScript模块:
import * as People from "People"; console.log(People.david);
我可以得到这个构build,但是当我尝试运行最终的JavaScript( node cli/main.js
)时,由tsc
生成的require
调用失败,因为它们不使用绝对path – require("People")
应该是在这种情况下require("./People")
。 在TypeScript中进行import
语句可以解除types的关联。
我很难达到这些目标:
- 对于从TypeScript导入的所有PureScript模块,保留TypeScripttypes。
- 确保TypeScript typechecks。
- 确保在运行时
require
调用PureScript模块。 - 使用npm包分发TypeScripttypes,以便TypeScript使用者也可以使用这些types。
如果您有经验需要TypeScript的PureScript模块,并通过npm分发所有这些,我真的很感激一些指导!
你的Purescript模块被称为“人”,但应该是“人”。 我认为用相对path导入你可能会部分地在那里,但我不认为有这样的事情在d.ts文件中的相对pathinput。
我检查了你的项目, allowJs
命名模块,然后我设置allowJs
为true,并键入模块内联:
import * as OutputPeople from "../output/People"; type Person = { name: string; }; type PeopleModule = { david: Person } const People: PeopleModule = OutputPeople console.log(People.david);
我把我的修改在这里的分支: https : //github.com/justinwoo/ps-js-ts-interop/commit/fc7c1239f9d1bac1cf2bea35f7a07d30c46a5f64
如果您确实需要使用绝对path来请求您的PureScript包(例如import * as People from 'People'
),那么我认为您需要绕过节点模块parsingalgorithm(将PureScript输出放置在node_modules
子目录中./output
,例如)。
但是,如果这不是那么重要,你可以用相对导入(比如import * as People from './People'
),你可以执行以下操作:
-
对于PureScript模块使用相对导入:
CLI / main.ts:
import * as People from './People';
-
将您的PureScripttypes与您的TypeScript源码放在一起:
. ├── People │ └── index.d.ts ├── main.ts └── tsconfig.json
-
将您的PureScripttypes更改为本地模块声明而不是全局:
CLI /人/ index.d.ts:
export interface Person { name: string; } export const david: Person;
-
现在,要使它与Node模块parsing一起工作,您需要将来自两个编译器的JS输出放在同一个目录中。 我们还希望TypeScript为我们的TS文件发布types声明(在npm上发布时可以使用)。 我们还删除了
paths
TS编译器选项(不再需要),并为节点types添加全局types引用。CLI / tsconfig.json:
{ "compilerOptions": { "target": "es5", "lib": ["es2015"], "moduleResolution": "node", "baseUrl": ".", "outDir": "./../output", "types": [ "node" ], "declaration": true }, "include": [ "*.ts" ] }
-
几乎完成。 现在,我们需要确保PureScript模块的types定义最终在输出目录中可供使用。 当生成types定义输出时,TypeScript将不会在其输出中复制
.d.ts
文件(因为这些文件不是由TS编译器创build的) – 我们需要对其进行补偿。 我不知道这是否是最好的(甚至是一个好的方法)来实现这一点,但下面的工作对我来说:的package.json:
"scripts": { "build": "pulp build && tsc -P cli/tsconfig.json && cd cli && rsync -am --include='*.d.ts' -f 'hide,! */' . ./../output" }, ...
-
最后但并非最不重要的,我们需要指定JS的入口点和npm使用者的types定义:
的package.json:
"main": "output/main.js", "typings": "output/main.d.ts", "files": [ "output/" ] ...
我相信这并不包括创build一个混合语言和混合types的npm包的所有细节,但希望这可以作为一个起点。
声明命名空间而不是模块使一切正常。 例如,在types/People.d.ts
:
declare namespace People { export interface Person { name: string; } export const david: Person; } export = People; export as namespace People;
在编译PureScript模块之后,在编译TypeScript之前,我将cp types/People.d.ts output/People/index.d.ts
。 这使得TypeScript代码对于相同的绝对导入(例如import * as People from "People";
很满意,并且TypeScript库也可以在没有额外configuration的情况下看到这些types。
但仍有一些问题:
- 我仍然必须在已编译的TypeScript中使用PureScript模块导入(在生成后步骤中预先加上
../
)。 但是,我的图书馆消费者并不需要这样做,因为它通过npm
,神奇地使它工作。 - 我无法弄清楚如何导出带句点的命名空间,所以像
Data.Maybe
这样的模块就像Data.Maybe
这样的命名空间。 - 我不太了解名称空间与模块,所以可能还有其他的注意事项。