Kilka ciekawych i nieco już bardziej „magicznych” aspektów TypeScripta, czyli jak zrobić non empty array oraz fixed size array. Droga do mistrzostwa w TS. Zaczynajmy.
Ok, najpierw przykład non empty array:
type NonEmptyArray<T> = [T, ...T[]];
const okay: NonEmptyArray<number> = [1, 2];
const alsoOkay: NonEmptyArray<number> = [1];
const err: NonEmptyArray<number> = []; // error!
Wydaje się proste, prawda? Ludzie narzekają na ten przykład. I w sumie rację mają:
type NonEmptyArr<T> = [T, ...T[]];
let anotherArray = [1,2,3];
let arr: NonEmptyArr<number> = [...anotherArray, 4];
//Type '[...number[], number]' is not assignable to type 'NonEmptyArr<number>'
Nawet ciekawe rozwiązanie podają:
type NonEmptyArr<T> = [T, ...T[]] | [...T[], T] | [T, ...T[], T];
let anotherArray = [1,2,3];
let arr: NonEmptyArr<number> = [...anotherArray, 4]; //ok
W sumie jest to jedyna opcja, aby móc robić takie spready, to nie zadziała:
type NonEmptyArr<T> = T[] & { 0: T }
let anotherArray = [1,2,3];
let arr: NonEmptyArr<number> = [...anotherArray, 4]; //err
Natomiast to nam się przyda do czego innego. Najpierw doprowadźmy to do porządku:
type NonEmptyArr<T> = T[] & { 0: T }
let arr: NonEmptyArr<number> = [1,2,3,4]; //ok
Ok, a można sobie dopisać length? W sensie kolejny &, length number? Zobaczmy:
type NonEmptyArr<T> = T[] & { 0: T } & {length: number};
let arr: NonEmptyArr<number> = [1,2,3,4]; //ok
Można nawet tak do tego podejść:
type NonEmptyArr<T> = { 0: T } & {[Idx: number]: T} & {length: number};
let arr: NonEmptyArr<number> = [1,2,3,4]; //ok
Ok, to teraz tak:
type FixedSizeArr<T, N extends number> = T[] & {length: N};
let arr: FixedSizeArr<number, 3> = [1,2,3]; //ok
let arr2: FixedSizeArr<number, 3> = [1,2,3,4]; //err
Natomiast żeby ta FixedSizeArr była spreadable to się nie da. Ja przynajmniej nie umiem.