如何配置使用从 PureScript 编译的 JavaScript 模块的 TypeScript 项目?
How do I configure a TypeScript project that uses JavaScript modules compiled from PureScript?
TL;DR 我想为已编译的 PureScript 模块创建 TypeScript 类型,并将它们分发到我的 npm 包中。我非常乐意手动维护这些类型,我只是想不出我需要在 tsconfig.json(上游和下游)和 package.json.
中输入什么
我有一个布局更简单的 project where the core functionality is implemented in PureScript with a TypeScript CLI, and all of this is ultimately distributed as JavaScript via npm. I've created a similar project:
.
├── 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
中我定义了核心功能:
module People where
type Person = { name :: String }
david :: Person
david = { name: "David "}
在 types/People.d.ts
中,我为 PureScript 模块定义了 TypeScript 类型,因此我可以安全地从 TypeScript 使用它们:
declare module "People" {
export interface Person {
name: string;
}
export const david: Person;
}
最后,在 cli/main.ts
中,我想导入具有我定义的 TypeScript 类型的已编译 PureScript 模块:
import * as People from "People";
console.log(People.david);
我可以构建它,但是当我尝试 运行 最终 JavaScript (node cli/main.js
) 时,[=20= 生成的 require
调用] 失败,因为他们不使用绝对路径——在这种情况下,require("People")
应该是 require("./People")
。在 TypeScript 中使 import
语句相对取消类型关联。
我很难实现这些目标:
- 维护从 TypeScript 导入的所有 PureScript 模块的 TypeScript 类型。
- 确保 TypeScript 类型检查。
- 确保
require
对 PureScript 模块的调用在 运行 时解析。
- 使用 npm 包分发 TypeScript 类型,以便 TypeScript 消费者也可以使用这些类型。
如果您有从 TypeScript 获取 PureScript 模块并通过 npm 分发所有这些模块的经验,我将不胜感激一些指导!
您的 Purescript 模块名为 "Person",但应该是 "People"。我认为通过相对路径导入,您可能会部分到达那里,但我认为 d.ts 文件中没有相对路径输入之类的东西。
我检查了你的项目并重命名了模块,然后我将 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
如果您确实需要使用绝对路径来请求您的 PureScript 包(例如 import * as People from 'People'
),我认为您将需要破解节点模块解析算法(通过将您的 PureScript 输出放在 node_modules
./output
的子目录,例如)。
但如果这不是那么重要并且您可以接受相对导入(例如 import * as People from './People'
),您可以执行以下操作:
对 PureScript 模块使用相对导入:
cli/main.ts:
import * as People from './People';
将您的 PureScript 类型与您的 TypeScript 源并排放置:
.
├── People
│ └── index.d.ts
├── main.ts
└── tsconfig.json
将您的 PureScript 类型更改为本地模块声明而不是全局:
cli/People/index.d.ts:
export interface Person {
name: string;
}
export const david: Person;
现在,要使其与 Node 模块解析一起使用,您需要将两个编译器的 JS 输出放在同一目录中。我们还希望 TypeScript 为我们的 TS 文件发出类型声明(在 npm 上发布时可以使用)。我们还删除了 paths
TS 编译器选项(不再需要),并为 Node 类型添加了全局类型引用。
cli/tsconfig.json:
{
"compilerOptions": {
"target": "es5",
"lib": ["es2015"],
"moduleResolution": "node",
"baseUrl": ".",
"outDir": "./../output",
"types": [
"node"
],
"declaration": true
},
"include": [
"*.ts"
]
}
快完成了。现在,我们需要确保 PureScript 模块的类型定义最终出现在输出目录中以供使用。在生成类型定义输出时,TypeScript 不会在其输出中复制 .d.ts
文件(因为这些文件不是由 TS 编译器创建的)——我们需要对此进行补偿。我不知道这是否是实现此目标的最佳(甚至是好的?)方法,但以下方法对我有用:
package.json:
"scripts": {
"build": "pulp build && tsc -P cli/tsconfig.json && cd cli && rsync -am --include='*.d.ts' -f 'hide,! */' . ./../output"
},
...
最后但同样重要的是,我们需要指定 JS 的入口点和 npm 消费者的类型定义:
package.json:
"main": "output/main.js",
"typings": "output/main.d.ts",
"files": [
"output/"
]
...
我相信这并没有涵盖创建混合语言和混合类型 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 库也可以在没有额外配置的情况下看到这些类型。
但仍存在一些问题:
- 我仍然需要在编译的 TypeScript 中相对化 PureScript 模块导入(通过在 post-构建步骤中添加
../
);不过,我的图书馆的消费者不必这样做,因为它经过 npm
并且神奇地使它起作用。
- 我不知道如何导出带句点的命名空间,所以
Data.Maybe
等模块由 Data_Maybe
. 等命名空间表示
- 我不太了解名称空间与模块,因此可能还有其他注意事项。
TL;DR 我想为已编译的 PureScript 模块创建 TypeScript 类型,并将它们分发到我的 npm 包中。我非常乐意手动维护这些类型,我只是想不出我需要在 tsconfig.json(上游和下游)和 package.json.
中输入什么我有一个布局更简单的 project where the core functionality is implemented in PureScript with a TypeScript CLI, and all of this is ultimately distributed as JavaScript via npm. I've created a similar project:
.
├── 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
中我定义了核心功能:
module People where
type Person = { name :: String }
david :: Person
david = { name: "David "}
在 types/People.d.ts
中,我为 PureScript 模块定义了 TypeScript 类型,因此我可以安全地从 TypeScript 使用它们:
declare module "People" {
export interface Person {
name: string;
}
export const david: Person;
}
最后,在 cli/main.ts
中,我想导入具有我定义的 TypeScript 类型的已编译 PureScript 模块:
import * as People from "People";
console.log(People.david);
我可以构建它,但是当我尝试 运行 最终 JavaScript (node cli/main.js
) 时,[=20= 生成的 require
调用] 失败,因为他们不使用绝对路径——在这种情况下,require("People")
应该是 require("./People")
。在 TypeScript 中使 import
语句相对取消类型关联。
我很难实现这些目标:
- 维护从 TypeScript 导入的所有 PureScript 模块的 TypeScript 类型。
- 确保 TypeScript 类型检查。
- 确保
require
对 PureScript 模块的调用在 运行 时解析。 - 使用 npm 包分发 TypeScript 类型,以便 TypeScript 消费者也可以使用这些类型。
如果您有从 TypeScript 获取 PureScript 模块并通过 npm 分发所有这些模块的经验,我将不胜感激一些指导!
您的 Purescript 模块名为 "Person",但应该是 "People"。我认为通过相对路径导入,您可能会部分到达那里,但我认为 d.ts 文件中没有相对路径输入之类的东西。
我检查了你的项目并重命名了模块,然后我将 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
如果您确实需要使用绝对路径来请求您的 PureScript 包(例如 import * as People from 'People'
),我认为您将需要破解节点模块解析算法(通过将您的 PureScript 输出放在 node_modules
./output
的子目录,例如)。
但如果这不是那么重要并且您可以接受相对导入(例如 import * as People from './People'
),您可以执行以下操作:
对 PureScript 模块使用相对导入:
cli/main.ts:
import * as People from './People';
将您的 PureScript 类型与您的 TypeScript 源并排放置:
. ├── People │ └── index.d.ts ├── main.ts └── tsconfig.json
将您的 PureScript 类型更改为本地模块声明而不是全局:
cli/People/index.d.ts:
export interface Person { name: string; } export const david: Person;
现在,要使其与 Node 模块解析一起使用,您需要将两个编译器的 JS 输出放在同一目录中。我们还希望 TypeScript 为我们的 TS 文件发出类型声明(在 npm 上发布时可以使用)。我们还删除了
paths
TS 编译器选项(不再需要),并为 Node 类型添加了全局类型引用。cli/tsconfig.json:
{ "compilerOptions": { "target": "es5", "lib": ["es2015"], "moduleResolution": "node", "baseUrl": ".", "outDir": "./../output", "types": [ "node" ], "declaration": true }, "include": [ "*.ts" ] }
快完成了。现在,我们需要确保 PureScript 模块的类型定义最终出现在输出目录中以供使用。在生成类型定义输出时,TypeScript 不会在其输出中复制
.d.ts
文件(因为这些文件不是由 TS 编译器创建的)——我们需要对此进行补偿。我不知道这是否是实现此目标的最佳(甚至是好的?)方法,但以下方法对我有用:package.json:
"scripts": { "build": "pulp build && tsc -P cli/tsconfig.json && cd cli && rsync -am --include='*.d.ts' -f 'hide,! */' . ./../output" }, ...
最后但同样重要的是,我们需要指定 JS 的入口点和 npm 消费者的类型定义:
package.json:
"main": "output/main.js", "typings": "output/main.d.ts", "files": [ "output/" ] ...
我相信这并没有涵盖创建混合语言和混合类型 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 库也可以在没有额外配置的情况下看到这些类型。
但仍存在一些问题:
- 我仍然需要在编译的 TypeScript 中相对化 PureScript 模块导入(通过在 post-构建步骤中添加
../
);不过,我的图书馆的消费者不必这样做,因为它经过npm
并且神奇地使它起作用。 - 我不知道如何导出带句点的命名空间,所以
Data.Maybe
等模块由Data_Maybe
. 等命名空间表示
- 我不太了解名称空间与模块,因此可能还有其他注意事项。