打字稿 1.4 中的联合类型是否可以用于声明 d3 样式 "chained" getter/setters?

Can union types in typescript 1.4 be used to declare d3-style "chained" getter/setters?

D3 等库中的常见模式是 "stackable getter/setters"。

例如(来自this example):

var force = d3.layout.force()
    .charge(-120)
    .linkDistance(30)
    .size([width, height]);

这里,chargelinkDistancesize作为setter,每个return一个force对象的实例,这样他们就可以"chained".

但是,它们也可以通过不指定参数来用作 getter,例如:

var d = force.linkDistance()

如果在第一个代码块之后调用,d 的值现在将为 30

我想使用 typescript 1.4 的新联合类型功能来创建这样的可链接 getter/setters。例如,以下编译为正确的 javascript:

class O {
    private _a: number = 0;
    a(x: number = null): O|number {
        if (x) {
            this._a = x;
            return this;
        }
        return this._a;
    }
}

这样 javascript 我可以做到:

var o = new O();
var v = o.a(3).a();

现在 v = 3。

但是从打字稿,我需要转换:

var o = new O();
var v: number = <number>(<O>o.a(3)).a();

不太吸引人!

有趣的是,看看 d3.d.ts,似乎人们一直在创建具有正确签名的接口,如下所示:

interface IA {
    a: {
        (): number;
        (x: number): IA;
    }
}

这不知何故神奇地解析了正确的签名来包装javascript,但我不知道如何在打字稿中实现这样的接口!

所以我的问题是,在打字稿中调用它们时,是否可以编写这样的可链接 getters/setters 而无需强制转换?或者,是否可以创建一个实现接口 IA 的打字稿 class?

返回你实际创建新类型的联合类型O|number

var o2: O|number = o.a(3);

TypeScript 编译器无法在不强制转换的情况下理解您需要的确切类型。

实际上联合类型的引入主要是为了消除函数重载,它们只能(至少目前)与类型 casting/checking 一起使用。

对于您的示例,我能看到的唯一方法是使用 2 种不同的方法来设置和获取值:

class O {
    private _a: number = 0;

    setA(x: number): O {        
        this._a = x;
        return this;
    }

    getA(): number {
        return this._a; 
    }
}

var o: O = new O();
var v: number = o.setA(3).getA();

is it possible to code such chainable getters/setters without requiring casts when they are used called in typescript? Alternately, is it possible to create a typescript class that implements the interface IA

是的。使用函数重载:

interface IA {
    a: {
        (): number;
        (x: number): IA;
    }
}

class A implements IA {
    private _a;
    a(): number
    a(x: number): A
    a(x?: any): any {
        if (x == void 0){
            return this._a;
        }
        else {
            this._a = x;
            return this;
        }
    }
}

var foo = new A(); 
var bar = foo.a(123); // okay
console.log(bar.a()); // 123
foo.a('not a number'); // Error