TL; DR 我想为已编译的PureScript模块创建TypeScript类型,并将它们分发到我的npm包中。我非常乐意手动维护这些类型,我只是无法弄清楚我需要放入tsconfig.json(上行和下行)以及package.json。
我有一个project,其核心功能是使用TypeScript CLI在PureScript中实现的,所有这些最终都是通过npm以JavaScript的形式发布的。我创建了一个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
)时,require
生成的tsc
次调用失败,因为它们不能使用在这种情况下,绝对路径 - require("People")
应为require("./People")
。在TypeScript中使import
语句相对取消了对打字的关联。
我很难实现这些目标:
require
调用PureScript模块在运行时解析。如果您有从TypeScript需要PureScript模块的经验,并通过npm分发所有这些,我真的很感激一些指导!
答案 0 :(得分:1)
您的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
答案 1 :(得分:1)
如果你肯定需要使用绝对路径来要求你的PureScript包(例如import * as People from 'People'
),我认为你需要破解节点模块分辨率算法(将你的PureScript输出放在{{1}中例如,node_modules
的子目录。
但是,如果这不重要,并且您对相对导入(例如./output
)没有问题,您可以执行以下操作:
使用PureScript模块的相对导入:
CLI / main.ts:
import * as People from './People'
将PureScript类型与TypeScript源并排放置:
import * as People from './People';
将PureScript类型更改为本地模块声明而不是全局:
CLI /人/ index.d.ts:
.
├── People
│ └── index.d.ts
├── main.ts
└── tsconfig.json
现在,要使其与Node模块解析一起使用,您需要将两个编译器的JS输出放在同一目录中。我们还希望TypeScript为我们的TS文件发出类型声明(在npm上发布时可以使用)。我们还删除了export interface Person {
name: string;
}
export const david: Person;
TS编译器选项(不再需要),并为Node类型添加了全局类型引用。
CLI / tsconfig.json:
paths
差不多完成了。现在,我们需要确保PureScript模块的类型定义最终在输出目录中可供使用。生成类型定义输出时,TypeScript不会在其输出中复制{
"compilerOptions": {
"target": "es5",
"lib": ["es2015"],
"moduleResolution": "node",
"baseUrl": ".",
"outDir": "./../output",
"types": [
"node"
],
"declaration": true
},
"include": [
"*.ts"
]
}
文件(因为这些文件不是由TS编译器创建的) - 我们需要对此进行补偿。我不知道这是否是实现这一目标的最好(甚至是好的?)方式,但以下方法对我有用:
的package.json:
.d.ts
最后但并非最不重要的是,我们需要指定JS的入口点和npm使用者的类型定义:
的package.json:
"scripts": {
"build": "pulp build && tsc -P cli/tsconfig.json && cd cli && rsync -am --include='*.d.ts' -f 'hide,! */' . ./../output"
},
...
我认为这并未涵盖创建混合语言和混合类型npm包的所有细节,但希望这可以作为一个起点。
答案 2 :(得分:0)
声明命名空间而不是模块使一切正常。例如,在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库也可以在没有其他配置的情况下看到这些类型。
但仍存在一些问题:
../
);但是,我的图书馆的消费者不必这样做,因为它经历了npm
并且神奇地使它发挥作用。Data.Maybe
这样的模块由Data_Maybe
等名称空间表示。