What is the best way to change the `this` type of an object that is provided as a parameter to a function

I am looking to create a custom function that can expose certain properties to the this of an object being passed as an argument. For example, this is how the function would be called:

const props = ['bar'];
myBarFunction(props, {
    get foo() {
        return fooify(this.bar)
    }
});

In this scenario, I aim to have the bar property accessible within this, even though TypeScript might typically throw an error for not recognizing bar in this.
Vue's defineComponent seems to offer similar functionality. However, implementing this feature in TypeScript or using Vue's Volar extension remains unclear to me.
Is there a way to define a function like myBarFunction to achieve this goal?

Answer №1

To implement this functionality, you must utilize the special ThisType<T> utility type. ThisType<T> is used in an object literal to contextualize the type of the methods' this variable as T. The unique thing about ThisType is that it cannot be defined by users; instead, it is a predefined empty interface {} in the library files and is handled specially by the compiler for contextual typing.

For instance, you can define a function like so:

declare function myBarFunction<K extends string>(
  props: readonly K[],
  obj: ThisType<{ [P in K]: string }>
): void;

In this function, the generic type K represents the key-like elements in the props array. The ThisType of obj is { [P in K]: string }, which is essentially equivalent to Record<K, string> using the Record<K, V> utility type. Thus, any object literal passed as obj will have a this context with string-valued properties based on the keys in the props array.

Let's test this out:

const props = ['bar'] as const; // <-- ensure const assertion

myBarFunction(props, {
  get foo() {
    return fooify(this.bar.toUpperCase()) // works fine
  }
});

It's important to note that when declaring props, you need a const assertion to maintain the literal type 'bar'. Without it, const props = ["bar"] would infer props as string[], losing track of its specific type.

If you hover over this, you'll see its type as {bar: string}.

Check out the Playground link for the code example

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

What are the best ways to utilize @types/bootbox and @types/jquery?

Is there a way to incorporate @types/bootbox and @types/jquery into an Angular 4 project? I attempted the following: npm install @types/bootbox and in my code, I am implementing it like so: import * as bootbox from 'bootbox'. However, I encou ...

Exploring TypeScript nested interfaces and types within VSCode

I often find myself hovering over functions or objects in VSCode with TypeScript to inspect their type. However, many times the types and interfaces of these objects are dependent on other interfaces and types, making it difficult to get detailed informat ...

Include an external JavaScript file within a component to display pictures in a web browser using Angular 2

I am developing a website using Angular 2 and need to incorporate a JavaScript file into a component. The goal is for this script to adjust the height of certain images to match the height of the browser window. What is the best way to integrate this scri ...

Oops! Issue encountered while trying to read the file "src/core/database/config.ts"

Need help with migrating a database in a Node Nest.JS application. When running the npx sequelize-cli db:migrate shell command, I encountered the following exception: Error details: Error: TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".t ...

How can I use JavaScript to sort through an array and organize the data into groups?

Below is an array that I currently have: Status=["active","inactive","pending","active","completed","cancelled","active","completed"] I am looking to achieve the following result: StatusInfo=["active":3,"inactive":2,"pending":1, "completed":2, "cancelle ...

What are the steps for incorporating the AAD B2C functionality into an Angular2 application with TypeScript?

I recently built a web application using Angular2 and TypeScript, but now one of my clients wants to integrate Azure B2C for customer login instead of OAuth. I followed a simple example on how to implement Azure B2C in a .NET Web app through the link provi ...

VS Code sees JavaScript files as if they were Typescript

I have recently delved into the world of Typescript and have been using it for a few days now. Everything seems to be working smoothly - Emmet, linting, etc. However, I've encountered an issue when trying to open my older JavaScript projects in VS Cod ...

Unable to find custom components when using react-router

My goal is to improve the organization of my Routes in React and separate concerns. I am currently utilizing react-router-dom version 5. Within my Application Routes component, I have structured it with 3 children components: AuthenticatedRoutes PublicRo ...

Having trouble deleting a component from an array in React?

I am facing an issue with my array and component functions. Each component has a handleRemove function that is supposed to remove the selected component from the array. However, the function is not working as expected. Instead of deleting just the selected ...

Exploring the TypeScript handbook: Utilizing rootDirs for Virtual Directories

Exploring the concept of Virtual Directories with rootDirs in the handbook, we find an interesting example demonstrating how modules can be imported from different source folders by combining multiple rootDirs. // File Structure src └── views ...

Attempting to showcase information on the Angular frontend

When attempting to retrieve the Street name, I am seeing [object Object]. What is the optimal approach for displaying JSON data on the client side? I managed to display a street name but struggled with other components. How can I access the other elements ...

Having trouble getting TypeScript to compile on Visual Studio Online TFS?

Currently, I am utilizing Typescript 1.7 within an MVC environment. Locally, my Typescript functions properly and compiles without any issues. However, when integrating with visualstudioonline TFS for continuous integration to an azure website, I have enc ...

Leveraging NPM workspaces in combination with Expo and Typescript

I'm struggling to incorporate NPM 7 workspaces into a Typescript Expo project. The goal is to maintain the standard Expo structure, with the root App.tsx file, while segregating certain code sections into workspaces. I'm facing challenges compil ...

Typescript's ability to have Enums with dynamic keys

Suppose I define: enum Sort { nameAsc = 'nameAsc', nameDesc = 'nameDesc' } Is it possible to do the following? const key = 'name' + 'Desc'; Sort[key] Appreciate any help in advance ...

Unable to modify the Express Request User type, however, I have the ability to incorporate new attributes to Request object

Encountering a familiar issue with what appears to be a simple fix. The Express Request object includes a user property that is specified as Express.User (an empty object). Attempting the common approach to redefining it: // index.d.ts import { User as P ...

When using Playwright, there may arise a requirement to reuse a specific UUID that has been defined in one test within another

I have two separate tests running in parallel, each creating a different company in my test environment. However, I need to access the uuid of both companies in later tests. I am looking for a way to store these uuids so they can be used across all subseq ...

Is error propagation from nested Promise to parent Promise not working properly in Node.js?

I'm currently working on a Node.js/TypeScript API with Express. Below is a snippet from my get method where I encountered an error in the format function. The error is caught by the promise, but it doesn't propagate to the parent promise after th ...

The identifier "id" is not a valid index for this type

The code snippet below demonstrates the similarities and differences between the functions addThingExample2 and addThing. While addThingExample2 directly uses the union type Things, addThing utilizes a generic parameter THING extends Thing. The expression ...

What is the reason for the variance in the inferred generic type parameter between an extended interface and a type alias representing an intersection of interfaces?

Why is the generic type parameter inferred differently in the following toy experiment, depending on whether the template is instantiated with an extended type or with an intersected type? This experiment has been simplified from a real-world example. inte ...

Assign a true or false value to every attribute of an object

Imagine we have a scenario with an interface like this: interface User { Id: number; FirstName: string; Lastname: string; Age: number; Type: string; } and a specific method for copying properties based on a flag. ...