Is there a way to turn the following piece of code into generic typescript code? I want to have a class that implements some interface A and that takes two elements of type A and returns different values for the properties of interface A depending on some boolean flag. I looked at typescript generics and custom types but couldn't figure it out.
Essentially, I want an element to return different values in portrait and landscape without having to resort to things like mySprite.setPosition(new Vector(10,10))
each time the orientation of my application changes. I am asking this out of curiosity, I am not looking for other solutions to this situation, I know there are many more.
Could I define some generic type, say Variant such that for any property of type A my sprite has, I could do something like mySprite.myPropOfTypeA=new Variant<A>(new A("landscape value"), new A("portrait value"))
so that mySprite.myPropOfTypeA.value
returns different values depending on the oute of isLandscape()
? I want this to be generic so that I don't have to create a derived class for each property I want to behave like this. Thanks!
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)));
Thanks!
Is there a way to turn the following piece of code into generic typescript code? I want to have a class that implements some interface A and that takes two elements of type A and returns different values for the properties of interface A depending on some boolean flag. I looked at typescript generics and custom types but couldn't figure it out.
Essentially, I want an element to return different values in portrait and landscape without having to resort to things like mySprite.setPosition(new Vector(10,10))
each time the orientation of my application changes. I am asking this out of curiosity, I am not looking for other solutions to this situation, I know there are many more.
Could I define some generic type, say Variant such that for any property of type A my sprite has, I could do something like mySprite.myPropOfTypeA=new Variant<A>(new A("landscape value"), new A("portrait value"))
so that mySprite.myPropOfTypeA.value
returns different values depending on the oute of isLandscape()
? I want this to be generic so that I don't have to create a derived class for each property I want to behave like this. Thanks!
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)));
Thanks!
Share Improve this question asked Aug 23, 2018 at 23:44 user1354784user1354784 4166 silver badges16 bronze badges 2-
You're okay with reading
mySprite.myPropOfTypeA.value
as opposed tomySprite.propOfTypeA
? – jcalz Commented Aug 24, 2018 at 0:34 -
I probably should not have used value as name choice, but value in this case would be a property in the interface A something like
interface A {value: number}
. A better example would be mySprite.position.x where mySprite.position is of typeIPosition
withinterface IPosition {x:number, y:number;}
and I would domySprite.position=new Variant<IPosition>(pos1, pos2)
, pos1 and pos2 being any object implementing the IPosition interface. – user1354784 Commented Aug 24, 2018 at 0:36
2 Answers
Reset to default 3The ability to programmatically alter all property reads on A
in the same way isn't really something a class
gives you (especially since there's no way to extend a generic type... class Variant<A> extends A
is invalid). What you really want to use in this case is a Proxy
. At the risk of giving you an answer you don't want (not sure if this violates "I am not looking for other solutions to this situation"), here's one way you could make such Proxy
objects:
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];
}
});
}
The function makeVariant
accepts a callback and two values of generic type A
, and returns an object whose properties will be drawn from one or the other value depending on whether the callback returns true
or false
. I'm not sure if you want the scope of the callback function to be outside of the definition of makeVariant
so it doesn't need to be passed in as a parameter, but you could probably fiddle with that if you need to.
Let's see if it works:
// 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
Looks reasonable to me. Hope that points you in a useful direction. Good luck!
I guess I understand you correctly :)
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"));
Feel free to ask questions in ments, will try to change the example in order to fit your task.
Also created a stackblitz example
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745270971a4619742.html
评论列表(0条)