如何从函数范围之外获取变量的类型?

huangapple go评论71阅读模式
英文:

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

问题

我有一个函数,在其中声明了一个具有相对复杂结构的变量:
```typescript
export function foo() {
    const myVar = {
        // 这里有一些具有复杂类型的属性...
    }

    // 对 `myVar` 做一些操作
}

现在我希望导出 myVar 的类型,以便我可以在其他文件中使用它。有没有办法从函数外部获取作用域变量的类型信息?类似这样的方式:

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

为了避免XY问题,提供更多背景信息:

我创建了一个 TypedMessenger 类。这个类的目的是更容易地与iframe和worker等通信。它的工作方式类似于这样:

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);

在另一端,您创建一个类似的 TypedMessenger,但两个泛型参数交换。然后,您可以调用 messenger.send("foo", 3),它将自动完成和类型检查您传递的参数。

现在,我遇到的问题是,我在一个函数内创建了一个messenger,并且其中许多处理程序使用了该函数范围内的变量。


<details>
<summary>英文:</summary>

I have a function in which a variable is declared with a reasonably complex structure:
```typescript
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&lt;typeof foo, &quot;myVar&quot;&gt;;

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 &quot;./worker.ts&quot;;

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

const messenger = new TypedMessenger&lt;TheirHandlers, MyHandlers&gt;();
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(&quot;foo&quot;, 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.

答案1

得分: 2

抱歉,以下是翻译好的内容:

很不幸,目前无法从函数范围之外获取类型。有一个相关的开放问题,但最近没有任何活动。

不过,有几种方法可以解决这个问题:

在函数范围之外声明类型并导出它。

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

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

这种方法的缺点是你必须两次编写结构。首先,你必须声明类型,然后你必须创建变量的值。如果你的变量足够复杂,你可能会想使用其他方法。

在函数之外声明myVar

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

export function foo() {
    // 使用 `myVar` 做一些事情...
}

除非你需要在函数内部访问其他变量,否则这种方法有效:

const myVar = {
    fn: (x: number) => {
        console.log(scopedVar); // scopedVar 不存在 :(
    }
}
export type MyVarType = typeof myVar;

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

    myVar.fn(3);
}

创建额外的函数并使用 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);
}

作为最后的手段,你可以创建一个返回变量的函数,任何作用域变量都可以作为 getMyVar 的参数传递。你可以使用 ReturnType<typeof getMyVar> 获取变量的类型。

英文:

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) =&gt; void;
};

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

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) =&gt; {}
}
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) =&gt; {
		console.log(scopedVar); // scopedVar doesn&#39;t exist :(
	}
}
export type MyVarType = typeof myVar;

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

Create an extra function and use ReturnType&lt;...&gt;.

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

export function foo() {
	const scopedVar = &quot;&quot;;

	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&lt;typeof getMyVar&gt;.

huangapple
  • 本文由 发表于 2023年1月9日 05:59:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/75051577.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定