What is the proper way to specify the type for a proxy that encapsulates a third-party class?

I have developed a unique approach to enhancing Firestore's Query class by implementing a Proxy wrapper. The role of my proxy is twofold:

  1. If a function is called on the proxy, which exists in the Query class, the proxy will direct that function call to the Query class.
    • If the Query class returns another instance of itself (such as when using .where()), instead of returning the Query instance directly, my proxy envelops it in another layer of proxy.
    • On the other hand, if the return type is not another Query instance (for example, with .onSnapshot()), the result is seamlessly passed back to the method caller without additional wrapping.
  2. In addition to forwarding existing methods, my proxy also includes some custom methods for added convenience.

Initially, I defined the type structure as follows:

interface MyInterface { /* custom methods here */ }
type Store = MyInterface & FirebaseFirestore.Query

While this setup allows TypeScript to recognize query-method availability within the store, it does not explicitly convey that all query method return types are encompassed within the Store type. How can I accurately convey this information to TypeScript?

Answer №1

It seems like a solution along these lines could work for you:

interface DataSnapshot {}

interface Utility {}

interface QueryInterface {
  where(condition: number): QueryInterface;
  onSnapshot(): DataSnapshot;
}

type ProxyHandler<T> = {
  [Key in keyof T]: T[Key] extends (...args: any) => T
    ? (...args: Parameters<T[Key]>) => ProxyHandler<T>
    : T[Key]
};

interface ExtendedProxy {
  newMethod(): Utility;
}

let dynamicProxy: ProxyHandler<QueryInterface> & ExtendedProxy;

dynamicProxy.onSnapshot(); // DataSnapshot
dynamicProxy.where(2); // Proxy<QueryInterface>
dynamicProxy.newMethod(); // Utility

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

Simulating TypeDI service behavior in Jest

My current setup includes Node with TypeScript, TypeDI and Jest. I've been working on creating services that have dependencies on each other. For example: @Service() export class MainService{ constructor(private secondService: SecondService){} public ...

What factors contribute to 'tslib' having more downloads than 'typecrypt'?

How is it possible that 'tslib', a library for 'typescript', has more downloads than 'typescript' itself? If one does not use 'typescript', then they cannot utilize 'tslib' as well. Just because someone us ...

Guide to typing a new version of a function without any optional parameters using a mapped tuple

I am attempting to create a modified version of a function that has the same arguments as the original function, but with none being optional. I have tried using a mapped tuple approach with the following logic: type IFArgs = ArgsN<typeof getFunc> t ...

What is the best way to enable code sharing between two TypeScript projects housed within the same repository?

Our project has the following structure: api (dir) -- package.json -- tsconfig.json -- src (dir) -- client (dir) ---- package.json ---- tsconfig.json ---- src (dir) The "client" directory houses a create-react-app project that proxies to the API d ...

When a parameter is passed into a React-Query function with an undefined value, it can lead to the API returning a 404 error

Two parameters are sent from the frontend to trigger a GET request in another TypeScript file. It seems that one of the parameters is not successfully passed due to unknown rerenders, resulting in a 404 Error being returned by the API call in the console. ...

Optimizing the sorting of object properties based on specific values (numbers or strings)

My goal is to simplify the process of sorting both number and string values. The first step involves checking if the parameter I've passed (which belongs to the DeliveryDetailsColumns constants) matches another parameter from a different type (Electro ...

What is the proper way to declare a Type for a JSX attribute in Google AMP that utilizes square brackets?

When utilizing AMP's binding feature, you must apply specific attributes that encapsulate an element's property with square brackets and connect it to an expression. An example from AMP is shown below: <p [text]="'Hello ' + foo"> ...

An error persists in PhpStorm inspection regarding the absence of AppComponent declaration in an Angular module

After creating a new Angular application, I am encountering the issue of getting the error message "X is not declared in any Angular module" on every component, including the automatically generated AppComponent. Despite having the latest version of the An ...

What are the different ways to customize the appearance of embedded Power BI reports?

Recently, I developed a website that integrates PowerBI embedded features. For the mobile version of the site, I am working on adjusting the layout to center the reports with a margin-left style. Below are the configuration parameters I have set up: set ...

The test.ts file does not contain any type definitions

While I am able to successfully utilize my types in .ts files, I am facing difficulties in understanding why it's failing in .test.ts files, even though both files are located in the same folder. Check out the code in the .ts file below: https://i.s ...

Reactivity in Angular Autocomplete with API Integration

I went through all the tutorials on Angular Autocomplete using API to follow the steps. I implemented valueChanges to monitor the form control, used switchMap to send a new request with each keyword change, and then displayed the data in the autocomplete d ...

Why is my custom Vuelidate validator not receiving the value from the component where it is being called?

On my registration page, I implemented a custom validator to ensure that the password meets specific criteria such as being at least 12 characters long and containing at least one digit. However, I encountered an issue where the custom validator was not r ...

Having trouble updating state with useEffect in a React functional component

Currently, I am dealing with a React functional component that is calling an API to fetch data. The response from the API call is confirmed to be received successfully. My aim is to store this data in an array within the component's state so that it c ...

Create interfaces for a TypeScript library that is available on npm for export

I have a project in TypeScript that I am packaging as a library to be used by both JavaScript and TypeScript projects. After compiling, I upload the .js and .d.ts files to npm. The main.ts file exports the following: interface MyInterface{ // ... } clas ...

Fastest method to invoke a potentially undefined function

With a background in C#, I am familiar with the null-conditional operator which allows you to call a function while avoiding a potential null-reference exception like this: Func<int> someFunc = null; int? someInteger = someFunc?.Invoke(); // someInte ...

Outputting double columns with Typescript Sequelize associations

I am currently in the process of constructing table models using sequelize along with typescript. Here is an example of one of my models: 'use strict'; import { Model, InferAttributes, InferCreationAttributes, CreationOptional } from 'seque ...

Angular 2 - Dependency Injection failing to function

I have created two different implementations for an interface and assigned them as providers for two separate components. However, I am encountering the following error: Error: Can't resolve all parameters for ChildComponent: (?). What could be the i ...

Using MUI-X autocomplete with TextField disables the ability to edit cells

When I double-click on a cell, everything works fine. However, after the second click to start editing the textfield, the cell stops editing. I can still choose an option though, so I believe the issue lies somewhere in the textField component, possibly i ...

Checking for the existence of a value in an object using Angular loops

I am seeking assistance in verifying the presence of a specific value within an object. My Object = (vagas.etapas) "Etapas" : { "05daf060-87cb-47cf-8c98-65b36941613d" : "Name 1", "0bf7aabf-42df-4f7d-86dc-af81e6cef394 ...

Setting default values and specifying available values for a class property in TypeScript

I'm curious about how to set a default value for a class property, as well as define all available values at once. For example: class MyClass{ isActive = -1; //Setting default value } class MyClass{ isActive: -1 | 0 | 1; //Defining all available ...