How to declare a Fixed length Array in TypeScript

前端 未结 3 799
情书的邮戳
情书的邮戳 2020-12-02 13:02

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

3条回答
  •  生来不讨喜
    2020-12-02 13:31

    The Tuple approach :

    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)


    The Array(ish) approach :

    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
    

提交回复
热议问题