Infer generic from properties

senky

Let's have an interface that describes a rating form with example results to preview how it will look after all participants have submitted the form:

interface Rating {
  maxRating: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
  exampleResults: number[]; // E.g. [0, 0, 0, 2, 5] = 2 votes for 4*, 5 votes for 5*.
}

This naive implementation doesn't check whether exampleResults's length is the same as the value of maxRating. So instead I tried:

interface Rating<T extends 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10> {
  maxRating: T;
  exampleResults: Tuple<number, T>; // Touple definition is omitted for simplification
}

but when I try to use it:

const rating: Rating = {
  maxRating: 5,
  exampleResults: [0, 0, 0, 1, 4],
}

I get this error:

Generic type 'Rating' requires 1 type argument(s).

But obviously TypeScript can infer type by reading the value of maxRating.

Now I get it if TypeScript doesn't support such inference today, but is there another way I can use to restrict type of one property based on value of another?

Thanks for any suggestions!

captain-yossarian

In order to do that, you need to infer/to know maxRating upfront. Consider this example:

type Max = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;

type Tuple<Length extends Max, Result extends number[] = []> =
  Result['length'] extends Length
  ? Result
  : Tuple<Length, [...Result, number]>

interface Rating<M extends Max> {
  maxRating: M
  exampleResults: Tuple<M>
}

const rating: Rating<5> = {
  maxRating: 5,
  exampleResults: [1, 2, 3, 4, 5] // ok
}

const rating2: Rating<5> = {
  maxRating: 5,
  exampleResults: [1, 2, 3, 4, 5, 6] // expected error
}

Playground

TypeScript is unable to infer maxRating from the object, like you did.

There is another way to infer maxRating. You can use a function:

const handler = <N extends Max>(r: Rating<N>) => r

handler({ maxRating: 10, exampleResults: [1, 2, 3, 4, 5, 0, 0, 0, 0, 0] }) // ok

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Is there a way to infer a generic parameter from its properties?

infer typing for nested properties in generic

Infer generic type from argument

typescript infer generics from properties

Infer generic parameter from base class

How to infer class from generic type in Java?

Infer one of generic types from function argument

Infer typescript function generic from param value

Infer generic awaited type from Promise argument

Infer return type from generic types

Infer generic type from key of object

Typescript infer Generic types from Implementation

Partially infer generic index type from arguments

Infer generic type arguments from nested generics

Infer generic type argument from function callback

Infer parameters from return type of generic

Infer generic parameter from an array of types

Infer generic from any using protocol with associatedtype

How to infer generic parameter from mapped type?

TypeScript: Apply generic function to all properties of object and infer return value

Is there a way to infer generic type from a generic type in TypeScript?

Why can I not infer an interface from a constrained generic collection?

Infer generic class type parameters from single constructor parameter

Is there a way to infer the types of a specific value from an interface passed as a generic?

Infer function generic type U from return value of passed function

Infer any (generic) TypeScript class type from argument passed to a function

Is it possible to infer generic type from inside string template literal

How to correctly infer React props from as prop with generic overload

Can we infer generic typed parameter from function's parameter?