0

i want to create a type that maps a tuple of shape [...T[]] into [...TodoStepBlueprint<T>[]].

my knowledge of typescript is limited but i think i understand what i did so far.

this is what i have so far: (which is an extension of How to 'map' a Tuple to another Tuple type in Typescript 3.0) using typescript (3.7.5)

interface Strategy<T extends [...TodoStepBlueprint<AbstractTodoData>[]]> {}

type MaybeType<T> = T extends AbstractTodoData ? TodoStepBlueprint<T> : never;
type MaybeTypes<Tuple extends [...AbstractTodoData[]]> = {
  [Index in keyof Tuple]: MaybeType<
    Extract<Tuple[Index], [...AbstractTodoData[]]>
  >;
} & { length: Tuple["length"] };


interface TodoStepBlueprint<
  T extends AbstractTodoData,
  K = [...AbstractTodoData[]]
> {
  readonly todoType: Constructor<T>;
  readonly name: string;
  readonly possibleNext?: Strategy<MaybeTypes<K>>;
  // naming identifier
}

this produces a typescript error:

Type 'MaybeTypes<K>' does not satisfy the constraint 'TodoStepBlueprint<AbstractTodoData, AbstractTodoData[]>[]'.
  Type 'MaybeTypes<K>' is missing the following properties from type 'TodoStepBlueprint<AbstractTodoData, AbstractTodoData[]>[]': pop, push, concat, join, and 25 more.ts(2344)

somehow typescript does not unterstand that its an array anymore. what did i do wrong?

leonat
  • 127
  • 8
  • 1
    Doesn't `K` need to be constrained? – Aluan Haddad Aug 14 '20 at 17:03
  • 1
    For any `X`, the type `[...X[]]` is identical to `X[]` and the compiler reduces it to `X[]`... so I'd suggest replacing any instance of `[...X[]]` with `X[]` for clarity. – jcalz Aug 14 '20 at 17:13
  • 1
    You're making `K` [*default*](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-3.html#generic-parameter-defaults) to an array, but you're not [*constraining*](https://www.typescriptlang.org/docs/handbook/generics.html#generic-constraints) it to be an array. – jcalz Aug 14 '20 at 17:16
  • 1
    Hmm, and the type parameter `K` is conventionally used for *keylike* types that are assignable `string | number | symbol`. If your type parameter is an array, consider a type parameter like `U` instead. – jcalz Aug 14 '20 at 17:18

1 Answers1

0

thanks for all your responses:

this is my working solution.


interface Strategy<T extends [...TodoStepBlueprint<AbstractTodoData>[]]> {
  getPossibleNext(): T;
  getNext(): T[number];
}

type EnsureTodoStepBlueprintType<T> = T extends AbstractTodoData
  ? TodoStepBlueprint<T>
  : never;

type MapToTodoStepBlueprintArrayType<Tuple extends any[]> = {
  [Index in keyof Tuple]: EnsureTodoStepBlueprintType<Tuple[Index]>;
} & { length: Tuple["length"] };

interface TodoStepBlueprint<
  TodoType extends AbstractTodoData,
  PossibleNextTodoTypes extends AbstractTodoData[] = []
> {
  readonly todoType: Constructor<TodoType>;
  readonly name: string;
  readonly possibleNext?: Strategy<
    MapToTodoStepBlueprintArrayType<PossibleNextTodoTypes>
  >;
  // naming identifier
}
leonat
  • 127
  • 8