question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Infer method name for parameter decorator

See original GitHub issue

TypeScript Version: 3.3.3 Tried with @next (3.4.0-dev.201xxxxx) ? NO

Search Terms: type:issues infer method name parameter decorator

Code

declare function Method():
{
    (t: any, m: 'method'): void;
}

declare function Parameter():
{
    (t: any, m: 'method', i: number): void;
}

class Play
{
    @Method() // err
    public another_method ( @Parameter() /* NO ERROR */ test: number ): void
    {
        throw new Error('Not yet implemented');
    }
    @Method()
    public method ( @Parameter() test: number ): void
    {
        throw new Error('Not yet implemented');
    }
}

Expected behavior: @Parameter() should error just as @Method() when applied to another_method() because the m parameter is typed "method" (which should reduced the set of method). i.e method name should be enforced.

Actual behavior: No error

Playground Link: https://typescript-play.js.org

Use case :

I crafted a type that filters method names with the nth parameters iff that parameters is of the given type T.

See KeysToTypedNthParameter definition here

let hash = {
    a( _0: string, _1: string ) {},
    b( _0: string, _1: number ) {},
    c( _0: number, _1: number ) {},
    d( _0: number, _1: string ) {},
}

let string_0: KeysToTypedNthParameter<0, string, typeof hash>; // "a" | "b"
let string_1: KeysToTypedNthParameter<1, string, typeof hash>; // "a" | "d"
let number_0: KeysToTypedNthParameter<0, number, typeof hash>; // "c" | "d"
let number_1: KeysToTypedNthParameter<1, number, typeof hash>; // "c" | "d"

Later, I used that type to infer method name for my parameter decorator - @Inject - in the excerpt below, I marked the ONLY line that should error and why (but both lines actually error)

class Test
{
    public blatantly!: boolean;
}

class Play
{
    public method(
        @Inject({ type: Test })
        @Inject({ type: Number }) // err (construtor mismatch instance type)
        test: Test,
    ): void
    {
        throw new Error( 'Not yet implemented' );
    }
}
Play;

Here is @Inject decorator definition and complete code -

const Inject: InjectLike = void 0 as unknown as InjectLike;

interface InjectLike
{
    <
        C extends ConstructorLike,
    >
    ({}: { type: C }): {
        <
            // FIXME : not enough to infer the method name - see ./__playground.ts#
            M extends ( T extends ConstructorLike ? never : KeysToTypedNthParameter<I, InstanceType<C>, T> ),
            I extends number,
            T,
        >
        ( target: T, member: M, index: I ): void;
    };
}

Issue Analytics

  • State:open
  • Created 5 years ago
  • Reactions:4
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

3reactions
dragomirtitiancommented, Apr 1, 2019

Hi any movement on this? Now that the 3.4 release rush is over can I submit a PR with the code I have for this (@DanielRosenwasser , @RyanCavanaugh, @rbuckton) ?

3reactions
dragomirtitiancommented, Mar 6, 2019

@rbuckton @RyanCavanaugh

Just as an experiment I made the changes we (me an @SalathielGenese) think are required, you can see them here

These changes do the following:

  1. For parameterIndex the number literal type is used instead of number
  2. For propertyKey the literal type is used instead or undefined if the decorator is used on a constructor parameter
  3. For target the actual type of the target is passed in, like it is for method decorators.

Uses cases enabled:

  1. We can restrict a parameter decorator based on the target (we can restrict the decorator to only be applied on a constructor, or a instance method or a static method)
  2. We can restrict a parameter decorator based on the type of the parameter type.
type FilterKeysByMethodArg<T, TIndex extends number, TParam> = {
    [P in keyof T] : T[P] extends (...p: infer A) => any ? 
        A extends Record<TIndex, TParam> ? P: never: never
}[keyof T]
declare function TypedParameter<TParam>():
{
    <T extends Record<TName, (...p: any[]) => any>, TIndex extends number, TName extends FilterKeysByMethodArg<T, TIndex, TParam>>(t: T, m: TName, pIndex: TIndex): void
}
class Play
{
    public method (
        @TypedParameter<string>() o: number, //  err
        @TypedParameter<number>() test: number // ok 
    ): void
    {
        throw new Error('Not yet implemented');
    }
}

Problems:

  1. Since propertyKey can be typed undefined the lib version of ParameterDecorator is not really correct anymore, propertyKey should be string | symbol | undefined
  2. Some existing decorators may raise compile time errors now when used on constructor parameters (since propertyKey will be typed as undefined in this case). I would argue this is correct behavior, since undefined was always a possible value for the propertyKey parameter.
Read more comments on GitHub >

github_iconTop Results From Across the Web

Is there any type inference for method decorator in TypeScript?
There are many cases where TypeScript undertakes contextual typing, but this isn't one. Add the type annotation to the parameter:
Read more >
Documentation - Decorators - TypeScript
A Decorator is a special kind of declaration that can be attached to a class declaration, method, accessor, property, or parameter. Decorators use...
Read more >
TypeScript - Parameter Decorator - LogicBig
A parameter decorator is applied on a method/constructor parameter declaration. The parameter decorator function is called with the ...
Read more >
A Complete Guide to TypeScript Decorators - Disenchanted
Property Decorators · @Params: target : Either the constructor function of the class for a static member,. or the prototype of the class...
Read more >
Chapter 5. Decorators and advanced types - TypeScript Quickly
a special kind of declaration that can be attached to a class declaration, method, accessor, property, or parameter. Decorators use the form @expression ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found