typescript-tuple
Advanced tools
Comparing version 1.2.1 to 1.3.0
/** | ||
* Choose type base on whether or not a tuple is finite | ||
* @example `IsFinite<[0, 1, 2]>` → `true` | ||
* @example `IsFinite<[0, 1, 2, ...number[]]>` → `false` | ||
* @example `IsFinite<[0], 'Finite', 'Infinite'>` → `'Finite'` | ||
* @example `IsFinite<[0, ...number[]], 'Finite', 'Infinite'>` → `Infinite` | ||
*/ | ||
export declare type IsFinite<Tuple extends any[], Finite = true, Infinite = false> = utils.IsFinite<Tuple, Finite, Infinite>; | ||
/** | ||
* Get type of first element | ||
@@ -43,2 +51,7 @@ * @example `First<[0, 1, 2]>` → `0` | ||
export declare namespace utils { | ||
type IsFinite<Tuple extends any[], Finite, Infinite> = { | ||
empty: Finite; | ||
nonEmpty: ((..._: Tuple) => any) extends ((_: infer First, ..._1: infer Rest) => any) ? IsFinite<Rest, Finite, Infinite> : never; | ||
infinite: Infinite; | ||
}[Tuple extends [] ? 'empty' : Tuple extends (infer Element)[] ? Element[] extends Tuple ? 'infinite' : 'nonEmpty' : never]; | ||
type Last<Tuple extends any[], Default = never> = { | ||
@@ -48,3 +61,4 @@ empty: Default; | ||
multi: ((..._: Tuple) => any) extends ((_: any, ..._1: infer Next) => any) ? Last<Next> : Default; | ||
}[Tuple extends [] ? 'empty' : Tuple extends [any] ? 'single' : 'multi']; | ||
infinite: Tuple extends (infer Element)[] ? Element : never; | ||
}[Tuple extends [] ? 'empty' : Tuple extends [any] ? 'single' : Tuple extends (infer Element)[] ? Element[] extends Tuple ? 'infinite' : 'multi' : never]; | ||
type Prepend<Tuple extends any[], Addend> = ((_: Addend, ..._1: Tuple) => any) extends ((..._: infer Result) => any) ? Result : never; | ||
@@ -54,3 +68,7 @@ type Reverse<Tuple extends any[], Prefix extends any[] = []> = { | ||
nonEmpty: ((..._: Tuple) => any) extends ((_: infer First, ..._1: infer Next) => any) ? Reverse<Next, Prepend<Prefix, First>> : never; | ||
}[Tuple extends [any, ...any[]] ? 'nonEmpty' : 'empty']; | ||
infinite: { | ||
ERROR: 'Cannot reverse an infinite tuple'; | ||
CODENAME: 'InfiniteTuple'; | ||
}; | ||
}[Tuple extends [any, ...any[]] ? IsFinite<Tuple, 'nonEmpty', 'infinite'> : 'empty']; | ||
type Concat<Left extends any[], Right extends any[]> = { | ||
@@ -60,11 +78,43 @@ emptyLeft: Right; | ||
multiLeft: ((..._: Reverse<Left>) => any) extends ((_: infer LeftLast, ..._1: infer ReversedLeftRest) => any) ? Concat<Reverse<ReversedLeftRest>, Prepend<Right, LeftLast>> : never; | ||
}[Left extends [] ? 'emptyLeft' : Left extends [any] ? 'singleLeft' : 'multiLeft']; | ||
type Repeat<Type, Count extends number, Holder extends any[] = []> = { | ||
infiniteLeft: { | ||
ERROR: 'Left is not finite'; | ||
CODENAME: 'InfiniteLeft' & 'Infinite'; | ||
}; | ||
}[Left extends [] ? 'emptyLeft' : Left extends [any] ? 'singleLeft' : IsFinite<Left, 'multiLeft', 'infiniteLeft'>]; | ||
type Repeat<Type, Count extends number, Holder extends any[] = []> = number extends Count ? Type[] : { | ||
fit: Holder; | ||
unfit: Repeat<Type, Count, Prepend<Holder, Type>>; | ||
}[Holder['length'] extends Count ? 'fit' : 'unfit']; | ||
union: Count extends Holder['length'] | infer Rest ? Rest extends number ? Repeat<Type, Holder['length']> | Repeat<Type, Rest> : never : never; | ||
}[Holder['length'] extends Count ? Count extends Holder['length'] ? 'fit' : 'union' : 'unfit']; | ||
type ConcatMultiple<TupleSet extends any[][]> = { | ||
empty: []; | ||
multi: ((..._: Reverse<TupleSet>) => any) extends ((_: infer Last, ..._1: infer ReversedRest) => any) ? Last extends any[] ? ReversedRest extends any[][] ? Concat<ConcatMultiple<Reverse<ReversedRest>>, Last> : never : never : never; | ||
}[TupleSet extends [] ? 'empty' : 'multi']; | ||
nonEmpty: ((..._: Reverse<TupleSet>) => any) extends ((_: infer Last, ..._1: infer ReversedRest) => any) ? Last extends any[] ? ReversedRest extends any[][] ? Concat<ConcatMultiple<Reverse<ReversedRest>>, Last> : never : never : never; | ||
infinite: { | ||
ERROR: 'TupleSet is not finite'; | ||
CODENAME: 'InfiniteTupleSet' & 'Infinite'; | ||
}; | ||
}[TupleSet extends [] ? 'empty' : IsFinite<TupleSet, 'nonEmpty', 'infinite'>]; | ||
type SingleTupleSet<Types extends any[], Holder extends [any][] = []> = { | ||
empty: Holder; | ||
nonEmpty: ((..._: Reverse<Types>) => any) extends ((_: infer Last, ..._1: infer ReversedRest) => any) ? SingleTupleSet<Reverse<ReversedRest>, Prepend<Holder, [Last]>> : never; | ||
}[Types extends [] ? 'empty' : 'nonEmpty']; | ||
type FillTuple<Tuple extends any[], Replacement, Holder extends any[] = []> = { | ||
empty: Holder; | ||
nonEmpty: ((...a: Tuple) => any) extends ((a: infer First, ...b: infer Rest) => any) ? FillTuple<Rest, Replacement, Prepend<Holder, Replacement>> : never; | ||
}[Tuple extends [] ? 'empty' : 'nonEmpty']; | ||
type CompareLength<Left extends any[], Right extends any[]> = { | ||
fitBoth: 'equal'; | ||
fitLeft: 'shorterLeft'; | ||
fitRight: 'shorterRight'; | ||
unfit: ((..._: Left) => any) extends ((_: any, ..._1: infer LeftRest) => any) ? ((..._: Right) => any) extends ((_: any, ..._1: infer RightRest) => any) ? CompareLength<LeftRest, RightRest> : never : never; | ||
}[Left['length'] extends Right['length'] ? 'fitBoth' : Left extends [] ? 'fitLeft' : Right extends [] ? 'fitRight' : 'unfit']; | ||
type SortTwoTuple<Left extends any[], Right extends any[], WhenEqual = [Left, Right]> = { | ||
equal: WhenEqual; | ||
shorterLeft: [Left, Right]; | ||
shorterRight: [Right, Left]; | ||
}[CompareLength<Left, Right>]; | ||
type ShortestTuple<TupleSet extends any[][], Shortest = any[]> = { | ||
empty: Shortest; | ||
nonEmpty: ((..._: TupleSet) => any) extends ((_: infer Head, ..._1: infer Tail) => any) ? Tail extends any[] ? Shortest extends any[] ? Head extends any[] ? ShortestTuple<Tail, SortTwoTuple<Shortest, Head>[0]> : never : never : never : never; | ||
}[TupleSet extends [] ? 'empty' : 'nonEmpty']; | ||
} |
{ | ||
"name": "typescript-tuple", | ||
"version": "1.2.1", | ||
"version": "1.3.0", | ||
"description": "Generics to work with tuples in TypeScript", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -11,2 +11,17 @@ # TypeScript Tuple | ||
### `IsFinite` | ||
```typescript | ||
import { IsFinite } from 'typescript-tuple' | ||
type Foo = IsFinite<[0, 1, 2]> // Expect: true | ||
const foo: Foo = true | ||
type Bar = IsFinite<[0, 1, 2, ...number[]]> // Expect: false | ||
const bar: Bar = false | ||
type Baz = IsFinite<[0, 1, 2], 'finite', 'infinite'> // Expect: 'finite' | ||
const baz: Baz = 'finite' | ||
``` | ||
### `First` | ||
@@ -64,6 +79,22 @@ | ||
import { Repeat } from 'typescript-tuple' | ||
type Foo = Repeat<['x'], 5> // Expect ['x', 'x', 'x', 'x', 'x'] | ||
// Basic | ||
type Foo = Repeat<'x', 5> // Expect ['x', 'x', 'x', 'x', 'x'] | ||
const foo: Foo = ['x', 'x', 'x', 'x', 'x'] | ||
// Using union | ||
type Bar = Repeat<'x', 1 | 3 | 4> // Expect ['x'] | ['x', 'x', 'x'] | ['x', 'x', 'x', 'x'] | ||
const bar1: Bar = ['x'] | ||
const bar3: Bar = ['x', 'x', 'x'] | ||
const bar4: Bar = ['x', 'x', 'x', 'x'] | ||
// Using ambiguous 'number' type | ||
type Baz = Repeat<'x', number> // Expect 'x'[] | ||
const baz: Baz = Array<number>() | ||
``` | ||
**NOTES:** | ||
* Due to TypeScript design limitations, using floating point numbers and negative numbers might lead to infinite loop within TSC compiler, avoid doing this. | ||
### `ConcatMultiple` | ||
@@ -70,0 +101,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
11262
118
109