type-fest
type-fest copied to clipboard
`NonEmptyTuple` type
export type NonEmpty<T> = [T, ...T[]];
Context: https://github.com/sindresorhus/type-fest/pull/287
Why add such a simple type? Mostly for readability and discoverability. Most people don't know about this trick and we can document it well with examples and stuff.
Upvote & Fund
- We're using Polar.sh so you can upvote and help fund this issue.
- The funding will be given to active contributors.
- Thank you in advance for helping prioritize & fund our backlog.
I would find it just a bit more readable if it mentioned the word Array
, like NonEmptyArray
for example. Other than that, I'm all for it. Or indeed, OneOrMore
or AtLeastOne
like how the original PR called it. Anything that clearly implies that we're talking about a list of some kind.
I will make the one we already have generic and public. https://github.com/sindresorhus/type-fest/blob/fedbc441a314c1f9f5f6225c993860d0886261da/source/internal.d.ts#L74
I agree.
Any thoughts on naming it NonEmptyTuple
? It's technically a tuple, even though the term tuple/array is a bit of a conflated mess in TS.
Isn't the difference that tuples have a fixed length and arrays have a variable length?
So a NonEmptyArray
is not the same as a NonEmptyTuple
. The main difference being that the NonEmptyTuple
is readonly and the NonEmptyArray
is not (necessarily) readonly. Right?
Isn't the difference that tuples have a fixed length and arrays have a variable length?
I'm not sure about that, it's more to do with the positioning of the elements and their types. A tuple can have a variable length but an imposed sequence of elements.
type VariableLengtTuple1 = [string, boolean, ...number[]];
const foo:VariableLengtTuple1 = ['hello', true, 1, 2, 3]; // Pass
const bar:VariableLengtTuple1 = ['hello', 'world', 1, 2, 3]; // Fail
const baz:VariableLengtTuple1 = ['hello', true, 1, 2, 3, 'not-allowed']; // Fail
Any thoughts on naming it
NonEmptyTuple
? It's technically a tuple, even though the term tuple/array is a bit of a conflated mess in TS.
A tuple matches both tuple and array, but array does not match tuple. It's clearer for me to call it a tuple because technically it is one, but I understand that it can be confusing.
The main difference being that the
NonEmptyTuple
is readonly and theNonEmptyArray
is not (necessarily) readonly. Right?
No, a readonly tuple cannot be modified in any ways, a non-readonly tuple can have its members modified as long as they are of the same type.
const writableTuple: [string, number]= ['life', 42];
writableTuple[0] = 'hello'; // Pass, it not reaonly
writableTuple[1] = 'hello'; // Fail, Type 'string' is not assignable to type 'number'.
writableTuple[2] = 'hello'; // Fail, key out of bound
const readonlyTuple: readonly [string, number] = ['life', 42];
readonlyTuple[0] = 'hello'; // Fail, Cannot assign to '0' because it is a read-only property.
NonEmptyTuple
's type could definitely be improved to allow passing a type restriction to the tuple:
Current:
export type NonEmptyTuple = readonly [unknown, ...unknown[]]
Proposed:
export type NonEmptyTuple<T extends any = unknown> = readonly [T, ...T[]]
Sadly these ideas won't fly for this use case:
type NonEmptyTuple<T extends any = unknown> = readonly [T, ...T[]];
const wontFly: NonEmptyTuple = [...[], ...[1]];
EDIT: At the time of writing, it will fail with:
Type 'number[]' is not assignable to type 'NonEmptyOf<number>'.
Source provides no match for required element at position 0 in target.ts(2322)
Using "typescript": "^5.2.2"
Potentially already exists, with the exception that Adam mentions (which I think is just a TypeScript limitation):
- https://github.com/sindresorhus/type-fest/issues/420