Home > Net >  How to use a custom method to call inner object method in object will typed in typescript?
How to use a custom method to call inner object method in object will typed in typescript?

Time:09-06

I want to access my method property in object by called this.getMethod just like below:

function defineObj(params) {
    // `enhanced` will add `getMethod` to params.__prop__
    return enhanced(params)
}

let obj = defineObj({
    methods: {
        foo: (num) => num,
        bar() {
            this.getMethod('foo', 1) // will call as `this.methods.foo(1)`
        }
    }
}) 

Now, I am plan to move those codes to Typescript and get type hinting.

when I call this.getMethod('foo', '1'), I want IDE tell me, I should use number instead of string. And I just want to knew how to use Typescript's Type to complete it.

I wrote codes to do that, but failed.

I am trying to define this context of methods by use CtrlContext. So I can use this.getMethod in function body of methods.foo.

type CtrlContext<M> = {
    getMethod: <T extends keyof M>(name: T, ...params:  M[T] extends (...arg: infer S2) => infer S1 ? S2 : any[] ) => any
}

type Methods<M> = {
    [K in keyof M]: (this: CtrlContext<M>, ...params: any) => ReturnType<any>
}

type Ctrls<M> = {
    methods: Methods<M>
}

function defineObj<M>(params: Ctrls<M>) {
    return params
}

defineObj({
    methods: {
        foo: (num: number) => num,
        foo2: (num1: number, str: string) => num,
        bar() {
            this.getMethod("foo", ) // Now, the second param is any, not number.
        }
    }
})

export default {}

enter image description here

codes online

Now, I can get type hinting of first parameter, but can't get function parameter hinting after I input first parameter. Is there some way to solve it ?

CodePudding user response:

I did not see definition of getMethod() method in your code. For type parameters. You can simply define them in the method declaration itself.

getMethod(name: string, value: number) {
}

and then, If you will assign second param as a string while calling. Typescript will give the error.

this.getMethod('foo', '1') ❌

this.getMethod('foo', 1) ✅

CodePudding user response:

I'm not sure of TypeScript's capabilities to do what you want. Someone else might have a better idea.

However, you could always wrap these methods such that it appears as a regular TypeScript function, that way it looks nicer to the outside and can also incorporate type safety.

class Wrapper {
  constructor(getMethod) {
    this.getMethod = getMethod;
  }

  foo(n: number) {
    this.getMethod("foo", n);
  }

  // include all other methods here
}

This is obviously a very tedious task and might not be suitable for your use-case, but I thought it was worth mentioning anyway.

You might be able to create a code generation tool for this as well.

CodePudding user response:

I solved by use ThisType and this example.

type AnyFunction = (...args: any) => any

type CtrlContext<M> = {
    getMethod: 
    <T extends keyof M>(name: T, ...params: Parameters<T extends keyof M ? M[T] extends AnyFunction ? M[T] : never : never>) => 
        ReturnType<T extends keyof M ? M[T] extends AnyFunction ? M[T] : never : never>
}

type Methods<M> = {
    [T in keyof M]: M[T]
}

type Ctrls<M> = {
    methods: Methods<M> & ThisType<CtrlContext<M>>
}

function defineObj<M>(params: Ctrls<M>) {
    return params
}

defineObj({
    methods: {
        foo(num: number) {
            return num
        },
        bar() {
            const val = this.getMethod("foo", 1)
                        // ^ (property) getMethod: <"foo">(name: "foo", num: number) => number

        }
    }
})

online

  • Related