在javascript中你可以这样做:
function Test() {
this.id = 1;
};
Test.prototype.customize = function(key, callback) {
this[key] = callback;
};
var callback = function() { alert(this.id); };
var x = new Test();
x.customize('testing', callback);
x.testing();
你能用打字稿做类似的事吗?
特别是我有兴趣参加一个类:
class Socket {
...
}
class Sockets {
public addChannel(name:string):void {
this[name] = new Socket();
}
...
}
data = new Sockets();
data.addChannel('video');
data.addChannel('audio');
...
var audio = data.audio.read();
var video = data.video.read();
etc.
编译器抱怨“套接字”上没有“音频”或“视频”成员,并且不会编译。有没有办法解决这个问题,而无需在容器类上手动定义属性?
我知道它有点像静态类型规则的一步,但我发现它有时候对API的好处很有用。
编辑:请参阅我在下面发布的示例答案;类似的东西。我仍然接受任何聪明的答案,让我以某种方式设法编译一些对基础对象本身有用的东西。
答案 0 :(得分:12)
更新:听起来你在运行时真正的动态行为...即你不知道它将是video
,audio
或其他一些值。在这种情况下,如果您有来自某个源的动态频道名称,则必须使用[]
语法 - 但仍有一些
var channel = 'video;'
var data = new Sockets();
data.addChannel(channel);
// Totally dynamic / unchecked
var media = data[channel].read();
// Or
interface IChannel {
read(): { /* You could type this */ };
}
// Dynamic call, but read method and media variable typed and checked
var media = (<IChannel>data[channel]).read();
以前的答案......对于阅读这个问题的人来说很有用,他们不是在完全动态行为之后(但对道格来说很无用,抱歉!)
如果要扩展现有类,可以使用继承:
class ClassOne {
addOne(input: number) {
return input + 1;
}
}
// ...
class ClassTwo extends ClassOne {
addTwo(input: number) {
return input + 2;
}
}
var classTwo = new ClassTwo();
var result = classTwo.addTwo(3); // 5
如果你想真正动态地做这件事,例如你只想向实例添加一些内容,你也可以这样做 - 但是继承可以为你提供更多的钱。
class ClassOne {
addOne(input: number) {
return input + 1;
}
}
// ...
var classOne = new ClassOne();
classOne['addTwo'] = function (input: number) {
return input + 2;
};
var result = (<any>classOne).addTwo(3); // 5
//or (nasty 'repeat the magic string version')
result = classOne['addTwo'](3);
如果您在动态路由上设置了死区,则TypeScript中的常见模式是使用接口而不是类来表示结构。接口(以及模块和枚举)是开放的 - 因此它们可以扩展到多个块。您需要确保您的界面和实现得到同等扩展。这是用于扩展内置对象的技术。
// NodeList is already declared in lib.d.ts - we are extending it
interface NodeList {
sayNodeList(): void;
}
NodeList.prototype.sayNodeList = function () {
alert('I say node, you say list... NODE');
}
这为您提供了完整的自动完成和类型检查。
答案 1 :(得分:3)
您没有在示例中扩展类型 ...您只是动态地向对象添加属性。在TypeScript中,您无法动态地将属性添加到包含具有不同类型的属性的对象 - 除非您转换为any
(在我看来,应该避免使用)。
我建议在Sockets中添加一个属性,该属性限制为具有Socket
类型的属性,如下所示:
class Sockets {
channels: { [index: string]: Socket; } = {};
public addChannel(name:string):void {
this.channels[name] = new Socket();
}
}
var data = new Sockets();
data.addChannel('audio');
// audio will be the return type of read... so you don't lose type
var audio = data.channels['audio'].read();
通过这样做,您不必记住将对象强制转换为Socket
,并获得类型安全的所有乐趣。
答案 2 :(得分:1)
现在还不可能,但是现在正在进行一场持续且积极的讨论,在这些活动中,我们正在进行各种活动。
答案 3 :(得分:1)
// Basic type
type a = {
prop1: string
}
// Extended type
type b = a & {
prop2: number
}
// Demo instance
let myExtendedObject: b = {
prop1: 'text',
prop2: 99
}
答案 4 :(得分:0)
class Blah {
public channels:any = {};
public addChan(name:string):void {
this.channels[name] = new Channel();
}
}
var b = new Blah();
b.channel('hello');
b.channels.hello.read(1024, () => { ... });
默认情况下,“任何”时间的任何属性似乎也都是“任何”,并且如果没有强制转换,你不会在其中获得任何类型的安全性,但是如果你正在编写一个要在javascript中使用的打字稿库,这不是什么大不了的事。