Creative Solution for Implementing a Type Parameter in a Generic

Within my codebase, there exists a crucial interface named DatabaseEngine. This interface utilizes a single type parameter known as ResultType. This particular type parameter serves as the interface for the query result dictated by the specific database driver. For instance, in the case of MSSQL, it would be represented as the IResult interface within the context of DatabaseEngine<IResult>. It's worth noting that this type does not solely pertain to the rowset acquired from a query; instead, it acts as a comprehensive "wrapper" encompassing the rowset along with accompanying metadata such as fields, affected rows, executed SQL statements, and more.

In correspondence to the MSSQL library, the IResult interface consists of a singular type parameter defining the rows of data being returned. This paradigm appears to be prevalent across many database libraries that I've come across.

The DatabaseEngine interface features a property named toDataFrame, which essentially functions as a manipulator to process retrieved data from the database (elaboration on the specifics of this operation is irrelevant for the purpose of this discourse). This function encompasses a type parameter denoted as T, representing the rows of objects extracted from the database. Ideally, its primary parameter should correspond to the result set originating from the database driver (e.g., IResult). However, since IResult was previously encapsulated within an individual type parameter, it results in requisite notation like ResultType<T>, although this approach proves futile.

To summarize concisely: The envisioned type structure can be articulated as follows:

interface DatabaseEngine<ResultType> {
    ...
    toDataFrame<T>(result: ResultType<T>): DataFrame<T>
}

// Here, T signifies the object type present in the rowset obtained from the database, while ResultType indicates the library-specific wrapper for querying outcomes

An illustrative application scenario could be depicted through the following example:

import mssql from 'mssql'

const msSqlDatabaseEngine: DatabaseEngine<IResult> = {
    ...
    toDataFrame<T>: (result) => {
        ... // Implement operations on the result to return a dataframe
        // Thanks to typings, the compiler deduces result as IResult<T>
    }
}

const queryResult = mssql.connect({ ... }).query('SELECT * from Employees') // Yields an object embodying the traits of IResult<Employee> (presuming Employee stands as a defined type elsewhere, disregarding further details)
const df = msSqlDatabaseEngine.toDataFrame(queryResult) // Directly utilize queryResult, as the compiler infers the inner generic T to represent Employee during this function invocation

It's evident that this remains an open-ended feature request. Numerous prior Stack Overflow inquiries fail to elucidate this specific requirement where amalgamation of type parameters from distinct origins occurs alongside one serving as a generic. Could there exist a viable workaround or series of utility types accommodating what's being sought after?

My attempt at implementing the aforementioned interface directly yielded errors pointing out that "ResultType is not generic," which aligns with its inherent nature. While trying to make ResultType generic, TypeScript fails to acknowledge this alteration due to its affiliation within a generic scope. Any proposed solutions involving utility types or alternative workarounds capable of yielding similar outcomes are fervently solicited.

Answer №1

Suppose you can deduce T from

IResult<T> | IOtherResult<T> | ...
,

sandbox

import mssql from 'mssql'

type MyDbResult<T> = { db: 'my-db', value: T }

type ResultType<T> =
    | mssql.IResult<T>
    | MyDbResult<T>

type UnwrapResultType<T> =
    | T extends ResultType<infer V> ? V : never
    // | T extends mssql.IResult<infer V> ? V
    // : T extends MyDbResult<infer V> ? V
    // : never;

type DataFrame<T> = T[][]

interface DatabaseEngine<BaseResultType extends ResultType<any>> {
    //                   ^ force result to be limited to ThisDBResult<any>
    toDataFrame<T extends BaseResultType>(result: T): DataFrame<UnwrapResultType<T>>
}

const msSqlDatabaseEngine: DatabaseEngine<mssql.IResult<any>> = {
    toDataFrame(
        result /* : result: T extends mssql.IResult<any> */
    ) /* : DataFrame<UnwrapResultType<T>> */ {
        return [[]]
    }
}
const mySqlDatabaseEngine: DatabaseEngine<MyDbResult<any>> = {
    toDataFrame(
        result /* T extends MyDbResult<any> */
    ) /* DataFrame<UnwrapResultType<T>> */ {
        return [[]]
    }
}

const con = await mssql.connect('')
const queryResult = await con.query<{ employee: true }>('SELECT * from Employees')
//    ^?
// const queryResult: mssql.IResult<{ employee: true; }>
const df = msSqlDatabaseEngine.toDataFrame(queryResult)
//    ^?
// const df: DataFrame<{ employee: true; }>

const myQueryResult: MyDbResult<number> = { db: 'my-db', value: 123 }
const mf = mySqlDatabaseEngine.toDataFrame(myQueryResult)
//    ^?
// const mf: DataFrame<number>

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

Error in Express Session: Property 'signin' is not found in type 'Session & Partial<SessionData>'. Code: 2339

