lundi 25 juillet 2022

How can I write an interface where a class returns the same type as itself?

Consider this code, it's written in Typescript but the language I don't think really matters.

interface IXY {
  x: number;
  y: number;

  scale(n: number): IXY;
}

interface IXYZ extends IXY {
  z: number;

  scale(n: number): IXYZ;
}

// this is not my real code, just an example.
function flip<T extends IXY>(v: T, flip: boolean): T {
  if (flip) return v.scale(-1); // Error here
  else return v;
}

This gives me the following error:

Type 'IXY' is not assignable to type 'T'.
'IXY' is assignable to the constraint of type 'T',
but 'T' could be instantiated with a different subtype of constraint 'IXY'

Now, I understand why this error is occuring. It's because any interface that extends IXY only has to ensure that scale returns something that extends IXY. Consider this example, where IABC just returns an IXY.

interface IABC extends IXY {
  scale(n: number): IXY; // does not have to return IABC.
}

I guess my question is, how can I write IXY's .scale to make sure whatever is extending it is returning the same type as that extension? When I call flip with an IXYZ I want to know that what I get out is also going to be an IXYZ.

How do I write an interface that ensures inheritors return the same type as themselves? How do I make sure I don't lose the z in IXYZ?

Many thanks.

Aucun commentaire:

Enregistrer un commentaire