Creating a specialized TypeScript interface by extending a generic one

Create a customized interface using TypeScript that inherits from a generic interface by excluding the first parameter from all functions.

Starting with the following generic interface:

interface GenericRepository {
  insertOne<E>(entity: Type<E>, body: E): Promise<string>;

  find<E>(entity: Type<E>, qm: Query<E>): Promise<E[]>;
}

interface Type<T> extends Function {
  new (...args: any[]): T;
}

type Query<E> = {
  [K in keyof E]: E[K];
};

class User {
  firstName?: string;
}

class Company {
  name?: string;
}

The goal is to dynamically generate specific interfaces such as:

interface UserRepository {
  insertOne(body: User): Promise<string>;

  find(qm: Query<User>): Promise<User[]>;
}

interface CompanyRepository {
  insertOne(body: Company): Promise<string>;

  find(qm: Query<Company>): Promise<Company[]>;
}

The current code snippet is incomplete and fails to properly infer types for the specific interfaces. Here's an attempt:

type SpecificRepository<E> = {
  [K in keyof GenericRepository]: Fn<GenericRepository[K], E>;
};

type Fn<A extends (...args: any[]) => any, E> = (...a: Params<Parameters<A>>) => ReturnType<A>;

type Params<T extends any[]> = T extends [infer F, ...infer L] ? L : never;


const userRepository = {} as SpecificRepository<User>;
const companyRepository = {} as SpecificRepository<Company>;

When testing the generated types:

async function someMethod() {
  const foundUsers = await userRepository.find({});
}

The type of foundUsers turns out to be unknown[] instead of User[]. How can this be resolved?

Answer №1

Congratulations on reaching this point! To enhance TypeScript's inference capabilities, consider making the interface generic instead of just its member function. By doing so, you can eliminate the need for subclassing:

interface CustomRepository<E> {
  add(entity: Type<E>, data: E): Promise<string>;

  search(entity: Type<E>, query: Query<E>): Promise<E[]>;
}

interface Type<T> extends Function {
  createInstance(...args: any[]): T;
}

type Query<E> = {
  [Key in keyof E]: E[Key];
};

class Customer {
  fullName?: string;
}

class Product {
  productName?: string;
}

const customerRepo = {} as CustomRepository<Customer>;
const productRepo = {} as CustomRepository<Product>;

async function executeOperation() {
  const matchingCustomers = await customerRepo.search({});
}

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

Exploring the capabilities of UIGrid in conjunction with TypeScript DefinitelyTyped has been a

I've noticed that the latest release of UI Grid (RC3) has undergone significant architectural changes compared to nggrid. I am encountering some problems with the definitelytyped files for nggrid because they are from a different version. Will there ...

Exploring the implementation of query parameters in Nest.js

I am currently a freshman in the world of Nest.js. Below is an excerpt from my code: @Get('findByFilter/:params') async findByFilter(@Query() query): Promise<Article[]> { } I have utilized Postman to test this specific router. ht ...

Is there a way to omit type arguments in TypeScript when they are not needed?