I received the following Error Code: Property 'signin' does not exist on type 'Session & Partial<SessionData>'. (2339) About My Application src/index.ts import "reflect-metadata"; import express = require("expr ...

Typescript: Verifying the type of an interface

In my code, I have a function called getUniqueId that can handle two different types of interfaces: ReadOnlyInfo and EditInfo. Depending on the type passed to this function, it will return a uniqueId from either interface: interface ReadOnlyInfo { item ...

A function that logs a message to the console if an array contains identical values

Struggling to find equal values in my array, I've attempted several methods without success. One approach I tried involved sorting the array: var sorted_arr = this.variacaoForm.value.variacoes.sort(); // the comparing function here for (var i = 0; ...

Trouble arises when attempting to transfer cookies between server in Fastify and application in Svelte Kit

In the process of developing a web application, I am utilizing Fastify for the backend server and Svelte Kit for the frontend. My current challenge lies in sending cookies from the server to the client effectively. Despite configuring Fastify with the @fas ...

Creating a Session Timeout feature for Ionic/Angular that includes resetting the timer with each new user interaction

Having trouble implementing a session timeout feature in my code. I need the timer to reset whenever a user interacts with the function. Can't figure out how to integrate similar code like the one provided as an example on Stack Overflow. This is the ...

One can only iterate through the type 'HTMLCollection' by utilizing the '--downlevelIteration' flag or setting a '--target' of 'es2015' or above

I'm currently working on developing a loader for my static grid. I've incorporated the react-shimmer-skeleton package source code, but I'm encountering issues with eslint in strict mode. You can find the respective repository file by followi ...

Error: The specified updateTag type in the Angular SEO service is not compatible

I am in the process of developing an SEO service using Angular's Meta service (https://angular.io/api/platform-browser/Meta) Within the service, there is a method for managing social media tags that seems to be encountering issues and producing the f ...

Angular2: Unable to locate the 'environment' namespace

After configuring my tsconfig.json, I can now use short import paths in my code for brevity. This allows me to do things like import { FooService } from 'core' instead of the longer import { FooService } from '../../../core/services/foo/foo. ...

Exploring Typescript's type narrowing capabilities through destructuring

This code snippet is encountering errors: type Example = { x: true, y: null, z: null } | { x: false, y: Error, z: null } | { x: false, y: null, z: { val: number} } function getExample(): Example { return { x: false, y: null, z: { val ...

Utilizing TypeScript with Sequelize for the Repository Design Pattern

I am in the process of converting my Express API Template to TypeScript, and I am encountering difficulties with the repositories. In JavaScript, the approach would be like this: export default class BaseRepository { async all() { return th ...

Is it better to keep a lengthy array in the back-end or front-end storage?

I'm facing a dilemma in my angular application. I have a lengthy array that I need to access easily from the front-end without causing any slowdowns. There are various options available, but I'm unsure which one would be the most efficient. Shoul ...

Incorporating a module from a nearby component repository into the primary task

As I work on developing a component library using React, TypeScript, Rollup, and Styled Components, I have made significant progress but have hit a roadblock that seems to be the final hurdle. The button component in my library is successfully exported, a ...

typescript's JSON.stringify function includes internal fields but omits public interface values

I'm currently grappling with some confusion surrounding serialization in TypeScript using JSON.stringify and interfaces. My goal is to create an export format for serializing certain objects back to their server-side representation, focusing solely on ...

Why won't the sound play on the button with the picture?

I am currently working on a website project that requires buttons with pictures and sound. Despite my efforts, the sound feature is not functioning properly in Chrome and Firefox. I am still learning and would like to know how to toggle the sound on and of ...

Unable to access the values of the object within the form

I am encountering an issue where I cannot retrieve object values in the form for editing/updating. The specific error message is as follows: ERROR TypeError: Cannot read properties of undefined (reading 'productName') at UpdateProductComponen ...

When working with Typescript and Vue.js, it's important to ensure that properties are initialized before

Check out the following code snippet: export default class PrimitiveLink extends Vue { style = { // Reset display: 'inline-block', textDecoration: 'none', outline: 'none', // Theme ...this.themeStyle ...

Angular 2 does not recognize the existence of .then in type void

I have a query regarding Angular2 and I'm struggling with the void function in my code. Can someone help me out? I am new to Angular2 and unsure of what needs to be added in the void function. Check out this image for reference export class PasswordR ...

To achieve this, my goal is to have the reels start playing on a separate page when a user clicks on the designated image. I am currently working on a project that involves this

When a user clicks on the designated image, I want the reels to start playing on a separate page. In my main project, I have a reels project within it, with the reels project built in ReactJS and the main project in React TypeScript. For example, if a user ...

How to specify the return type of a promise from an observer in Angular 6

Typically, I prefer using observables. However, in order to avoid 'callback hell' in this particular scenario, I decided to use toPromise(). Unfortunately, I encountered a lint error message when trying to define the return type: The 'Obj ...

What is the process for setting the value of a TextField based on a Dropdown Selection?

I have a question regarding the code snippet below. I am wondering how to set the value of a specific TextField based on the selected item in a Dropdown component named ChildComponent. import * as React from "react"; import ChildComponent from './Ope ...