How can I ensure an array is passed a certain number of parameter in a function apart from using a tuple
I have a function in typescript which takes an array as a parameter and when the function is called i want a certain number of elements to be passed in the array how can I achieve this apart from using a tuple
type a =(arr: [number, number]) => boolean
const b:a = (arr) => {}
b([]) // should throw an error if the parameter passed in array is less than two
How can I achieve this without using tuples
CodePudding user response:
You could extend Array<number>
with a specific length and types for each index:
interface TupleOfTwoNumbers extends Array<number> {
length: 2;
0: number;
1: number;
}
type a = (arr: TupleOfTwoNumbers) => boolean
const b: a = (arr) => true
b([]); // !
b([1]); // !
b([1, 2]); // ok
b([1, 2, 3]); // !
but the errors generated aren't as helpful:
Argument of type '[]' is not assignable to parameter of type 'TupleOfTwoNumbers'.(2345)
compared to using tuples:
Argument of type '[]' is not assignable to parameter of type '[number, number]'. Source has 0 element(s) but target requires 2.(2345)
CodePudding user response:
If you have to do this instead of using tuples, you can type the length
property of the array as the length you want, and then it will require the length of the passed array to match that.
type FixedLengthArray<T, Length extends number = number> = readonly T[] & {
length: Length
}
function foo(arr: FixedLengthArray<number, 3>) {
// Do stuff
}
foo([1, 2, 3, 4] as const);
/*
Argument of type 'readonly [1, 2, 3, 4]' is not assignable to parameter of type 'FixedLengthArray<number, 3>'.
Type 'readonly [1, 2, 3, 4]' is not assignable to type '{ length: 3; }'.
Types of property 'length' are incompatible.
Type '4' is not assignable to type '3'.ts(2345)
*/
The as const
is required to make the length of the array fixed instead of just plain number
.
This reflects reality, as a regular array's length can change and therefore type-checking should fail unless it is definitely a certain length.
You can use either as const
or assert the type of the array:
// as const
const arr1 = [1, 2, 3] as const
foo(arr1)
// Type Assertion
type SetLength<T extends any[], Length extends number> = T & {
length: Length;
};
const arr2 = [1, 2, 3]
foo(arr as SetLength<typeof arr, 3>)