Typescript: Can I define an n-length tuple type?

后端 未结 3 783
轮回少年
轮回少年 2020-12-06 00:50

I am creating a shogi game board using Typescript. A shogi board has 9 ranks and files.

I\'d like to assert a 9x9 multidimensional array as a type to ensure both the

相关标签:
3条回答
  • 2020-12-06 01:24

    Update:

    With Recursive conditional types (added in TypeScript 4.1.0) it is possible to:

    type Tuple<T, N extends number> = N extends N ? number extends N ? T[] : _TupleOf<T, N, []> : never;
    type _TupleOf<T, N extends number, R extends unknown[]> = R['length'] extends N ? R : _TupleOf<T, N, [T, ...R]>;
    
    type Tuple9<T> = Tuple<T, 9>;
    type Board9x9<P> = Tuple9<Tuple9<P>>;
    

    Playground


    Original answer:

    Typescript 3 introduces rest elements in tuple types

    The last element of a tuple type can be a rest element of the form ...X, where X is an array type

    To restrict the length of a tuple we can use intersection with { length: N }

    type Tuple<TItem, TLength extends number> = [TItem, ...TItem[]] & { length: TLength };
    
    type Tuple9<T> = Tuple<T, 9>;
    type Board9x9<P> = Tuple9<Tuple9<P>>;
    

    This works when variable of Tuple type is being initialized:

    const t: Tuple<number, 1> = [1, 1] // error: 'length' incompatible.
    

    A caveat here, typescript won't warn you if you'll try to access non element at index out of tuple range:

    declare const customTuple: Tuple<number, 1>;
    customTuple[10] // no error here unfortunately
    
    declare const builtinTuple: [number];
    builtinTuple[10] // error: has no element at index '10'
    

    There's a suggestion to add a generic way to specify length of a tuple type.

    0 讨论(0)
  • 2020-12-06 01:27
    type PushFront<TailT extends any[], FrontT> = (
      ((front : FrontT, ...rest : TailT) => any) extends ((...tuple : infer TupleT) => any) ?
      TupleT :
      never
    )
    
    type Tuple<ElementT, LengthT extends number, OutputT extends any[] = []> = {
      0 : OutputT,
      1 : Tuple<ElementT, LengthT, PushFront<OutputT, ElementT>>
    }[
      OutputT["length"] extends LengthT ?
      0 :
      1
    ]
    
    //type t3 = [string, string, string]
    type t3 = Tuple<string, 3>
    //type length = 0 | 3 | 1 | 2
    type length = Partial<Tuple<any, 3>>['length']
    

    Add a generic way to specify length of a tuple type #issuecomment-513116547

    0 讨论(0)
  • 2020-12-06 01:34

    One quick simplification would be to create a Tuple9 type, that can be used to create the first level as well as the second level of the matrix:

    type Tuple9<T> = [T, T, T, T, T, T, T, T, T]
    type Board9x9<P> = Tuple9<Tuple9<P>>
    
    0 讨论(0)
提交回复
热议问题