At the risk of demonstrating my lack of knowledge surrounding TypeScript types - I have the following question.
When you make a type declaration for an array like th
This solution provides a strict FixedLengthArray (ak.a. SealedArray) type signature based in Tuples.
Syntax example :
// Array containing 3 strings
let foo : FixedLengthArray<[string, string, string]>
This is the safest approach, considering it prevents accessing indexes out of the boundaries.
Implementation :
type ArrayLengthMutationKeys = 'splice' | 'push' | 'pop' | 'shift' | 'unshift' | number
type ArrayItems> = T extends Array ? TItems : never
type FixedLengthArray =
Pick>
& { [Symbol.iterator]: () => IterableIterator< ArrayItems > }
Tests :
var myFixedLengthArray: FixedLengthArray< [string, string, string]>
// Array declaration tests
myFixedLengthArray = [ 'a', 'b', 'c' ] // ✅ OK
myFixedLengthArray = [ 'a', 'b', 123 ] // ✅ TYPE ERROR
myFixedLengthArray = [ 'a' ] // ✅ LENGTH ERROR
myFixedLengthArray = [ 'a', 'b' ] // ✅ LENGTH ERROR
// Index assignment tests
myFixedLengthArray[1] = 'foo' // ✅ OK
myFixedLengthArray[1000] = 'foo' // ✅ INVALID INDEX ERROR
// Methods that mutate array length
myFixedLengthArray.push('foo') // ✅ MISSING METHOD ERROR
myFixedLengthArray.pop() // ✅ MISSING METHOD ERROR
// Direct length manipulation
myFixedLengthArray.length = 123 // ✅ READ-ONLY ERROR
// Destructuring
var [ a ] = myFixedLengthArray // ✅ OK
var [ a, b ] = myFixedLengthArray // ✅ OK
var [ a, b, c ] = myFixedLengthArray // ✅ OK
var [ a, b, c, d ] = myFixedLengthArray // ✅ INVALID INDEX ERROR
(*) This solution requires the noImplicitAny typescript configuration directive to be enabled in order to work (commonly recommended practice)
This solution behaves as an augmentation of the Array type, accepting an additional second parameter(Array length). Is not as strict and safe as the Tuple based solution.
Syntax example :
let foo: FixedLengthArray
Keep in mind that this approach will not prevent you from accessing an index out of the declared boundaries and set a value on it.
Implementation :
type ArrayLengthMutationKeys = 'splice' | 'push' | 'pop' | 'shift' | 'unshift'
type FixedLengthArray]> =
Pick>
& {
readonly length: L
[ I : number ] : T
[Symbol.iterator]: () => IterableIterator
}
Tests :
var myFixedLengthArray: FixedLengthArray
// Array declaration tests
myFixedLengthArray = [ 'a', 'b', 'c' ] // ✅ OK
myFixedLengthArray = [ 'a', 'b', 123 ] // ✅ TYPE ERROR
myFixedLengthArray = [ 'a' ] // ✅ LENGTH ERROR
myFixedLengthArray = [ 'a', 'b' ] // ✅ LENGTH ERROR
// Index assignment tests
myFixedLengthArray[1] = 'foo' // ✅ OK
myFixedLengthArray[1000] = 'foo' // ❌ SHOULD FAIL
// Methods that mutate array length
myFixedLengthArray.push('foo') // ✅ MISSING METHOD ERROR
myFixedLengthArray.pop() // ✅ MISSING METHOD ERROR
// Direct length manipulation
myFixedLengthArray.length = 123 // ✅ READ-ONLY ERROR
// Destructuring
var [ a ] = myFixedLengthArray // ✅ OK
var [ a, b ] = myFixedLengthArray // ✅ OK
var [ a, b, c ] = myFixedLengthArray // ✅ OK
var [ a, b, c, d ] = myFixedLengthArray // ❌ SHOULD FAIL