我和我的团队正在构建一个大型Web应用程序项目,该项目使用旧版本的流行JavaScript库(jQuery,Backbone,Underscore等)。我们目前正在尝试将TypeScript用于新解决方案以及替换现有JavaScript代码。因为我们的项目严重依赖于特定的JS库版本(例如jQuery 1.8.3),所以将这些库更新到最新版本比在最新版本中下载和删除稍微复杂一些。
这为我们在TypeScript的阶段性方面带来了问题;我们需要声明与最新的TypeScript标准兼容的过时的JS库版本。虽然DefinitelyTyped在提供声明文件方面做得很好 最新版本的特定于最新版本的TypeScript的JS库,它不提供与旧版兼容的JS库版本的声明文件最新的TypeScript标准。
似乎随着TypeScript的增长,所有旧的库声明(例如jQuery-1.8.3.d.ts)都处于灰尘中,因为这些库同时在不断发展。这是完全可以理解的,因为我不希望社区中有太多的努力来不断更新过时的库声明文件,以便它们与新的TypeScript标准兼容。
所以我的问题是:逐步使用依赖于旧JS库的新TypeScript代码的最佳方法是什么?
以下是我遇到的问题示例。我本质上是尝试使用TypeScript创建一个Backbone应用程序。
// Model.ts
import Backbone = require("backbone");
export class NewModel extends Backbone.Model {
...
}
因为我们正在使用带有require.js的AMD,我们得到如下内容:
// Model.js
...
define(['require', 'exports', 'backbone'], function(require, exports, Backbone) {
...
}
这很棒,它正是我们想要的输出,因为我们的require.config文件定义了我们需要的所有库:
// Config.ts
require.config({
baseUrl: './',
paths: {
'jquery': '../jquery-1.8.3.min',
'underscore': '../underscore/underscore.min',
'backbone': '../backbone/backbone',
'text': '../require/text'
},
shim: {
jquery: {
exports: '$'
},
underscore: {
exports: '_'
},
backbone: {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
}
}
});
然而,除非我们有 backbone.d.ts 描述 backbone.js 库的结构,否则 TypeScript不允许我们编译此代码并提供“骨干”模块的环境声明。
// backbone.d.ts
declare module Backbone {
...
export class Model extends ModelBase {
...
}
...
}
declare module 'backbone' {
export = Backbone;
}
// Model.ts
/// <reference path="path/to/backbone.d.ts" />
import Backbone = require("backbone")
export class NewModel extends Backbone.Model {
...
}
如果我们没有这些声明,那么我们没有Backbone模块的环境声明,因此在TypeScript中不能extend Backbone.Model
因为Backbone.Model
没有被定义为任何地方的类。这是一个夸张的示例问题,因为Model
类类型存在于所有'backbone.d.ts'文件中,无论版本如何。但是,如果没有准确的.d.ts文件来表示代码,JS库中会有更多细微的更改,这些更改可能会导致代码中断。
话虽这么说,你也可以使用更新版本的.d.ts文件(我们一直在做),只要你只使用实际存在关联JS库的部分,并且直接使用它们。否则,如果您使用的函数不存在或者函数传递的参数太多,那么实际调用该函数时只会看到该错误。 TypeScript不会接收它,因为它的信息仅基于.d.ts文件的信息。
我们可以使用 amd依赖性解决方法生成define
要求,例如:
// Model.ts
/// <amd-dependency path="backbone" />
var Backbone = require("backbone");
export class NewModel extends Backbone.Model {
...
}
哪会产生以下结果:
// Model.js
...
define(['require', 'exports', 'backbone'], function(require, exports) {
var Backbone = require('backbone');
...
}
这为我们提供了我们想要的Backbone
引用,但TypeScript仍然抱怨,因为它不知道我们声明的Backbone
变量。换句话说,它不提供.d.ts文件提供的结构。
尽管我们缺少.js文件与其相关的.d.ts文件之间的相关性,但我们的大多数TypeScript解决方案实际上仍然正常工作。我担心的是:将来这种差异是否会导致我们的申请出现重大问题?
目前,我能想到的最佳解决方案是:
我对这两种解决方案都不是特别激动,这就是为什么我要寻求另一种观点。如果此时还有人还在我身边(很抱歉拖了这个),那么我将非常感谢您提出的解决方案。
答案 0 :(得分:1)
这可能是一个粗略的问题,也是我们团队在TypeScript早期确实处理过的问题。我们最终开始使用明确键入的d.ts文件版本,并根据我们的需要进行调整。对于很多图书馆,我们发现打字不是使用新的语言功能,没有完成,或者在某些情况下是错误的。我们已尽力在有意义的地方做出贡献。
考虑到你正在考虑的两种方法,我会选择#1。当语言以超快的速度发展时,使用最新的TypeScript标准使d.ts文件保持最新是一个问题。虽然我仍然期望v2中有许多新功能,但v1相当稳定。在1.0的运行期间,语言的变化似乎是按月计算的。我现在不认为我们需要处理那种流失:)