Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NonEmptyTuple type #476

Closed
sindresorhus opened this issue Sep 29, 2022 · 10 comments · Fixed by #915
Closed

NonEmptyTuple type #476

sindresorhus opened this issue Sep 29, 2022 · 10 comments · Fixed by #915
Labels
help wanted Extra attention is needed type addition

Comments

@sindresorhus
Copy link
Owner

sindresorhus commented Sep 29, 2022

export type NonEmpty<T> = [T, ...T[]];

Context: #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.
Fund with Polar
@Evertt
Copy link

Evertt commented Sep 30, 2022

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.

@skarab42
Copy link
Collaborator

I will make the one we already have generic and public.

export type NonEmptyTuple = readonly [unknown, ...unknown[]];

@sindresorhus
Copy link
Owner Author

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.

@Evertt
Copy link

Evertt commented Sep 30, 2022

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?

@skarab42
Copy link
Collaborator

skarab42 commented Sep 30, 2022

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

@skarab42
Copy link
Collaborator

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.

@skarab42
Copy link
Collaborator

skarab42 commented Sep 30, 2022

The main difference being that the NonEmptyTuple is readonly and the NonEmptyArray 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.

@sindresorhus sindresorhus changed the title NonEmpty type NonEmptyTuple type Sep 30, 2022
@bvandercar-vt
Copy link

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[]]

@adam-rocska
Copy link

adam-rocska commented Sep 5, 2023

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"

@fregante
Copy link
Collaborator

fregante commented Sep 9, 2023

Potentially already exists, with the exception that Adam mentions (which I think is just a TypeScript limitation):

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed type addition
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants