打字稿:`this`类型和泛型函数

时间:2017-01-18 16:06:13

标签: typescript polymorphism

假设我想创建一个接口addable,它使用方法__add__来描述类,该方法将类的对象添加到同一类的另一个对象中。

我们还要说我想要一个独立的函数add,它接受​​同一个类的两个addable个对象并返回它们的总和。

我的第一个想法是在界面中使用this类型:

interface addable<T> {
    __add__: (this: T, other: T) => T;
}

然后我按如下方式实现我的课程:

class Point implements addable {
    constructor(public x: number, public y: number) { }
    __add__(other: Point) {
        return new Point(this.x + other.x, this.y + other.y);
    }
}

哪个失败了:

  

Class'Point'错误地实现了接口'addable'。

     

属性类型“添加”不兼容。输入'(other:Point)=&gt;点'不能分配给''(其他:这个)=&gt;这个'。

     

类型'Point'不能指定为'this'类型。

编辑:经过一些研究后我发现this类型引用了this对象,而不是this对象的类。所以这次尝试注定要失败。

请参阅the example 1

我的第二个尝试是使用带有this伪参数的泛型:

interface addable<T> {
    __add__: (this: T, other: T) => T;
}

上面指定的类定义适用于这种情况。但是,当我尝试定义独立add

const add = <T>(a1: addable<T>, a2: addable<T>) => a1.__add__(a2);

我明白了:

  

'addable'类型的'this'上下文不能赋值给方法   '这''类型'''。

请参阅the example 2

有没有人知道如何实现所需的行为?

EDIT2:

界面

interface Addable<T> {
    add: (this: Addable<T>, other: Addable<T>) => Addable<T>;
}

显然是我想要的。那么独立的功能就是

const add = <T>(a1: Addable<T>, a2: Addable<T>) => a1.add(a2)

但这个定义过于宽松。它实际上是对Addable的任何两个实例进行类型检查,而不仅仅是同一类的实例

interface Addable<T> {
    add: (this: Addable<T>, other: Addable<T>) => Addable<T>;
}
class Point implements Addable<Point> {
    constructor(public x: number, public y: number) { }
    add(other: Point) {
        return new Point(this.x + other.x, this.y + other.y);
    }
}
class Num implements Addable<Num> {
    constructor(public number: number) { }
    add(other: Num) {
        return new Num(this.number + other.number);
    }
}
const add = <T>(a1: Addable<T>, a2: Addable<T>) => a1.add(a2)

var p1 = new Point(1, 1);
var num1 = new Num(10);

const wrongAdded = p1.add(num1);  // correctly fails

const wrongAdded2 = add(p1, num1);  // typechecks! why???

推断的添加类型为<{}>。这听起来不对,但我不熟悉打字稿足以声称有任何见解。

2 个答案:

答案 0 :(得分:0)

这实现了你想要的......我完全删除了参数this。如果需要,我会重命名它。这允许将一个点添加到另一个点,返回结果点...

interface Addable<T> {
    add: (other: T) => T;
}

class Point implements Addable<Point> {
    constructor(public x: number, public y: number) { }

    add(other: Point) {
        return new Point(this.x + other.x, this.y + other.y);
    }
}

var p1 = new Point(1, 1);
var p2 = new Point(3, 3);

var added = p1.add(p2);

alert(added.x + ' ' + added.y);

注意:我在这里调整了名称以使它们与野外的TypeScript更加一致 - 因为我不希望其他程序员将你的约定复制/粘贴到生产中。如果您愿意,可以自由使用名称addable__add__。)

答案 1 :(得分:0)

问题的最后一个版本几乎就在那里。我对泛型类型的约束使用了错误的语法。最终版本看起来像这样

interface Addable<T> {
    add: (this: Addable<T>, other: Addable<T>) => Addable<T>;
}
class Point implements Addable<Point> {
    constructor(public x: number, public y: number) { }
    add(other: Point) {
        return new Point(this.x + other.x, this.y + other.y);
    }
}

class Num implements Addable<Num> {
    constructor(public number: number) { }
    add(other: Num) {
        return new Num(this.number + other.number);
    }
}
const add: <T extends Addable<T>>(a1: T, a2: T) => T = function (a1, a2) {
    return a1.add(a2);
}

var p1 = new Point(1, 1);
var p2 = new Point(2, 2);
var num1 = new Num(10);

const added = p1.add(p2);
const added2 = add(p1, p2);

const wrongAdded = p1.add(num1);  // Fails

const wrongAdded2 = add(p1, num1);  // Fails