Veetaha
Veetaha

Reputation: 862

How to limit the type of parameter that the given parameter decorator may be applied to

There is currently a way to limit the type of property that the given property decorator may be applied to. E.g.

type PropertyDecorator<TPropType = unknown> = (
    <
        TPropName     extends string | symbol,
        TProtoOrClass extends Record<TPropName, TPropType>
    >
    (protoOrClass: TProtoOrClass, propName: TPropName) => void
);

function boolPropertyDecorator(): PropertyDecorator<boolean> {
    return () => {};
}

class Foo {
    // compile-time error "Type 'number' is not assignable to type 'boolean'"
    @boolPropertyDecorator()       
    prop!: number;

}

But I can't manage to leverage such a type checking for method parameter decorators.

type ParameterDecorator<TParamType = unknown> = (
    <
        TMethodName   extends string | symbol,
        TParamIndex   extends number,
        TProtoOrClass extends Record<
            TMethodName, 
            (this: TProtoOrClass, ...args: unknown[] & Record<TParamIndex, TParamType>) => unknown
        >

    >
    (
        protoOrClass:   TProtoOrClass, 
        methodName:     TMethodName, 
        parameterIndex: TParamIndex
    ) => void
);


function numberParameterDecorator(): ParameterDecorator<number> {
    return () => {};
}

class Foo {
    // no decorator-related error message is generated, but should!
    method(@numberParameterDecorator() str: string) {}
}

I can't say for sure why this happens. Is it a TypeScript bug with parameter decorators? Why is there no error message? Is it somehow related to annihilating unit types (e.g. TParamIndex or TParamName)?

Upvotes: 2

Views: 233

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249506

Your assumption is that TMethodName and TParamIndex get inferred to their literal type versions based on usage. They unfortunately don't for parameter decorators (for method decorators the method name does get inferred to the string literal of the method name, so it's at least an inconsistency in the way they are handled).

There is a GitHub issue around this, I even have a version of the typescript compiler code that would do this linked in the issue, but unfortunately it does not seem to be a priority at the moment for the team to incorporate this.

Priorities also change based on feedback, so feel free to upvote the issue, maybe comment about your use case as that will help the team see that there is a real need for this.

Upvotes: 1

Related Questions