简体   繁体   中英

Typescript: infer generic types in generic type constraint

I have a generic interface that takes a type argument that must extend another generic type. For example:

export interface IPoint<TX, TY>
{
    x: TX;
    y: TY;
}
export interface ISeries<TPoint extends IPoint>
{
    points: Array<TPoint>;
}

Here, I must specify TX and TY for IPoint .

My question is: is there a way to infer those types automatically, for example like this?

export interface ISeries<TPoint extends IPoint<infer TX, infer TY>>
{
    points: Array<TPoint>;
}

The only way to make this work I've found for now is to add TX and TY as type parameters for ISeries , but it's quite impractical because then I have to specify the three types every time I use the interface.

I could also use IPoint<any, any> , but then I lose the information about the real types of x and y .

EDIT: To add some clarification about what I want to achieve, let's consider the following example:

export interface ISeries<TPoint extends IPoint<infer TX, infer TY>>
{
    points: Array<TPoint>;
    transformYValues?: (yValue: TY) => number;
}

Here I would need TY to strongly type transformYValues .

Thanks for your help

EDIT 2: Found a solution (thanks captain-yossarianfromUkraine).

export interface ISeries<TPoint extends IPoint<any, any>>
{
    points: Array<TPoint>;
    transformYValues?: (yValue: TPoint['y']) => number;
}

The key here is TPoint['y'] , I wasn't aware of this neat feature called Indexed Access Types (see https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html ).

In summary => use any typing in the generic type constraints, then use indexed access types to strongly type methods/properties inside the interface.

Consider this example:

export interface Point<X, Y> {
  x: X;
  y: Y;
}

type Values = string | number

export interface Series<Points extends Point<Values, Values>[]> {
  points: Points;
  transformYValues: (yValue: Points[number]['y']) => number;
}

const inference = <
  X extends Values,
  Y extends Values,
  Points extends Point<X, Y>[]
>(data: Series<[...Points]>) => void 0


inference({
  points: [{ x: 1, y: 2 }, { x: 1, y: 9 }],
  transformYValues: (arg) => {
    arg // 2 | 9
    return 42
  }
})

PLayground

I added Values type as a constraint for allowed x and y data types.

Also, I have added a function inference because type inference works with generic conditional types and function arguments.

To infer literal type x:1 y:2 I have used variadic tuple types , see this [...Points]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM