使用与父级相同的方法扩展类并返回对象,但构造函数不同

Extend class and return object with same methods as parents but different constructor

提问人:reactfreakoutovercome 提问时间:10/13/2023 最后编辑:T.J. Crowderreactfreakoutovercome 更新时间:10/14/2023 访问量:57

问:

我正在尝试从外部库扩展一个类,该库包含在开始任何操作之前在输入中使用其构造函数的方法,因为它可以有多种类型。我想创建一个工作方式与它类似但对输入进行清理的类。

class ParentClass {
    constructor(value: ParentClass.ValueType) {
        // ...
    }

    methodUsingConstructor(otherValue: ParentClass.ValueType) {
        const x = new this.constructor(otherValue)
        // do some stuff here with x ...
        return result;
    }

    // ...
}

如果我这样做

class SafeParentClass extends ParentClass {
    constructor(value: ParentClass.ValueType) {
        // Do some input sanitizing ...
        super(sanitizedValue);
    }
}

我可以用.但是,我将获得一个带有 ParentClass 构造函数的对象。这意味着如果我这样做,则不会进行消毒,并且会出现错误。new SafeParentClass(value)(new SafeParentClass(value1)).methodUsingConstructor(value2)value2

我怎样才能创建一个我可以调用的方法,并且它们将有一个构造函数来清理输入?SafeParentClassParentClass

例:

import { Decimal } from 'decimal.js';

class SafeDecimal extends Decimal {
    constructor(value: Decimal.Value) {
        if (typeof value === 'string') {
            super(parseFloat(value)); // will do super('NaN') if value is not parseable
        } else {
            super(value);
        }
    }
}

然后测试它

describe('safeDecimal', () => {
    it('should return NaN output with invalid input', () => {
        expect(new SafeDecimal('123123').add('').toString()).toEqual('NaN');
    });
});

这会抛出一个 .DecimalError

JavaScript TypeScript OOP 清理

评论

1赞 T.J. Crowder 10/14/2023
“我可以使用新的safeParentClass(value)。但是,我将获得一个带有 ParentClass 构造函数的对象。“是什么让你这么想的?你在做一个在你的?(如果是这样:不要。returnconstructor
0赞 reactfreakoutovercome 10/14/2023
@T.J.Crowder:我可能弄错了,事实并非如此!我所知道的是,当我调用 并使用应该清理的 value2 时,我收到一个错误,因为它不是。我没有在构造函数中使用return(new safeParentClass(value1)).methodUsingConstructor(value2)
0赞 reactfreakoutovercome 10/14/2023
@T.J.Crowder 添加了一个示例,感谢您的反馈
1赞 T.J. Crowder 10/14/2023
你期待做什么?.add('')
1赞 reactfreakoutovercome 10/14/2023
返回“NaN”,因此整个操作应返回“NaN”。

答:

-1赞 Parzh from Ukraine 10/14/2023 #1

恐怕,您必须在派生类中自己实现所有方法。如果第三方类的方法的逻辑不能完全按照您的要求执行操作,则可以创建一个派生类,并将原始方法称为 。使用此技术,您可以首先清理输入,然后将其定向到原始方法。super.method(…)

基本上,这是你如何做到的:

class ThirdPartyClass {
  method(argument) {
    // the logic here unsafely uses the argument
  }
}
class DerivedClass extends ThirdPartyClass {
  override method(argument) {
    const safeArgument = sanitize(argument)

    return super.method(safeArgument)
  }
}

您必须对正在使用的所有方法执行此操作。

评论

0赞 Parzh from Ukraine 10/14/2023
请注意,这是一个特定于 TypeScript 的关键字,您不能在纯 JavaScript 代码中使用它override
0赞 reactfreakoutovercome 10/14/2023
谢谢,这就是我开始实施的,直到我意识到有很多方法正在使用并且更喜欢更灵活的解决方案。谢谢!
0赞 Parzh from Ukraine 10/14/2023
别客气!如果第三方库是开源的,我会转到源代码,查找由尽可能多的其他方法调用的实例方法,并重写这些方法(而不是重写每个方法,这很乏味)。
1赞 T.J. Crowder 10/14/2023 #2

问题是写的方式。具体来说,它覆盖了每个实例上的属性(而不是允许它从原型继承,这是正常的事情)。它在 () 中的当前第 4,290 行上执行此操作。对它的评论说,它这样做是为了掩盖继承的“......这就是对象(正常的做法是修复继承的 insetad。decimal.jsconstructorDecimaldecimal.mjsx.constructor = Decimal;

您可以通过覆盖以下功能来解决此问题:decimal.js

class SafeDecimal extends Decimal {
    constructor(value: Decimal.Value) {
        if (typeof value === "string") {
            super(parseFloat(value)); // will do super('NaN') if value is not parseable
        } else {
            super(value);
        }
        this.constructor = SafeDecimal; // <=== Here
    }
}

然后,使用构造函数并计算示例起作用(结果为 )。我没有测试过其他东西。NaN

在正常情况下,您不需要这个。它只是因为特定的编写方式而有必要。decimal.js


话虽如此,您可能希望分叉它并执行您认为需要在分叉中进行的更改。

最后,您可能需要考虑做一些比 更健壮的事情,因为会很乐意返回字符串(而抛出错误或返回可能更合理)。以下是您可能用来构建更强大的工具的各种选项的答案。parseFloatparseFloat123"123asdlfkjasldf"NaN