typescript TS1241: Kan ikke løse signaturen til metode-dekoratør når den kalles som et uttrykk


Min testkode er som følger:

function test(target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) {
    return descriptor;
}

class Test {
    @test
    hello() {
    }
}

men kompilatoren gir meg en feil

Error:(33, 5) TS1241: Unable to resolve signature of method decorator when called as an expression.
 Supplied parameters do not match any signature of call target.

Jeg har allerede spesifisert:

--experimentalDecorators --emitDecoratorMetadata

Svar #1

Bruk --target ES5 --emitDecoratorMetadata --experimentalDecorators

eller bruk følgende konfigurasjon:

{
  "compilerOptions": {
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "ES5"
  }
}

Svar #2

Det ser ut til at TypeScript forventer at returtypen til dekoratorfunksjonen skal være 'any' eller 'void'. Så i eksemplet nedenfor, hvis vi legger til : any på slutten, fungerer det til slutt.

function test(target: Object, 
              propertyKey: string, 
              descriptor: TypedPropertyDescriptor<any>): any {
    return descriptor;
}

Svar #3

Denne kryptiske feilmeldingen ser ut til å ha hatt flere grunnårsaker over tid. Per slutten av 2019 er dette hva jeg kunne samle:

  • Beskjeden er i beste fall misvisende; problemet har ingenting å gjøre med evnen til å løse signaturer, eller mangel på sådan. Den indikerer heller et typingsproblem på dekoratørene. For eksempel gir følgende kode TS1241 på @f(), men ikke på @g():
function f() {
    console.log("f(): evaluated");
    return function (targetClass: any, propertyKey: string, descriptor: TypedPropertyDescriptor<() => void>) {
        console.log("f(): called with " + arguments.length + " arguments");
    }
}

function g() {
    console.log("g(): evaluated");
    return function (target: any, propertyKey: string) {
        console.log("g(): called with " + arguments.length + " arguments");
    }
}

class C {
    @f()      // TypeScript signals TS1241 here
    @g()      // but not there
    method() { }
}
  • Kallkonvensjonen for dekoratører, og dermed deres type, avhenger av den målrettede JavaScript-dialekten. For eksempel, å kjøre koden ovenfor med {"compilerOptions": { "target": "ES3" } } resulterer i

    f(): evaluated main-2.js line 1134 > eval:9:13
    g(): evaluated main-2.js line 1134 > eval:15:13
    g(): called with 2 arguments main-2.js line 1134 > eval:17:17
    f(): called with 2 arguments
    f(): evaluated main-2.js line 1134 > eval:9:13
    g(): evaluated main-2.js line 1134 > eval:15:13
    g(): called with 3 arguments main-2.js line 1134 > eval:17:17
    f(): called with 3 arguments
    
  • (💡 Når du prøver ut koden på typescriptlang.org/play, åpne først JavaScript-konsollen i nettleserens utviklerverktøy; klikk deretter Kjør).
    På den annen side, å kjøre nøyaktig den samme koden under "target": "ES5" resulterer i, og følgelig er TypeScript helt fornøyd med @f() (og også @g()) i det tilfellet.

Den enkleste løsningen er derfor å late som om den tredje parameteren er valgfri, det vil si

function f() {
    console.log("f(): evaluated");
    return function (targetClass: any, propertyKey: string, descriptor?: TypedPropertyDescriptor<() => void>) {
        console.log("f(): called with " + arguments.length + " arguments");
    }
}

class C {
    @f()
    method() { }
}

som typekontrolleres vellykket både under "target": "ES3" og "target": "ES5".

Denne «juksen» er spesielt viktig hvis du bruker angular-meteor, i så fall vil du definitivt ikke rote med "target"-innstillingen i tsconfig.json.

Relaterte artikler