编辑:根据下面@artur-grzesiak 的评论,我们将 Playground 修改为更简单的版本,没有命名错误的interface方法。我们仍然希望编译器针对 not Implemented 抛出错误getInterface,但它不会这样做:
type GConstructor<T = {}> = abstract new (...args: any[]) => T;
// Raw objects interfaces
interface IBaseDataObject {
readonly id: string;
}
// Name Pattern
interface Name {
name: string;
}
// interfaces that classes must implement
interface BaseDataObjectInterface<T extends IBaseDataObject> {
readonly id: string;
readonly interface: T;
}
abstract class AbstractBaseObject<T extends IBaseDataObject> {
readonly id: string;
abstract readonly interface: T
constructor(
iBaseDataObject: T
) {
this.id = iBaseDataObject.id;
}
}
type AbstractBaseObjectCtor<T extends IBaseDataObject> = GConstructor<AbstractBaseObject<T>>;
// Country interface, class and instances
interface ICountry extends IBaseDataObject, Name {}
function NameAbstractMixin<TBase extends AbstractBaseObjectCtor<T>, T extends IBaseDataObject & Name>(Base: TBase) {
abstract class NamedBase extends Base implements Name {
readonly name: string;
constructor(...args: any[]) {
super(...args)
this.name = args[0].name;
}
}
return NamedBase;
}
class Country extends NameAbstractMixin(AbstractBaseObject<ICountry>) implements BaseDataObjectInterface<ICountry> {
// get interface(): ICountry {
// return {
// id : "hello",
// name: "France",
// }
// }
}
Run Code Online (Sandbox Code Playgroud)
AbstractBaseObjectCountry 类应该强制执行从声明抽象属性的类继承的抽象契约interface,并且该类Country应该实现BaseDataObjectInterface需要相同属性/访问器的类,但打字稿编译器不会引发任何错误,正如您在此打字稿游乐场上看到的那样。
我在这里错过了什么吗?
如果删除与错误本身无关的所有内容,问题将简化为:
type GConstructor<T = {}> = abstract new (...args: any[]) => T;
type ICountry = 'ICountry' | 'IAnotherCountry'
abstract class AGetInterface<T> {
abstract readonly getValue: T
}
function NameAbstractMixin1<TBase extends GConstructor<AGetInterface<T>>, T>(Base: TBase) {
abstract class NamedBase extends Base { }
return NamedBase;
}
class Country1 extends NameAbstractMixin1(AGetInterface<ICountry>) {
// get getValue(): ICountry {
// return 'ICountry';
// }
}
Run Code Online (Sandbox Code Playgroud)
让我们尝试详细添加编译器应该猜测的类型:
// Non-abstract class 'Country' does not implement inherited abstract member
class Country2 extends NameAbstractMixin1<GConstructor<AGetInterface<ICountry>>, ICountry>(AGetInterface<ICountry>) {
// get getValue(): ICountry {
// return 'ICountry';
// }
}
Run Code Online (Sandbox Code Playgroud)
所以这就是原因,编译器无法猜测类型
让我们尝试帮助编译器正确猜测类型
type GuessType3<C> = C extends GConstructor<AGetInterface<infer T>> ? T : never;
function NameAbstractMixin3<TBase extends GConstructor<AGetInterface<T>>, T = GuessType3<TBase>>(Base: TBase) {
abstract class NamedBase extends Base { }
return NamedBase;
}
// Non-abstract class 'Country3' does not implement inherited abstract member 'getValue'
class Country3 extends NameAbstractMixin3(AGetInterface<ICountry>) { }
Run Code Online (Sandbox Code Playgroud)
现在检查它在初始代码中是否有效
type GuessType<TBase> = TBase extends AbstractBaseObjectCtor<infer T> ? T : never
function NameAbstractMixin<TBase extends AbstractBaseObjectCtor<T>, T extends IBaseDataObject & Name = GuessType<TBase>>(Base: TBase) { ... }
// Non-abstract class 'Country' does not implement inherited abstract member 'getInterface'
class Country extends NameAbstractMixin(AbstractBaseObject<ICountry>) { ... }
Run Code Online (Sandbox Code Playgroud)
确实如此
通常在这种情况下尝试提供一些开箱即用的类型参数,
function NameAbstractMixin4<T>() {
return function <TBase extends GConstructor<AGetInterface<T>>>(Base: TBase) {
abstract class NamedBase extends Base { }
return NamedBase;
}
}
// Non-abstract class 'Country4' does not implement inherited abstract member 'getValue'
class Country4 extends NameAbstractMixin4<ICountry>()(AGetInterface<ICountry>) { }
Run Code Online (Sandbox Code Playgroud)
完美地工作,例如
顺便说一句,直到现在我才知道您可以在使用 T 类型参数之后放置它
如果您知道如何在没有双功能的情况下拆分类型参数,请发表评论,我一直在寻找
| 归档时间: |
|
| 查看次数: |
239 次 |
| 最近记录: |