You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The above issues reference various problems with decorators and decorator type checking. The following are some examples of issues I'd like to address:
Constructor parameter decorators receive undefined for propertyKey
The definition of ParameterDecorator indicates the propertyKey is string | symbol, however constructor parameters receive undefined. Receiving undefined is an intentional behavior, as it allows the decorator author to detect they are decorating a constructor's parameter. However, this is not correctly noted in the definition of ParameterDecorator. That is the crux of #33260.
However, there is more that we should be doing here, as we do not accurately check the type that should be passed for the propertyKey argument:
declarefunctionP(target: Function,propertyKey: undefined,parameterIndex: number): void;classC{constructor(@Px: any){}// ok (correct)method(@Px: any){}// ok (should be an error)}P(C,undefined,0);// ok (correct)P(C.prototype.method,"method",0);// error (correct)
The converse should also be addressed. If the propertyKey only allows string | symbol, then the decorator should be an error when used on a constructor parameter:
declarefunctionP(target: Function,propertyKey: string|symbol,parameterIndex: number): void;classC{constructor(@Px: any){}// ok (should be an error)method(@Px: any){}// ok (correct)}P(C,undefined,0);// error (correct)P(C.prototype.method,"method",0);// ok (correct)
Parameter decorators do not check target type
In this case, we are not correctly checking the type of the target parameter:
declarefunctionP(target: new(...args: any[])=>any,propertyKey: string|symbol|undefined,parameterIndex: number): void;classC{constructor(@Px: any){}// ok (correct)method(@Px: any){}// ok (should be an error)}P(C,undefined,0);// ok (correct)P(C.prototype.method,"method",0);// error (correct)
And the same issue occurs when target is a function type:
declarefunctionP(target: (...args: any[])=>any,propertyKey: string|symbol|undefined,parameterIndex: number): void;classC{constructor(@Px: any){}// ok (should be an error)method(@Px: any){}// ok (correct)}P(C,undefined,0);// error (correct)P(C.prototype.method,"method",0);// ok (correct)
Constraining the type of a parameter
Constraining the type of a parameter is difficult (but not impossible) now that we have string literal types:
typeWithConstructorParameter<Fextends(new(...args: A)=>any),Iextendsnumber,T,Aextendsany[]=ConstructorParameters<F>>=F&(new(...args: ReplaceArg<A,I,T>)=>any);typeReplaceArg<Aextendsany[],Iextendsnumber,T>={[PinkeyofA]: Pextends `${I}` ? T : A[P]};
However, we again do not seem to check this correctly in decorators:
typeExpected={x: number};declarefunctionP<Fextends(new(...args: any[])=>any),Iextendsnumber>(target: WithConstructorParameter<F,I,Expected>,propertyKey: undefined,parameterIndex: I): void;classC{constructor(@Px: {y: number}){}// ok (should be error)}P(C,undefined,0);// error (correct), because `{ y: number }` is not assignable to `{ x: number }`
This is not a new issue, its likely existed since decorators were added.
The text was updated successfully, but these errors were encountered:
Distilled down the inference example to a subjectively simpler one:
declarefunctiondecorator1(target: MyClass,prop: 'method1',index: 0) : void;declarefunctiondecorator2(target: string,prop: any,index: any): void;declarefunctiondecorator3(target: any,prop: 'wrong',index: any): void;declarefunctiondecorator4(target: any,prop: any,index: 99) : void;classMyClass{method1(@decorator1foo: number){}// ^^^^^^^^^^^ should pass, now `Argument of type 'number' is not assignable to parameter of type '0'`method2(@decorator2foo: number){}// ^^^^^^^^^^^ should fail, now passesmethod3(@decorator3foo: number){}// ^^^^^^^^^^^ should fail, now passesmethod4(@decorator4foo: number){}// ^^^^^^^^^^^ should fail, now fails but for the wrong reason, message is the same as #1}decorator1(MyClass.prototype,'method1',0);// correct, no type errors//decorator2(MyClass.prototype,'method1',0);// correct, type error// ^^^^^^^^^^^^^^^^^decorator3(MyClass.prototype,'method1',0);// correct, type error// ^^^^^^^^^decorator4(MyClass.prototype,'method1',0);// correct, type error// ^
This is more of a meta issue that covers the following existing issues, but with some additional context:
The above issues reference various problems with decorators and decorator type checking. The following are some examples of issues I'd like to address:
Constructor parameter decorators receive
undefined
forpropertyKey
The definition of
ParameterDecorator
indicates thepropertyKey
isstring | symbol
, however constructor parameters receiveundefined
. Receivingundefined
is an intentional behavior, as it allows the decorator author to detect they are decorating a constructor's parameter. However, this is not correctly noted in the definition ofParameterDecorator
. That is the crux of #33260.However, there is more that we should be doing here, as we do not accurately check the type that should be passed for the
propertyKey
argument:The converse should also be addressed. If the
propertyKey
only allowsstring | symbol
, then the decorator should be an error when used on a constructor parameter:Parameter decorators do not check
target
typeIn this case, we are not correctly checking the type of the
target
parameter:And the same issue occurs when
target
is a function type:Constraining the type of a parameter
Constraining the type of a parameter is difficult (but not impossible) now that we have string literal types:
However, we again do not seem to check this correctly in decorators:
This is not a new issue, its likely existed since decorators were added.
The text was updated successfully, but these errors were encountered: