2

I am creating an Express rest API and also looking into creating my own decorator functions. I am now creating a decorator for a controller class.

But whenever I want to add this decorator to the controller I get the following error:

Unable to resolve signature of class decorator when called as an expression. Type 'Constructable' is not assignable to type 'typeof ZoneController'. Property 'getZones' is missing in type 'RestController' but required in type 'ZoneController'.

This error does not popup in the stackblitz (it should popup at the decorator on the ZoneController), but for the code see the Stackblitz

This makes sense because the RestController is the parent class of the ZoneConroller, so it does not know of any methods. In order to solve this I want to add a generic typing to the controller decorator:

type Constructable<T> = new (...args: any[]) => T

export function Controller<T extends RestController>(restCtor: Constructable<T>): Constructable<T> {
  return class extends restCtor {
    router = null
  }
}

But this causes the following error:

Class '(Anonymous class)' incorrectly extends base class 'T'. '(Anonymous class)' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'RestController'

I do not know how I should solve this error. For the error and code see the following Stackblitz. I have found some documentation (here and here) on this error, but it is unclear to me how I should change my code to resolve this error.

How should I change my code in order to resolve this issue? I am using typescript v4.0.2 and the following TSConfig:

{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "downlevelIteration": true,
    "experimentalDecorators": true,
    "module": "esnext",
    "moduleResolution": "node",
    "importHelpers": true,
    "target": "es2015",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2018",
      "dom"
    ]
  }
}

1 Answer 1

1

The definition for a class can be written using an interface:

interface SomeClass {
  new(...args: any[]): SomeClass
}

Following the same pattern, I think you'll want to change your definition of Constructable:

type Constructable<T> = new (...args: any[]) => Constructable<T>
Sign up to request clarification or add additional context in comments.

1 Comment

That indeed solves the issue, but it also causes a new error: Argument of type 'typeof ZoneController' is not assignable to parameter of type 'Constructable<typeof RestController>'.  Type 'ZoneController' is not assignable to type 'Constructable<typeof RestController>'. Type 'ZoneController' provides no match for the signature 'new (...args: any[]): Constructable<typeof RestController>'. The error is thrown on the @Controller decorator above the ZoneController class. Again, not visible in the stackblitz

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.