Background
我需要在Typescript中为现有的Javascript包创建一个适配器 . 这需要为现有包创建定义文件,并编写一些构建在这些接口之上的类 . 我需要在多个项目中重用生成的Typescript包 .
要创建这个包,我使用的是C#类库项目,但是没有定义C#类型,我只将它用于Typescript . Typescript编译器设置为输出单个 *.js
和 *.d.ts
文件 .
Problems
编译时,我的 *.ts
文件中定义的类可以在输出 *.d.ts
文件中找到,但 *.d.ts
文件中定义的任何接口都不会显示在输出中 . 我的类中的几个方法使用这些接口作为返回类型,因此当我尝试重用该包时,我得到了缺少接口的"Cannot find name 'xxx'."编译器错误 .
Some code:
这是正在消失的接口之一:
declare module IS_Interface
{
export interface Iterable<T>
{
hasMoreElements(): boolean;
nextElement(): T;
}
}
此项目中的所有Typescript文件都在 IS_Interface
模块中 . 声明文件以 declare module IS_Interface
开头,而* .ts文件以 module IS_Interface
开头 .
这是一个使用接口的类(它将显示在* .d.ts文件中):
module IS_Interface
{
export class IterableUtil
{
static ToArray<T>(iterable: Iterable<T>) : Array<T>
{
let result = new Array<T>();
while(iterable.hasMoreElements())
{
result.push(iterable.nextElement());
}
return result;
}
}
}
这是我的编译器设置:
{PropertyGroup Condition="'$(Configuration)' == 'Debug'"}
{TypeScriptNoImplicitAny}True{/TypeScriptNoImplicitAny}
{TypeScriptOutFile}bin/debug/IS_Adapter.js{/TypeScriptOutFile}
{TypeScriptGeneratesDeclarations}True{/TypeScriptGeneratesDeclarations}
{TypeScriptNoEmitOnError}True{/TypeScriptNoEmitOnError}
{/PropertyGroup}
所有的Typescript和声明文件都在我的项目文件中的“TypeScriptCompile Include”标记中 .
Questions
-
有没有办法从Typescript编译输出接口?
-
这不是打算使用Typescript接口吗?
-
有没有更简单的方法来创建不需要C#/ VB项目的Typescript包?
-
我不应该在这样的文件之间拆分模块吗?声明模块的哪些部分已声明且部件不是?
Update
@Martin - 我删除了模块声明 . 我对Typescript中的命名空间/模块解析感到困惑 . 模块主要是物理分组还是逻辑分组?它们都是两者兼而有之吗?我的大部分经验都是使用C#中的桌面/服务器编程,其中存在明确的程序集与命名空间区别 .
这是一些简化的代码:
注意,在我的输出* .d.ts文件中,我仍然有我的import语句,但它是一个损坏的引用 .
MyInterface.d.ts
:
export interface Iterable<T>
{
hasMoreElements(): boolean;
nextElement(): T;
}
MyConsumer.ts
:
import { Iterable } from "./MyInterface";
export class Thing
{
Name: string;
Thing: Iterable<number>;
}
我仍然在生成的 .d.ts
文件中没有接口 .
Workaround
这是我可怕的解决方法 . 它由预构建命令和作为构建后命令运行的 exe
组成 . 它不漂亮,但它似乎到目前为止工作 .
预建:(只有这样我们才能在重建时将以前的版本与自身合并)
DEL "$(TargetDir)*.d.ts"
Postbuild:
"$(SolutionDir)\TypeScriptDefMerge\bin\Debug\TypeScriptDefMerge.exe" "$(ProjectDir) " "MyTargetFile.d.ts"
可执行程序:
using System;
using System.IO;
using System.Linq;
namespace TypeScriptDefMerge {
class Program {
// 1st argument must be the project directory path.
// 2nd argument must be the target file name.
static void Main(string[] args) {
Console.Write(args.Length);
Console.Read();
if (args == null) throw new ArgumentNullException("args");
if (args.Length != 2) throw new ArgumentException("Must have exactly 2 arugments.");
var projectDir = args[0];
var outputName = args[1];
//Source definition files must be in this subdirectory
//I use "\Internal" for my scripts and "\External" for 3rd-party scripts
var sourceDir = projectDir + "\\Scripts\\Internal";
//Output must be in this subdirectory
var outputDir = projectDir + "\\bin\\Debug";
var temp1 = outputDir + "\\TEMP1.d.ts";
var temp2 = outputDir + "\\TEMP2.d.ts";
File.Delete(temp1);
File.Delete(temp2);
//Create temp file holding contents of each source file
CreateMergedFile(temp1, GetDefinitionFiles(sourceDir));
//Create temp file holding the contents of the 1st temp file, and the normal output file
CreateMergedFile(temp2, GetDefinitionFiles(outputDir));
//Delete temporary files
foreach (var f in GetDefinitionFiles(outputDir).Where(x => x != temp2)) {
File.Delete(f);
}
//Rename final file
File.Move(temp2, outputDir + "\\" + outputName);
}
//Get all definition files in the given directory
static string[] GetDefinitionFiles(string directory) {
return Directory.EnumerateFiles(directory)
.Where(x => x.EndsWith(".d.ts"))
.ToArray();
}
//Concatenate all the given files to a new file at the given path.
static void CreateMergedFile(string outputPath, string[] sourcePaths) {
using (var temp = File.CreateText(outputPath)) {
foreach (var f in sourcePaths) {
temp.Write(File.ReadAllText(f));
temp.WriteLine();
}
}
}
}
}
说真的,必须有比这更好的东西 . 难道人们不希望重用接口吗?如果你能想出任何不那么笨重的东西,请告诉我 .
另请注意,这不承认“从项目中排除”并且完全基于目录 .