【问题标题】:Typescript generic class that implements a generic type实现泛型类型的打字稿泛型类
【发布时间】:2018-08-24 09:14:45
【问题描述】:

有没有办法将以下代码转换为通用打字稿代码?我想要一个类实现一些接口 A 并接受两个 A 类型的元素并为接口 A 的属性返回不同的值取决于一些布尔标志。我查看了 typescript 泛型和自定义类型,但无法弄清楚。

本质上,我希望一个元素在纵向和横向中返回不同的值,而不必在每次我的应用程序的方向发生变化时都求助于mySprite.setPosition(new Vector(10,10)) 之类的东西。我是出于好奇而问这个问题,我不是在寻找这种情况的其他解决方案,我知道还有更多。

我能否定义一些通用类型,比如 Variant,这样对于我的精灵所具有的任何 A 类型的属性,我都可以执行类似mySprite.myPropOfTypeA=new Variant<A>(new A("landscape value"), new A("portrait value")) 这样的操作,以便 @987654323 @ 根据isLandscape() 的结果返回不同的值?我希望它是通用的,这样我就不必为我想要表现得像这样的每个属性创建派生类。谢谢!

interface IVector{
    x:number,
    y:number;
}

class Vector implements IVector{
    private _x:number;
    private _y:number;

    public get x() {return this._x;}
    public get y() {return this._y;}

    constructor(x:number, y:number){
        this._x=x;
        this._y=y;
    }
}

class VariableVector implements IVector{

    private _landscape: IVector;
    private _portrait: IVector;

    constructor(landscape: IVector, portrait: IVector){
        this._landscape=landscape;
        this._portrait=portrait;
    }

    public get x() {return isLandscape()? this._landscape.x:this._portrait.x;}
    public get y() {return isLandscape()? this._landscape.y:this._portrait.y;}

}

let mySprite=new Sprite(new VariableVector(new Vector(0,0), new Vector(10,10)));

谢谢!

【问题讨论】:

  • 您可以阅读mySprite.myPropOfTypeA.value 而不是mySprite.propOfTypeA
  • 我可能不应该使用 value 作为名称选择,但在这种情况下 value 将是接口 A 中的一个属性,类似于 interface A {value: number}。一个更好的例子是 mySprite.position.x,其中 mySprite.position 的类型是 IPositioninterface IPosition {x:number, y:number;},我会这样做 mySprite.position=new Variant<IPosition>(pos1, pos2),pos1 和 pos2 是任何实现 IPosition 接口的对象。

标签: javascript typescript generics


【解决方案1】:

以编程方式改变A 上读取的all 属性的能力实际上并不是class 提供给您的(特别是因为没有办法扩展泛型类型.. .class Variant<A> extends A 无效)。在这种情况下,您真正​​想要使用的是Proxy。冒着给你一个你不想要的答案的风险(不确定这是否违反“我不是在寻找这种情况的其他解决方案”),这是你可以制作此类 Proxy 对象的一种方法:

function makeVariant<A extends object>(
  condition: () => boolean, 
  trueValue: A, 
  falseValue: A
): A {
  return new Proxy(trueValue, {
    get(target, prop: keyof A, receiver) {
      return condition() ? trueValue[prop] : falseValue[prop];
    }
  });
}

函数makeVariant 接受一个回调和两个泛型类型A 的值,并返回一个对象,其属性将从一个值或另一个值中提取,具体取决于回调是返回true 还是false。我不确定您是否希望回调函数的范围超出makeVariant 的定义,因此不需要将其作为参数传入,但如果需要,您可能会摆弄它。

让我们看看它是否有效:

// not sure if isLandscape() is meant to be global    
let landscape: boolean = true;
function isLandscape() {
  return landscape;
}

const variantVector = makeVariant(isLandscape, new Vector(1, 2), new Vector(3, 4));

landscape = true;
console.log(variantVector.x, variantVector.y) // 1, 2
landscape = false;
console.log(variantVector.x, variantVector.y) // 3, 4

在我看来是合理的。希望能为您指明一个有用的方向。祝你好运!

【讨论】:

  • 谢谢,正是我想要的。我有一种感觉,仅使用泛型类型无法做到这一点,但我尝试使用您的方法,它可以满足我的需要。
【解决方案2】:

我想我对你的理解是正确的:)

class IPosition {
  constructor(public x: number, public y: number, public value: string) {}
}

class Variant<T extends IPosition> {
  constructor(private _landscape: T, private _portrait: T) {}

  public get x() { return isLandscape() ? this._landscape.x: this._portrait.x; }
  public get y() { return isLandscape()? this._landscape.y:this._portrait.y; }
}

const myPropOfTypeA = new Variant<IPosition>(new IPosition(0, 0, "landscape value"), new IPosition(10, 10, "portrait value"));

随时在 cmets 中提问,将尝试更改示例以适合您的任务。

还创建了stackblitz example

【讨论】:

    猜你喜欢
    • 2021-11-26
    • 1970-01-01
    • 2020-05-09
    • 2022-11-23
    • 2020-06-29
    • 1970-01-01
    • 2018-04-27
    • 2017-09-15
    • 2020-01-23
    相关资源
    最近更新 更多