实现通用类型的Typescript泛型类

4
有没有办法将以下代码转换为通用的TypeScript代码?我想要一个实现某个接口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”)),从而使mySprite.myPropOfTypeA.value根据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 吗? - jcalz
我可能不应该使用value作为名称选择,但在这种情况下,value将是接口A中的属性,类似于interface A {value: number}。一个更好的例子是mySprite.position.x,其中mySprite.position是类型为IPosition的,具有interface IPosition {x:number, y:number;},我会执行mySprite.position=new Variant<IPosition>(pos1, pos2),其中pos1和pos2是实现IPosition接口的任何对象。 - user1354784
2个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
3

在同样的方式下编程地改变 A 的所有属性读取并不是一个 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的值,并返回一个对象,该对象的属性将根据回调函数返回truefalse从其中一个值中提取。如果您不确定回调函数的作用域是否要超出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

我认为这很合理。希望这能为你指明一个有用的方向。祝你好运!


谢谢,正是我想要的。我有一种感觉,只使用通用类型无法完成这个任务,但我尝试了您的方法,它做到了我需要的。 - user1354784

1

我猜我理解你的意思了 :)

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"));

欢迎在评论中提出问题,我会尝试更改示例以适应您的任务。

还创建了一个 stackblitz示例


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,