Jespertheend
Jespertheend

Reputation: 2250

How to get types of variables from outside the scope of a functions?

I have a function in which a variable is declared with a reasonably complex structure:

export function foo() {
    const myVar = {
        // some properties with complex types here...
    }

    // Do something with `myVar`
}

And now I wish to export the type of myVar so that I can use it in other files. Is there any way to get type information of scoped variables from outside the function? Something like this:

export type MyVarType = GetVariableFromFunction<typeof foo, "myVar">;

Some more context to avoid the XY problem:

I have created a TypedMessenger class. The purpose of this class is to make it easier to communicate with iframes and workers etc. It works something like this:

import type {TheirHandlers} from "./worker.ts";

const myHandlers = {
    foo(x: number) {
        return x;
    ,
    bar() {
        return "hello";
    },
};
export type MyHandlers = typeof myHandlers;

const messenger = new TypedMessenger<TheirHandlers, MyHandlers>();
messenger.setResponseHandlers(myHandlers);

On the other end you create a similar TypedMessenger but with the two generic parameters flipped. And then you are able to call messenger.send("foo", 3) and it will autocomplete and type check the arguments you passed in.

Now the issue that I'm running into is that I have created a messenger inside a function, and many of these handlers use variables from the scope of that function.

Upvotes: 3

Views: 1598

Answers (1)

Jespertheend
Jespertheend

Reputation: 2250

Unfortunately getting types from outside the scope of a function is not possible right now. There's an open issue for it but it doesn't have any recent activity.

There's a couple of ways you can work around this though:

Declare the type outside of the function scope and export it.

type MyVarType = {
    x: boolean;
    fn: (x: number) => void;
};

export function foo() {
    const myVar = {
        x: true,
        fn: (x: number) => {}
    }
}

The downside of this method is that you have to write your structure twice. First you have to declare the type, and then you have to create the value of the variable. If your variable is complex enough you might want to use one of the other methods.

Declare myVar outside of the function.

const myVar = {
    x: true,
    fn: (x: number) => {}
}
export type MyVarType = typeof myVar;

export function foo() {
    // Do stuff with `myVar`...
}

This works unless you need access to other variables inside your function:

const myVar = {
    fn: (x: number) => {
        console.log(scopedVar); // scopedVar doesn't exist :(
    }
}
export type MyVarType = typeof myVar;

export function foo() {
    const scopedVar = "hello";
    
    myVar.fn(3);
}

Create an extra function and use ReturnType<...>.

function getMyVar(scopedVar: string) {
    return {
        fn: (x: number) => {
            console.log(scopedVar);
        }
    }
}
export type MyVarType = ReturnType<typeof getMyVar>;

export function foo() {
    const scopedVar = "";

    getMyVar(scopedVar).fn(3);
}

As a last resort you can create a function that returns the variable, any scoped variables can be passed in the arguments of getMyVar. And you can get the type of the variable using ReturnType<typeof getMyVar>.

Upvotes: 2

Related Questions