我正在尝试允许两个类扩展相同的接口,但具有不同的类型参数。我有SomeTypedInterface,扩展SomeBaseClass的SomeClass和扩展ISomeBaseProps的ISomeProps。我希望SomeClass和SomeBaseClass都使用各自的道具来扩展SomeTypedInterface。
注意:这两个类都不实际实现SomeTypedInterface或ISome * Props。幕后发生了一些不可思议的事情,与这个问题没有太大关系。长话短说,SomeTypedInterface中的函数和ISome * Props中的属性将自动添加到这些类的实例中。我只是想让编译器知道这里正在使用的类型,以便我们在使用这些对象时具有良好的智能感知。
这是有问题的简单示例:
interface SomeTypedInterface<TProps>
{
getProps(): TProps;
}
interface ISomeBaseClassProps
{
baseStringProp: string;
}
interface SomeBaseClass extends ISomeBaseClassProps,
SomeTypedInterface<ISomeBaseClassProps> { }
class SomeBaseClass
{
...
}
interface ISomeClassProps extends ISomeBaseClassProps
{
booleanProp: boolean;
}
interface SomeClass extends ISomeClassProps,
SomeTypedInterface<ISomeClassProps> { }
class SomeClass extends SomeBaseClass
{
...
}
这会出现以下错误:
Interface 'SomeClass' cannot simultaneously extend types 'SomeBaseClass' and 'SomeTypedInterface<ISomeClassProps>'.
Named property 'getProps' of types 'SomeBaseClass' and 'SomeTypedInterface<ISomeClassProps>' are not identical.
其他一些信息:
我真正要寻找的是一种告诉编译器的方法,即SomeClassdInterface的SomeClass扩展覆盖相同接口的SomeBaseClass扩展,对SomeTypedInterface进行(简单或复杂)更改和/或对SimpleTypedInterface进行简单更改。类的接口。这将是一种广泛使用的模式,因此在单个实现中的简单性至关重要。
答案 0 :(得分:1)
也许可以代替声明合并(或除了声明合并)而在类中声明属性?喜欢:
class SomeClass extends SomeBaseClass {
getProps!: () => ISomeClassProps; // note the !
}
可以用您之前做过的任何魔术来完成实际的实现,但是现在SomeClass
不再抱怨getProps
的类型了。请注意definite assignment assertion (!
),以使--strictPropertyInitialization
不会打扰您。
有帮助吗?
答案 1 :(得分:1)
这是另一种方法,假设您需要以编程方式创建类属性,并且无法手动添加它们。让我们创建一个帮助函数,该函数返回SomeBaseClass
构造函数并将其断言为较窄的类型。然后,可以让您的子类扩展该函数的返回值,并且它应具有与声明合并类似的作用:
// helper function asserting that SomeBaseClass returns instances of a narrower type T
const assertSomeBaseClass = <T extends SomeBaseClass>() => SomeBaseClass as (new () => T);
// don't do declaration merging, instead extend an asserted-to-be-narrower class:
class SomeClass extends assertSomeBaseClass<
ISomeClassProps & SomeTypedInterface<ISomeClassProps>
>() {
//...
}
// test the properties
declare const someClass: SomeClass;
someClass.baseStringProp; // string
someClass.booleanProp; // boolean
someClass.getProps(); // ISomeClassProps
至少在我对您的用例了解的情况下,这似乎可行。希望能有所帮助。再次祝你好运!
答案 2 :(得分:0)
我想我找到了我可以接受的解决方案。
我不是让基类和派生类都扩展了接口,而是让基类接受了泛型,然后使用其自己的props和泛型的组合类型来扩展接口。然后,派生类将扩展基类。
结果是两个类都使用不同的类型参数扩展了接口。
interface SomeTypedInterface<TProps>
{
getKeys(): keyof TProps;
}
interface ISomeBaseClassProps
{
baseStringProp: string;
}
interface SomeBaseClass<TProps extends ISomeBaseClassProps = ISomeBaseClassProps> extends ISomeBaseClassProps,
SomeTypedInterface<TProps & ISomeBaseClassProps> { }
class SomeBaseClass<TProps>
{
...
}
interface ISomeClassProps extends ISomeBaseClassProps
{
booleanProp: boolean;
}
interface SomeClass extends ISomeClassProps { }
class SomeClass extends SomeBaseClass<ISomeClassProps>
{
...
}
此解决方案有两个缺点,但是我认为这对于我的用例都是可以接受的。
keyof TProps | "baseStringProp
。它在派生类中完美运行,因为该类不需要泛型。在我们的场景中,我们正在使用的“类”中的很大一部分实际上并不需要类声明(问题的“其他信息”部分中的#2),所以我认为这是对于较不常见的多级继承情况,可以接受的解决方案(虽然肯定不是理想的)。