You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

45 lines
1.6 KiB

// ============ An implementation of first() ============
/**
* Get the type of the ith element of a tuple.
* Kind: Vector -> number -> *
*/
type ElementOf<Arr extends unknown[], Index extends keyof Arr> = Arr[Index]
// An example - this returns the type of the second element of the tuple
// In this case, literal values are types (kinda), so this resolves to the literal type 'hello'
// That is, it is satisfiable by the subset of strings {hello}
// In an editor like VSCode, hover over the name of the type to see what it resolved to
type ExampleElementOf = ElementOf<[true, 'hello', 3.14], 1>
// This succeeds because the value 'hello' is assignable to the type 'hello'
const exampleElementGood: ExampleElementOf = 'hello'
// This fails because the value 'fubar' is not assignable to the type 'hello'
// const exampleElementBad: ExampleElementOf = 'fubar'
/**
* Accepts non-empty tuples.
* Does this by coercing the inferred tuple Arr to the intersection type Arr with an interface
* that MUST have an index 0 which has the type of the first element of Arr.
* Kind: Vector -> *
*/
type NonEmpty<Arr extends unknown[]> = Arr & { 0: ElementOf<Arr, 0> }
/**
* Gets the first element of a non-empty tuple.
*
* Accepts a parameter `arr` of type `NonEmpty<Arr>` where `Arr` is the inferred
* type of the tuple.
*
* @param arr
*/
function first<Arr extends unknown[]>(arr: NonEmpty<Arr>): ElementOf<Arr, 0> {
return arr[0]
}
const firstNumber = first([3.14]) // => type: number
const firstString = first(['hello', 3.14]) // => type: string
// const firstEmpty = first([]) // => type: never