Here is a function I am currently working with: function progress<T>(data: JsonApiQueryData<T>): number { const { links, meta } = data.getMeta(); if (!links.next) { return 1; } const url = new URL(links.next); return parseInt(url ...

Intellisense in VS Code is failing to work properly in a TypeScript project built with Next.js and using Jest and Cypress. However, despite this issue,

I'm in the process of setting up a brand new repository to kick off a fresh project using Next.js with TypeScript. I've integrated Jest and Cypress successfully, as all my tests are passing without any issues. However, my VSCode is still flagging ...

What is the correct way to use Observables in Angular to send an array from a Parent component to a Child

Initially, the task was to send JSON data from the parent component to the child component. However, loading the data through an HTTP request in the ngOnInit event posed a challenge as the data wasn't being transmitted to the child component. Here is ...

Incorporate a fresh element into an object after its initial creation

Hello, I am looking to create an object in JavaScript that includes an array-object field called "Cities." Within each city entry, there should be information such as the city's name, ID, key, and a District array object containing town data for that ...

Sharing interfaces and classes between frontend (Angular) and backend development in TypeScript

In my current project, I have a monorepo consisting of a Frontend (Angular) and a Backend (built with NestJS, which is based on NodeJS). I am looking to implement custom interfaces and classes for both the frontend and backend. For example, creating DTOs s ...

Utilizing TypeScript in an AngularJS (1.x) project alongside Webpack: A Step-By-Step Guide

Currently, I am working through the official guide on transitioning from AngularJS (1.x) to Angular (2+). I have successfully divided my application into Components and integrated ES6 with Webpack as the module loader. However, I now find myself unsure of ...

How can you toggle the selection of a clicked element on and off?

I am struggling with the selection color of my headings which include Administration, Market, DTA. https://i.stack.imgur.com/luqeP.png The issue is that the selection color stays on Administration, even when a user clicks on another heading like Market. ...

The issue persists in VSCode where the closing brackets are not being automatically added despite

Recently, I've noticed that my vscode editor is failing to automatically add closing brackets/parenthesis as it should. This issue only started happening recently. I'm curious if anyone else out there has encountered this problem with their globa ...

Unleashing the full potential of Azure DevOps custom Tasks in VS Code and TypeScript: A guide to configuring input variables

Scenario: I have developed a custom build task for Azure DevOps. This task requires an input parameter, param1 The task is created using VS Code (v1.30.1) and TypeScript (tsc --version state: v3.2.2) Issue During debugging of the task, I am unable to pr ...

The Typescript module in question does not contain any exported components or functions related to

I've encountered an unusual issue while working on a React, Redux TypeScript application. It seems that after making some changes, one of the modules has stopped exporting its members. Here is the folder structure: src |---- components |---- contain ...

Demonstrating reactivity: updating an array property based on a window event

One example scenario involves setting specific elements to have an active class by assigning the property "active" as true (using v-bind:class). This property is modified within a foreach loop, after certain conditions are met, through the method "handleSc ...

A comprehensive guide on enabling visibility of a variable within the confines of a function scope

In the code snippet shown below, I am facing an issue with accessing the variable AoC in the scope of the function VectorTileLayer. The variable is declared but not defined within that scope. How can I access the variable AoC within the scope of VectorTile ...

Generating instances using TypeScript generics

Looking to create a factory for instantiating classes with generics. After checking out the TypeScript docs, everything seems to work as expected. Here's a simplified version of how it can be done: class Person { firstName = 'John'; ...

Troubleshooting Angular MIME problems with Microsoft Edge

I'm encountering a problem with Angular where after running ng serve and deploying on localhost, the page loads without any issues. However, when I use ng build and deploy remotely, I encounter a MIME error. Failed to load module script: Expected a ...

Typescript: Streamline the process of assigning types to enum-like objects

One common practice in JavaScript is using objects as pseudo-enums: const application = { ELECTRIC: {propA: true, propB: 11, propC: "eee"}, HYDRAULIC: {propA: false, propB: 59, propC: "hhh"}, PNEUMATIC: {propA: true, propB: ...

Syncing a line's position with the cursor in Angular using the ChartJs Annotation Plugin

I've been working on creating a crosshair using the annotation plugin, and while I've been able to modify the line's value, it doesn't seem to update on the chart. Here are the details of my chart options : public financialChartOptions ...

Issue encountered with express-jwt and express-graphql: TypeScript error TS2339 - The 'user' property is not found on the 'Request' type

Implementing express-jwt and graphql together in typescript has been a challenge for me. import * as express from 'express' import * as expressGraphql from 'express-graphql' import * as expressJwt from 'express-jwt' import s ...

Getting the local path of a file from an input file in Angular 7

Is there a way to retrieve the local file path from an input field in HTML? After running the code below, I obtained 'C:\fakepath\fileTest.txt' I am looking for a method to get the local path so that I can pass it on to my control ...