Typescript 在运行时使用派生类扩展基实例
我有以下类层次结构:Typescript 在运行时使用派生类扩展基实例,typescript,Typescript,我有以下类层次结构: class Base { public BaseMethod() { // doesSomeStuff } } class Derived extends Base { constructor() { super(); } public DerivedMethod() { // do some stuff BaseMethod(); } } 我现在的问题是,在
class Base {
public BaseMethod() {
// doesSomeStuff
}
}
class Derived extends Base {
constructor() {
super();
}
public DerivedMethod() {
// do some stuff
BaseMethod();
}
}
我现在的问题是,在运行时,我得到一个classBase
的实例,我需要将该实例扩展为typeDerived
。我不控制Base
的构造,也不是classBase
的所有者
如何在运行时扩展该实例,使其成为派生类型的实例
function someFunction(base: Base) {
let derived: Derived = extend(base);
derived.BaseMethod();
derived.DerivedMethod();
}
function extend(base: Base): Derived {
// implementation?
}
PS:我需要瞄准ES5 这在ES6中可以使用。如果给
extend
函数一个asserts
返回类型,您甚至可以使用控制流缩小,而不是使用更严格的类型返回输入:
函数扩展(base:base):断言base是派生的{
setPrototypeOf(base,派生的.prototype);
}
设b:Base=newbase();
延长(b);
b、 DerivedMethod();//好的,由于控制流变窄
警告:如果不小心,这允许您创建具有无效状态的对象。如果Derived
类有自己的属性foo
,那么调用setPrototypeOf
会得到一个没有该属性的Derived
对象。您有责任确保extend
添加派生的
对象所需的任何新属性
如果你的目标是早于ES6,有一个,但这只适用于谷歌浏览器和Mozilla Firefox;它通过更改
\uuu proto\uu
属性来工作,但此属性在ES6之前是非标准的,因此其他浏览器不支持它。为了扩展polyfill,似乎没有其他方法可以在其他浏览器中获取或设置对象的原型,因此如果您需要在其他浏览器上的ES5中执行此操作,那么您可能运气不佳
另一种解决方案可能是通过monkey patching,但是派生的
obj实例将为false,这意味着它实际上不是派生的实例,这在ES6中是可能的。如果给extend
函数一个asserts
返回类型,您甚至可以使用控制流缩小,而不是使用更严格的类型返回输入:
函数扩展(base:base):断言base是派生的{
setPrototypeOf(base,派生的.prototype);
}
设b:Base=newbase();
延长(b);
b、 DerivedMethod();//好的,由于控制流变窄
警告:如果不小心,这允许您创建具有无效状态的对象。如果Derived
类有自己的属性foo
,那么调用setPrototypeOf
会得到一个没有该属性的Derived
对象。您有责任确保extend
添加派生的
对象所需的任何新属性
如果你的目标是早于ES6,有一个,但这只适用于谷歌浏览器和Mozilla Firefox;它通过更改\uuu proto\uu
属性来工作,但此属性在ES6之前是非标准的,因此其他浏览器不支持它。为了扩展polyfill,似乎没有其他方法可以在其他浏览器中获取或设置对象的原型,因此如果您需要在其他浏览器上的ES5中执行此操作,那么您可能运气不佳
另一个解决方案可能是通过monkey patching,但派生的obj实例将为false,这意味着它不会是派生的实例,我根据@kaya3的答案找到了一个令人满意的解决方案。如果您不需要支持传统浏览器,请查看他/她的答案
对于Object.setPrototypeOf
,有一个polyfill可供使用,它在传统IE浏览器(至少到IE9)中也可以使用。我在公园里找到的。它有一个警告,对象的引用需要重新分配
以下是我的解决方案:
class Base {
public BaseMethod() {
console.log('base called');
}
}
class Derived extends Base {
constructor() {
super();
}
public DerivedMethod() {
this.BaseMethod();
console.log('derived called');
}
}
function extend(base: Base): Derived {
return <Derived>(Object.setPrototypeOf(base, Derived.prototype));
}
function assert(base: Base): asserts base is Derived { }
let b: Base = new Base();
b = extend(b);
assert(b);
b.BaseMethod(); // base called
b.DerivedMethod(); // base called derived called
根据@kaya3的答案,我找到了一个令人满意的解决方案。如果您不需要支持传统浏览器,请查看他/她的答案
对于Object.setPrototypeOf
,有一个polyfill可供使用,它在传统IE浏览器(至少到IE9)中也可以使用。我在公园里找到的。它有一个警告,对象的引用需要重新分配
以下是我的解决方案:
class Base {
public BaseMethod() {
console.log('base called');
}
}
class Derived extends Base {
constructor() {
super();
}
public DerivedMethod() {
this.BaseMethod();
console.log('derived called');
}
}
function extend(base: Base): Derived {
return <Derived>(Object.setPrototypeOf(base, Derived.prototype));
}
function assert(base: Base): asserts base is Derived { }
let b: Base = new Base();
b = extend(b);
assert(b);
b.BaseMethod(); // base called
b.DerivedMethod(); // base called derived called
是否必须将基本
对象更改为派生
对象?你能不能编写一个静态工厂方法来构造一个新的派生的
对象,给定一个基
对象来复制它的状态?@kaya3不,这对我来说是不可能的。否则,其他对象将丢失对该对象的引用。是否必须将基本
对象更改为派生
对象?你能不能编写一个静态工厂方法来构造一个新的派生的
对象,给定一个基
对象来复制它的状态?@kaya3不,这对我来说是不可能的。否则其他对象将丢失对该对象的引用。@daniatic我明白了。我在编辑中提到了polyfill,但这只适用于两种特定的浏览器,因为它依赖于这些浏览器的非标准功能。否则,似乎不太可能有解决方案,但可能不需要在运行时实际更改对象的类来解决实际问题。在这种情况下,您应该提出一个新问题,详细说明您希望在object.Thx上更改的具体行为,以便进行编辑。polyfill还是没用。我需要支持IE9+:(扩展实际类Base
会解决您的问题吗?您可以在每个浏览器中分配新属性,如Base.constructor.DerivedMethod=…
。这将扩展每个Base
对象,包括已经存在的对象,而不必单独调用每个对象上的extend
。)当然,如果您只想扩展某些实例,则不适用。这是个好主意,但仍然不是f