What is the technique for retrieving variable types from beyond the function's scope?

I am facing a challenge with a function where I have declared a variable with a somewhat complex structure:

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

    // Do something with `myVar`
}

Now, I want to export the type of myVar so that I can utilize it in other files. Is there a way to obtain type information of scoped variables from outside the function? Something similar to this:

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

Providing additional context to avoid the XY problem:

I have developed a TypedMessenger class. This class is aimed at simplifying communication with iframes and workers. It functions as follows:

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 recipient end, you create a similar TypedMessenger but with the two generic parameters flipped. Subsequently, you can use messenger.send("foo", 3) to trigger autocompletion and type checking for the arguments passed in.

The issue arises as I have instantiated a messenger within a function, and several handlers within it rely on variables from the function's scope.

Answer №1

Regrettably, accessing types from outside the scope of a function is currently not supported. There is an ongoing issue regarding this, although there has been no recent activity on it.

There are several workarounds that you can use:

Define 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) => {}
    }
}

One drawback of this approach is having to define your structure twice – first as a type and then as a variable's value. For more complex variables, consider using one of the alternative methods.

Declare myVar outside of the function.

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

export function foo() {
    // Perform operations with `myVar`...
}

This method works well unless you require access to other variables within the function:

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

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

Create an additional function and utilize 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);
}

If all else fails, you can create a function that returns the variable, passing any scoped variables as arguments in getMyVar. The variable's type can be obtained using

ReturnType<typeof getMyVar>
.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Encountering a module error when using SignalR with Webpack and TypeScript: 'Unable to locate module './NodeHttpClient''

I am currently working on integrating a SignalR client into an Angular application using Webpack and TypeScript. Here is the content of my package.json file: { "private": true, "version": "0.0.0", "scripts": { "test": "karma start ClientApp/tes ...

Utilizing ConcatMap in conjunction with an internal loop

I am having a coding issue where I need certain requests to run sequentially, but some of the responses are observables. The data is mainly retrieved except for two requests that need to be executed in a loop for each account. I am using concatMap and fork ...

Converting React to Typescript and refactoring it leads to an issue where the property 'readOnly' is not recognized on the type 'IntrinsicAttributes & InputProps & { children?: ReactNode; }'

I'm currently in the process of refactoring an application using Typescript. Everything is going smoothly except for one particular component. I am utilizing the Input component from the library material-ui. import {Input} from "material-ui"; class ...

Encountering an issue while trying to load a file from an API due to difficulties in parsing it to

When trying to load an xlsx file from an API, I encountered an error because Angular automatically tries to parse the body as JSON. To resolve this issue, I found that specifying the response type directly in the request works: this.http.get(this.url + " ...

Can getters and setters be excluded from code coverage reports in Angular projects?

Looking to clean up my coverage reports for the front end portion of an angular project by removing trivial code like getters and setters. I generate my reports using npm run test-sonar -- --coverage, but everything is included in the report when I view ...

TSX implementation of a paginator with an ellipse in the center

Looking to add ellipses in the Pagination, specifically when there are more than 10 pages (e.g., 1 2 3 4 ... 11 12 13 14). I've tried various methods but need guidance as a beginner. Can anyone suggest changes based on my code to help me achieve this? ...

Leveraging external data within the constructor of a Knockout.JS observableArray item

I am working on a bar that shows a dynamic number of sub-bars with varying values. The total width of the bar remains constant. Whenever a value changes, I need to recalculate the widths of all sub-bars based on the new total sum of values. These sub-bars ...

An irritating problem with TypeScript-ESLint: when a Promise is returned without being resolved

Check out this TypeScript snippet I've simplified to showcase a problem: import * as argon2 from "argon2"; export default async function(password:string):Promise<string> { return argon2.hash(password, { type: argon2.argon2id, ...

What methods can I utilize from Google Maps within Vuex's createStore()?

Currently, I am in the process of configuring my Vuex store to hold an array of Marker objects from the Google Maps Javascript API. Here is a snippet of how my createStore function appears: import { createStore } from "vuex"; export default ...

How should I structure my MySQL tables for efficiently storing a user's preferences in a map format?

My current project involves developing a web application that provides administrators with the ability to manage user information and access within the system. While most user details like name, email, and workID are straightforward, I am facing difficulty ...

Issues with applying different styles in a React Component based on prop values are hindering the desired outcome

I am currently working on a Display component that is supposed to show an item. The item should be styled with the css property text-decoration-line, applying line-through when the Available prop is set to false, and no decoration when set to true. Howev ...

Each styled component will yield the respective type definitions using (@types/styled-components)

Encountering a strange problem with styled-components in VSCode. Every component from styled-components is returning 'any'. https://i.sstatic.net/0kFJw.png https://i.sstatic.net/S20cS.png I had it working previously, but unsure when it stopped ...

Updating nullable columns in typeorm entities: a step-by-step guide

Within my typeorm entity, there is a column defined as: @Column({ type: 'bigint', nullable: true, }) lockedTimestamp?: number; In my nest.js code, I am trying to handle it like this: if (...) {entity.lockedTimesta ...

Error: Missing 1 type argument(s) in generic type definition

I've developed an abstract class structure as shown below: export abstract class CsvFileReader<T> { data: T[] = [] constructor(public file: string) {} abstract mapRow(row: string[]): T read() { this.data = this.file .split(& ...

Leveraging TypeScript enums in conjunction with React to anticipate a string prop

Trying to enforce strict typing for a Button component in React. How can I ensure a prop has a specific string value? The current effort yields Type '"primary"' is not assignable to type 'ButtonLevel' enum ButtonLevel { Primary = ...

What is the best way to share a configuration value retrieved from the back end across all components of an Angular 6 application?

In the Web API's Web.config file, I have defined configurations like MAX_FILE_SIZE and others. I want to retrieve these configurations from the backend and make them available to all Angular 6 components globally. Could someone suggest the most effect ...

Unable to loop through the Array

let Users = [ { name: 'John', id: '1', jp: 'USA' }, { name: 'Jane', id: '2', jp: 'Japan' }, ]; export function DisplayUsers(usersList) { return ( <div> {usersList?.map((user ...

Tips for creating dynamic alerts using mui v5 Snackbar

My goal is to call an API and perform several actions. After each action, I want to display the response in a Snackbar or alert. Despite iterating through the messages in a map, I'm only able to show the first response and none of the others. Here is ...

When the nestjs interface appears to be missing a defined method

Upon reviewing the code at this link: https://github.com/nestjs/nest/tree/master/packages/common One can see that the interface ArgumentsHost has been defined, but the contents of its methods are not explicitly defined. However, when looking at the foll ...

Can a TypeScript generic version of the Y-combinator be successfully executed?

Here is an interesting JavaScript implementation of the Y-combinator: const Y = g => (x => g(x(x)))(x => g(x(x))) //or const Y = f => { const g = x => f(x(x)) return g(g) } I've been thinking, could it be possible to create a TypeS ...