我有一个类(Foo
)和一个子类(Bar extends Foo
),它们的静态成员函数(func(...)
)都具有不同的类型。
interface IFoo {
f1: string;
f2: string;
}
class Foo {
static func(data: Partial<IFoo>): Partial<IFoo> {
return { f1: data.f1, f2: data.f2 }
};
}
interface IBar extends Partial<IFoo>{
b1: string;
b2: string;
}
class Bar extends Foo {
static func(data: Partial<IBar>): Partial<IBar> {
return { ...Foo.func(data), b1: data.b1, b2: data.b2 }
};
}
在此示例中,一切看起来都不错,但是我需要第二个版本的func
静态方法,而没有使用Partial
类型修饰符:
interface IFoo {
f1: string
f2: string
}
class Foo {
static func(data: Partial<IFoo>): Partial<IFoo> {
return { f1: data.f1, f2: data.f2 }
};
static func2 = Foo.func as (data: IFoo) => IFoo; // This one
}
interface IBar extends Partial<IFoo>{
b1: string;
b2: string;
}
class Bar extends Foo {
static func(data: Partial<IBar>): Partial<IBar> {
return { ...Foo.func(data), b1: data.b1, b2: data.b2 }
};
static func2 = Bar.func as (data: IBar) => IBar; // This one
}
Err ... func
和func2
在技术上做同样的事情,除了func
允许具有不完整的对象参数,相反,func2
则需要一个完全填充的参数
但是我在“ Bar”类上遇到了这个错误:
Class static side 'typeof Bar' incorrectly extends base class static side 'typeof Foo'.
Types of property 'func2' are incompatible.
Type '(data: IBar) => IBar' is not assignable to type '(data: IFoo) => IFoo'.
Types of parameters 'data' and 'data' are incompatible.
Type 'IFoo' is missing the following properties from type 'IBar': b1, b2ts(2417)
由于func
和func2
是相同的方法,但是仅使用Partial
修饰符,有什么方法可以消除此错误并能够覆盖{{1} }正确吗?
=====
编辑:
@jcalz解决方案都很好,但是如果func2
是一个抽象类,则会出现以下错误:
Foo
代码:
Type 'typeof Foo' is not assignable to type '(new () => Foo) & Pick<typeof Foo, "prototype" | "func">'.
Type 'typeof Foo' is not assignable to type 'new () => Foo'.
Cannot assign an abstract constructor type to a non-abstract constructor type.ts(2322)
我想我不能用const FooWithoutFunc2: (new () => Foo) & Omit<typeof Foo, "func2"> = Foo;
class Bar extends FooWithoutFunc2 {
// ...
}
输入Foo,因为它不是 newable ...。如何键入这样的抽象(new () => Foo)
?
谢谢。
答案 0 :(得分:1)
如果您覆盖某个东西,它需要与您覆盖的东西保持兼容。在TypeScript中,这是在类的静态方面以及类的实例方面实施的。这意味着某人应该能够像呼叫Bar.func2()
一样呼叫Foo.func2()
。但是您不能在定义中调用Bar.func2({f1: "", f2: ""})
,因此Bar
的静态端无法正确扩展Foo
的静态端。
因此,可能的解决方法:
如果有人打电话给Bar.func2({f1: "", f2: ""})
并返回{f1: "", f2: "", b1: undefined, b2: undefined}
,也许没关系。如果我要求Foo.func2
,然后递给我Bar.func2
,然后像调用Foo.func2
一样调用它,则会得到带有这些未定义的额外属性的输出,但结果仍然是有效的IFoo
,因此我应该很高兴(或者至少它遵守签名)。这意味着Bar.func2
既是有效的(x: IBar)=>IBar
也是有效的(x: IFoo)=>IFoo
。因此,我们可以使用intersection type声明它们都是它们,这相当于说Bar.func2
有两个overloaded呼叫签名:
class Bar extends Foo {
static func(data: Partial<IBar>): Partial<IBar> {
return { ...Foo.func(data), b1: data.b1, b2: data.b2 };
}
static func2 = Bar.func as ((data: IBar) => IBar) & typeof Foo.func2; // okay
}
Foo.func2({ f1: "", f2: "" });
Bar.func2({ f1: "", f2: "", b1: "", b2: "" });
Bar.func2({ f1: "", f2: "" }); // also okay because Bar.func2 extends Foo.func2
const foo: Foo = new Bar(); // but Bar still extends Foo (the instance side)
或者,也许您真的不希望任何人都使用非Bar.func2()
参数的值来调用IBar
。在这种情况下,class Bar extends Foo
就不可能成立。 Bar
的实例侧扩展了Foo
的实例侧,但构造函数对象本身未扩展。我们还可以通过创建另一个构造器对象来表达这一点,该构造器对象创建Foo
实例,但编译器不知道它具有func2
静态方法:
const FooWithoutFunc2: (new () => Foo) & Omit<typeof Foo, "func2"> = Foo;
class Bar extends FooWithoutFunc2 {
static func(data: Partial<IBar>): Partial<IBar> {
return { ...Foo.func(data), b1: data.b1, b2: data.b2 };
}
static func2 = Bar.func as ((data: IBar) => IBar); // okay
}
Foo.func2({ f1: "", f2: "" });
Bar.func2({ f1: "", f2: "", b1: "", b2: "" });
Bar.func2({ f1: "", f2: "" }); // error, typeof Bar doesn't extend typeof Foo anymore
const foo: Foo = new Bar(); // but Bar still extends Foo (the instance side)
现在Bar
仍在实例侧扩展Foo
,而Bar
在静态侧扩展FooWithoutFunc2
。
我想这取决于您的用例是否适合您。无论如何,希望能有所帮助;祝你好运!