最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

typescript - TS cannot infer a class instance method prop name in a static method - Stack Overflow

programmeradmin5浏览0评论

Trying to make a static method that accept only instance method prop names, unfortunately out of ideas how to make this work with the following case. Any thoughts (please no type assertion in the call signature)?

Playground

type MethodKeys<T extends object> = keyof { [K in keyof T as T[K] extends (...args: any) => any ? K : never]: unknown };

class Model{ 
    static chainMethod<C extends typeof Model, T extends InstanceType<C>, K extends MethodKeys<T>>
        (this: C, name: K, method: T[K]) {
        
        }
    method(){

    }
}

class Party{
    static addProps<C extends typeof Model>(model: C){
        model.chainMethod('method', function(){ // error

        })
    }
}

Another try:

Playground

class Model{ 
    static chainMethod<C extends typeof Model, T extends InstanceType<C>, K extends keyof T, F extends T[K] extends (...args: any) => any ? T[K]: never>
        (this: C, name: K, method: F) {
        
        }
    method(){

    }
}

class Party{
    static addProps<C extends typeof Model>(model: C){
        model.chainMethod('method', function(){

        })
    }
}

UPDATE
Matt Kantor has solved the second solution, but I would still prefer the first one where autocomplete would show only method names

Trying to make a static method that accept only instance method prop names, unfortunately out of ideas how to make this work with the following case. Any thoughts (please no type assertion in the call signature)?

Playground

type MethodKeys<T extends object> = keyof { [K in keyof T as T[K] extends (...args: any) => any ? K : never]: unknown };

class Model{ 
    static chainMethod<C extends typeof Model, T extends InstanceType<C>, K extends MethodKeys<T>>
        (this: C, name: K, method: T[K]) {
        
        }
    method(){

    }
}

class Party{
    static addProps<C extends typeof Model>(model: C){
        model.chainMethod('method', function(){ // error

        })
    }
}

Another try:

Playground

class Model{ 
    static chainMethod<C extends typeof Model, T extends InstanceType<C>, K extends keyof T, F extends T[K] extends (...args: any) => any ? T[K]: never>
        (this: C, name: K, method: F) {
        
        }
    method(){

    }
}

class Party{
    static addProps<C extends typeof Model>(model: C){
        model.chainMethod('method', function(){

        })
    }
}

UPDATE
Matt Kantor has solved the second solution, but I would still prefer the first one where autocomplete would show only method names

Share Improve this question edited Mar 22 at 13:07 Alexander Nenashev asked Mar 22 at 12:21 Alexander NenashevAlexander Nenashev 24.7k3 gold badges10 silver badges28 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 4

I believe this has the behavior you want:

Playground

class Model{ 
    static chainMethod<C extends typeof Model, K extends keyof InstanceType<C>, F extends InstanceType<C>[K]>
        (this: C, name: K, method: F & ((...args: never) => unknown)) {
        
        }
    nonMethod?: string
    method(){

    }
}

class Party{
    static addProps<C extends typeof Model>(model: C){
        model.chainMethod('method', function(){})

        // these should all have errors:
        model.chainMethod('method', function(x: string){})
        model.chainMethod('nonMethod', 'test')
        model.chainMethod('nonExistentKey', function(){})
    }
}

It's a good rule of thumb to use as few type parameters as possible in generic function types. I also replaced your conditional type (to check method-ness) with an intersection, as that's simpler for the type checker to reason about.


As per your update, here's another version with different autocomplete behavior:

Playground

type MethodKeys<T> = keyof {
    [K in keyof T as T[K] extends (...args: never) => unknown ? K : never]: unknown
}

class Model{ 
    static chainMethod<T extends Model, K extends MethodKeys<T>, F extends T[K]>
        (this: abstract new (...args: never) => T, name: K, method: F) {
        
        }
}
发布评论

评论列表(0)

  1. 暂无评论