6

我们可以为 es6 类实现接口的方式非常简单:

interface IDog {
    bark(): void
}

class Dog implements IDog {
    bark(): void {

    }
}

问题是:如何为这个“类”实现相同的接口:

const Dog = function() {

}

Dog.prototype.bark = function() {

}

我尝试将 Dog 的类型定义为 IDog: const Dog: IDog。没用。

所以,我需要它来实现依赖倒置,我不知道如何用 es5 类做到这一点。我看到 Classical Inheritance 样式是 Javascript 中的“反模式”,所以我决定以旧方式创建类,并且需要帮助实现 Typescript 接口。

4

2 回答 2

9

我假设您想要 es5 样式的类实现,它被声明为符合IDog接口,并由编译器进行类型检查以确保它真正符合该接口。

坏消息 - TypeScript 不支持。你可以让 TypeScript 认为 es5Dog是一个实现的类IDog,但你必须声明DogConstructor接口并使用as any as DogConstructor类型断言Dog。而且您不能让 TypeScript 对基于原型的实现进行类型检查,因为Object.prototype(以及随后Dog.prototype)被声明为any在系统库中(请参阅这些 问题进行一些讨论):

interface IDog {
    bark(): void
}

interface DogConstructor {
    new(): IDog;
}

const Dog = function (this: IDog) {
    // this.bark(); you can do this because of `this: IDog` annotation
} as any as DogConstructor;

Dog.prototype.bark = function() {

}

const p = new Dog();
p.bark();

我认为对此的支持将永远不会得到改善。Es5 风格的类通常是在不进行类型检查的 javascript 代码中实现的,TypeScript 为编写类型声明提供了足够的支持,允许以类型安全的方式使用 javascript 实现。如果你在 TypeScript 中实现类,你可以简单地使用真正的类。

于 2018-07-09T01:14:46.430 回答
2

对此没有语言支持,如果这种情况足够普遍,我们能做的最好的事情就是推出我们自己的类创建函数,它对我们添加到类中的成员施加限制。

使用noImplicitThis编译器选项,ThisType我们也可以对类成员进行很好的类型检查,我们没有得到任何像明确的字段分配这样的花哨的东西,但它已经足够好了:

interface IDog {
    bark(): void
}

function createClass<TInterfaces, TFields = {}>() {
    return function<TMemebers extends TInterfaces>(members: TMemebers & ThisType<TMemebers & TFields>) {
        return function<TCtor extends (this: TMemebers & TFields, ...a: any[]) => any>(ctor: TCtor) : FunctionToConstructor<TCtor, TMemebers & TFields> {
            Object.assign(ctor.prototype, members);
            return ctor as any;
        }
    }
}

const Dog = createClass<IDog, { age: number }>()({
    eat() {
        // this is not any and has the fields defined in the TFields parameter
        // and the methods defined in the current object literal
        for(let i =0;i< this.age;i++) {
            this.bark();
            console.log("eat")
        }
    },
    bark() {
        console.log("BA" + "R".repeat(this.age) + "K");
    }
})(function(age: number) {
    this.age = age; // this has the fields and members previously defined 
    this.bark();
})
const p = new Dog(10);
p.bark();

// Helpers
type IsValidArg<T> = T extends object ? keyof T extends never ? false : true : true;

type FunctionToConstructor<T, TReturn> =
    T extends (a: infer A, b: infer B) => void ?
    IsValidArg<B> extends true ? new (p1: A, p2: B) => TReturn :
    IsValidArg<A> extends true ? new (p1: A) => TReturn :
    new () => TReturn :
    never;

注意上面的实现类似于这里的答案,你可以在那里阅读更深入的解释。

于 2018-07-09T04:36:37.293 回答