Repository navigation
[...(T[] & { length: N; })] be instantiated as [T, T, T, ..., T](N T's in total)Β #55772
Description
π Search Terms
Array Type At Least Elements Generic
β Viability Checklist
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals
β Suggestion
Declare an array with at least limited N elements (N = 3) is easy like:
type ArrayWith3PlusElements<T> = T[] & {
0: T;
1: T;
2: T;
}But when N is arbitury, generic support is required.
Please add feature that can declare an array with at least N elements using generic like this:
type ArrayWithNElements<T, N extends number> = T[] & {
length: N;
};
type MyArray3 = ArrayWithNElements<number, 3>; // Array with 3 elements of type number
const arr01: MyArray3 = [1, 2, 3]; // Valid
const arr02: MyArray3 = [1, 2, 3, 4]; // Error: Array does not have 3 elements
const arr03: MyArray3 = [1, 2]; // Error: Array does not have 3 elements
type ArrayWithNPlusElements<T, N extends number> = [...ArrayWithNElements<T, N>, ...T[]];
type MyArray3Plus = ArrayWithNPlusElements<number, 3>; // Array with at least 3 elements of type number
const arr11: MyArray3Plus = [1, 2, 3]; // Valid
const arr12: MyArray3Plus = [1, 2, 3, 4]; // Valid
const arr13: MyArray3Plus = [1, 2]; // Expected to be error but actually valid: Array does not have at least 3 elementsThat is, rest elements(...) operation of ArrayWithNElements<T, N> in ArrayWithNPlusElements<T, N> should effect in the type instantiation. For simplicity, instantiation is converted for ArrayWithNElements<T, N> only when the ... operation acts on it.
π Motivating Example
-
Validation: By enforcing a minimum number of elements in an array, you can ensure that the array meets certain requirements or constraints. For example, you might want to validate that an array has at least N elements before performing certain operations on it.
-
API Contracts: When designing APIs, you may want to specify that an array parameter should have a minimum length. This can help prevent errors or unexpected behavior when the array is used within the API.
-
Performance Optimization: In some cases, having a minimum number of elements in an array can improve performance. For example, if you know that an algorithm requires at least N elements to work efficiently, you can enforce this constraint in the type system to ensure that the algorithm is only used with arrays of sufficient length.
-
Code Clarity: By explicitly stating the minimum number of elements in an array type, you can make the code more self-documenting and easier to understand for other developers. It provides a clear indication of the expected array length and can help prevent mistakes or misunderstandings.
Overall, declaring a generic array type with at least N elements can help improve code correctness, maintainability, and performance in certain scenarios.
π» Use Cases
- What do you want to use this for?
The ability to define a generic array type with a minimum number of elements would be useful in scenarios where you want to ensure that an array meets certain requirements or constraints. For example, you might want to enforce that an array has at least N elements before performing certain operations on it.
- What shortcomings exist with current approaches?
The current approach in TypeScript does not support defining a type with a specific number of elements in an array. This limitation makes it challenging to enforce a minimum number of elements in an array type directly.
- What workarounds are you using in the meantime?
In the absence of native TypeScript support, you can consider using runtime checks or custom validation functions to ensure that an array has a minimum number of elements. These checks can be performed at runtime using conditional statements or utility functions. While this approach does not provide compile-time type safety, it can help validate the array length during runtime execution.
Activity
MartinJohns commentedon Sep 18, 2023
Duplicate of #54740, #50838, #47874.
KingMario commentedon Sep 18, 2023
I'm sorry but this is for at least N elements, not exactly N elements.
MartinJohns commentedon Sep 18, 2023
True, but that's more or less the same. π€·ββοΈ Just
[T, T, T, ...T[]]instead of[T, T, T].Also relevant: #55746
KingMario commentedon Sep 18, 2023
But this requires N to be generic.
And if required, readonly can be added so that the variable cannot be called with pop method or so.
KingMario commentedon Sep 18, 2023
Or perhaps, this behavior is buggy that arr13 is valid based on the following codes?
MartinJohns commentedon Sep 18, 2023
I have no idea what you mean with that comment.
Regardless, you can still just adapt the solution from the linked issue:
The team is not going to add extra functionality or a utility type for this (as per the issues I linked).
KingMario commentedon Sep 18, 2023
What I want is a declaration with two parameter T and N, where N extends number, and If you want to declare an array with at least N elements. If N is 10,000, you don't have to write a TupleAtLeastMap for over 10,000 lines first.
MartinJohns commentedon Sep 18, 2023
I understand that. And I linked you an issue where someone requests almost the same, and the team explicitly declines the feature request. What makes you think your "Tuple at least N" issue is any different than the "Tuple exact N" issue?
Anyhow, I provided you the next best solution, and now I'm outta here. βοΈ
KingMario commentedon Sep 18, 2023
Martin Johns (@MartinJohns) Thanks.
Tuple exact N can be declared generically with parameter T and N like this and TypeScript can validate any variable declared as such type:
KingMario commentedon Sep 18, 2023
Giving this buggy behavior codes could express what I required more clearly:
vs:
TypeScript TS Playground
--
Please note:
type NewArrayWithNElements<T, N extends number> = [...ArrayWithNElements<T, N>];are supposed to have also limited the array exactly N elements.jcalz commentedon Sep 18, 2023
I agree with Martin Johns (@MartinJohns) that this issue will almost surely be declined. Utility types are only added if they are needed to support
--declaration.If you want to write your own
ArrayWithNPlusElementsyou can do so:Playground link
which works for
Nup to 999 or so. If you need 10,000 it's probably impossible since I believe that's at or close to the limit for making programmatically generated tuple types.But even for 999 I sincerely doubt you really have a use case where it helps for the compiler to know this information. Let's use 50 as an example. Can you demonstrate some code where having a value of type
ArrayWithNPlusElements<number, 50>is demonstrably superior to having a value of typenumber[]? If you are hardcoding indices likearr[40]then it will help catch things likearr[99]as errors. But if you're iterating over the array likefor (let i=0; i<50; i++) { arr[i] }or computing array indices likearr[50-i]then there's no benefit because the type checker doesn't do type level math like that.KingMario commentedon Sep 18, 2023
Joe Calzaretta (@jcalz) Thanks.
This requirement comes from several functions in one project that each accepts an array as parameter and requires the array to have at least one or more elements, and the minimum number of elements required varies from function to function. These functions are passed constant parameters at call time, so I wanted to check that the minimum number of elements requirement is met for each function call at compile time rather than run time to catch errors earlier.
The very first way to write this is to declare for each function separately the parameter like
Then I realized that I could use
type ArrayWithNElements<T, N> = T[] & {length: N}to declare an array of exactly N elements, so I tried using[...ArrayWithNElements<T, N>, ...T[]]to declare an array of at least N elements but found that this declaration doesn't work in validating variables in TS playground.In contrast, with
type TupleExactMap<T> = [T, T, T];,[...TupleExactMap<T>, ...T[]]is able to show error for array with less than 3 elements.Playground link
The feature I required here is that
[...ArrayWithNElements<T, N>, ...T[]]would work as[...TupleExactMap<T>, ...T[]]do.Thanks for your working
ArrayWithNPlusElementstype declaration, which looks like a recursive declaration. Thanks Martin Johns (@MartinJohns), both type declarations can actually meet my current needs.[-]Declare an array with at least N elements using generic[/-][+]rest elements(...) operation of `ArrayWithNElements<T, N>` in `ArrayWithNPlusElements<T, N>` will affect the minimum length of the array in the type instantiation[/+][-]rest elements(...) operation of `ArrayWithNElements<T, N>` in `ArrayWithNPlusElements<T, N>` will affect the minimum length of the array in the type instantiation[/-][+]rest elements(...) operation of `ArrayWithNElements<T, N>` in `ArrayWithNPlusElements<T, N>` should affect the minimum length of the array in the type instantiation[/+][-]rest elements(...) operation of `ArrayWithNElements<T, N>` in `ArrayWithNPlusElements<T, N>` should affect the minimum length of the array in the type instantiation[/-][+]rest elements(...) operation of `ArrayWithNElements<T, N>` in `ArrayWithNPlusElements<T, N>` should set the minimum length of the array in the type instantiation[/+][-]rest elements(...) operation of `ArrayWithNElements<T, N>` in `ArrayWithNPlusElements<T, N>` should set the minimum length of the array in the type instantiation[/-][+]rest elements(...) operation of `ArrayWithNElements<T, N>` in `ArrayWithNPlusElements<T, N>` should effect in the type instantiation[/+][-]rest elements(...) operation of `ArrayWithNElements<T, N>` in `ArrayWithNPlusElements<T, N>` should effect in the type instantiation[/-][+]rest elements(...) operation of `T[] & { length: N; }` should effect in the type instantiation[/+][-]rest elements(...) operation of `T[] & { length: N; }` should effect in the type instantiation[/-][+]`[...(T[] & { length: N; })]` be instantialized as `[T, T, T, ..., T]`[/+][-]`[...(T[] & { length: N; })]` be instantialized as `[T, T, T, ..., T]`[/-][+]`[...(T[] & { length: N; })]` be instantialized as `[T, T, T, ..., T]`(totally N T)[/+][-]`[...(T[] & { length: N; })]` be instantialized as `[T, T, T, ..., T]`(totally N T)[/-][+]`[...(T[] & { length: N; })]` be instantialized as `[T, T, T, ..., T]`(N T's in total)[/+][-]`[...(T[] & { length: N; })]` be instantialized as `[T, T, T, ..., T]`(N T's in total)[/-][+]`[...(T[] & { length: N; })]` be instantiated as `[T, T, T, ..., T]`(N T's in total)[/+]typescript-bot commentedon Sep 21, 2023
This issue has been marked as "Declined" and has seen no recent activity. It has been automatically closed for house-keeping purposes.