skip to Main Content
function Middleware<T extends Function>(middleware: Array<{ funcs: Array<keyof T['prototype']>, class: T }>) {

}

class TestValidation {
  Test() { }
}

class FilterValidation {
  Filter() { }
}

I am defining Middleware fonkisyon and I want to use giving class functions as string. But not working.

example usage

Middleware([
    { funcs: ['Test'], class: TestValidation },
    { funcs: ['Filter'], class: FilterValidation}
  ]) 

this code givin error
Type '"Filter"' is not assignable to type 'keyof TestValidation'

how can I fix this problem?

2

Answers


  1. To fix the TypeScript type problem in your code, you can make a small modification. Instead of defining funcs as an array of keyof T[‘prototype’], you can define it as an array of strings that represent the function names. Here’s an updated version of your code:

    function Middleware<T extends { prototype: Record<string, any> }>(middleware: Array<{ funcs: Array<keyof T['prototype']> | string[], class: T }>) {
      // Your implementation here
    }
    
    // Example usage
    class TestValidation {
      Test() {
        // Implementation of Test function
      }
    }
    
    class FilterValidation {
      Filter() {
        // Implementation of Filter function
      }
    }
    
    Middleware([
      { funcs: ['Test'], class: TestValidation },
      { funcs: ['Filter'], class: FilterValidation }
    ]);
    

    By defining funcs as Array<keyof T[‘prototype’]> | string[], it allows both keys of the prototype and string representations of the function names. This change will resolve the error you were encountering.

    Note: In the example usage, make sure you have defined the TestValidation and FilterValidation classes with their respective functions (Test and Filter).

    Login or Signup to reply.
  2. One approach is to make Middleware generic in a type parameter T corresponding to the tuple type of instance types constructed by the class property of the middleware array. So if you call Middleware([{funcs: [], class: Class1}, {funcs: [], class: Class2}]), where Class1 and Class2 are class constructors of types named Class1 and Class2 respectively, then T would be the type [Class1, Class2].

    And we’d make the middleware parameter be of a mapped type over T, such that each element of middleware takes on a type related to the corresponding element of T. For each numeric index I from the keys of T, the class property should be a construct signature for T[I] (the element of T at key I), while the funcs property should be an array of keys of T[I] whose properties are functions.

    We can write it like this:

    function Middleware<T extends readonly object[]>(
      middleware: [...{ [I in keyof T]: {
        funcs: ReadonlyArray<KeysMatching<T[I], Function>>
        class: new () => T[I]
      } }]
    ) {}
    

    where KeysMatching<T, V> is a utility type to get the property keys of T whose property values are assignable to V. One possible definition is

    type KeysMatching<T, V> = keyof
      { [K in keyof T as T[K] extends V ? K : never]: any }
    

    See In TypeScript, how to get the keys of an object type whose values are of a given type? for more information about how KeysMatching works.

    Oh, and the middleware parameter’s type is wrapped in a variadic tuple type like [...+] to give the compiler a hint that we want T to be inferred as a tuple and not an unordered array.


    Okay, let’s test it:

    class TestValidation { Test() { } }
    class FilterValidation { Filter() { } }
    
    Middleware([
      { funcs: ['Test'], class: TestValidation },
      { funcs: ['Filter'], class: FilterValidation }
    ]); // okay
    

    Looks good. Let’s test it on an example that fails:

    class Foo {
      a = 1;
      b = 2;
      c() { }
    }
    Middleware([{
      class: Foo, funcs: ["a", "b", "c"]; // error!
      // ---------------> ~~~  ~~~
    }])
    

    That fails because "a" and "b" are keys of Foo whose values are not functions. Only "c" is accepted. So this solution works for both accepting desirable inputs and rejecting undesirable ones.

    Playground link to code

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search