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

Add NonEmptyArray to lib (but **not** length > 0 narrowing) #60491

Open
Rudxain opened this issue Nov 12, 2024 · 5 comments
Open

Add NonEmptyArray to lib (but **not** length > 0 narrowing) #60491

Rudxain opened this issue Nov 12, 2024 · 5 comments
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript

Comments

@Rudxain
Copy link

Rudxain commented Nov 12, 2024

⚙ Compilation target

ES2023

⚙ Library

ES2023

Missing / Incorrect Definition

type NonEmptyArray<T> = [T, ...T[]]
type ReadonlyNonEmptyArray<T> = readonly [T, ...readonly T[]]

Sample Code

const is_non_empty = <T>(a: ReadonlyArray<T>): a is ReadonlyNonEmptyArray<T> =>
	a.length > 0

function sum(a: ReadonlyNonEmptyArray<number>): number
function sum(a: ReadonlyNonEmptyArray<bigint>): bigint
function sum(a:
	ReadonlyNonEmptyArray<number> |
	ReadonlyNonEmptyArray<bigint>
) {
	//@ts-expect-error
	return a.reduce((acc, x) => acc + x)
}

Documentation Link

There's no docs that I'm aware of. However, there are multiple issues using this boilerplate.

Here's a WIP example implementations of sum. The sample code is a simplified version of that. More info here

@Rudxain Rudxain changed the title Add NonEmptyArray (but **not** length > 0 narrowing) Add NonEmptyArray to lib (but **not** length > 0 narrowing) Nov 12, 2024
@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature labels Nov 12, 2024
@jcalz
Copy link
Contributor

jcalz commented Nov 13, 2024

I'm confused by this; is the suggestion that a NonEmptyArray utility type be added... to... the TS libraries for ES2023? Why that version of JavaScript in particular? What functionality from ES2023 is that needed for?

The new issue template for "library change" doesn't mention it, but the "new feature" template has a rule that

So I don't see how or why this would be added to TypeScript. @RyanCavanaugh, could you clarify why this is awaiting more feedback instead of just declined? Thanks!

@Rudxain
Copy link
Author

Rudxain commented Nov 13, 2024

Why that version of JavaScript in particular?

description: "What's your compilation target (e.g.: `ES2015`)?"

description: "What's the current library you're using?"

I've considered specifying ESNext, but I felt it was more honest to answer with the stable version.

https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types

I'm unsure if this counts as a utility, as it's not a "type of types" but a more concrete (while still generic) "array of 1 or more things"

@mkantor
Copy link
Contributor

mkantor commented Nov 14, 2024

I'm unsure if this counts as a utility, as it's not a "type of types" but a more concrete (while still generic) "array of 1 or more things"

It's a generic type whose instantiation is a concrete type, which is the case for all generic types in TypeScript (the language doesn't support higher-kinded types).

@Rudxain
Copy link
Author

Rudxain commented Nov 14, 2024

It's a generic type whose instantiation is a concrete type, which is the case for all generic types

Correct! I should've said something like:
"""
Unlike Exclude, Pick, Omit, etc... NonEmptyArray is not a "type-level function" as it doesn't map a type to another.
"""
But if we go to the "everything is a function" route, NonEmptyArray<T> actually is a type-fn that maps T to a "tuple of 1 or more Ts". Which, I guess it's technically correct? I mean, there are functions that return concrete constants (this is true for many languages), which can be thought of as "A lambda that maps a Unit-type to a unit from another type" (this is true if the lambda is pure)

doesn't support higher-kinded types

I beg to differ: #55280 (see the namespaces section). TBF, it isn't an actual HKT, but it does have some features in common

@jcalz
Copy link
Contributor

jcalz commented Nov 14, 2024

Hmm, I really wish someone from the TS team would re-review this, otherwise this is apparently going to remain unresolved.

Your suggested types are still utility types (type NonNullable<T> = T & {} is a utility type, which is arguably less of a "mapping" than [T, ...T[]]) and runs into all the problems as mentioned in https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types: you're using up the name NonEmptyArray in the global scope, with a specific definition you prefer, but what if I prefer type NonEmptyArray<T> = [...T[], T] or type NonEmptyArray<T> = T[] & {0: any}? Or something completely different? What good does it do for TypeScript itself to make this choice for people?

As for ES2023, the library change feature is supposed to be something like #59162: some particular JS feature that was introduced with ES2023 is either missing or incorrect in the TS library. You're not talking about any JS feature at all, in any version of JS. That's why you balked at the documentation link. Utility types tend to go in the ES5 library, since it would be quite strange for someone targeting ES2018 to not have NonEmptyArray<T> in scope. But it's still not an ES5 "library change" request, per se. This really looks like a misfiled feature request.

I've made an attempt to explain what's going on, but I am not a member of the TS team, so I cannot speak authoritatively about this. At this point I'm in danger of merely repeating myself (maybe I already have?) so I'll disengage until and unless more definitive happens.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

4 participants