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

The React Component in Next.js does not come equipped with CSS Module functionality

I have been attempting to incorporate and apply CSS styles from a module to a React component, but the styles are not being applied, and the CSS is not being included at all. Here is the current code snippet: ./components/Toolbar.tsx import styles from & ...

angular2 ngif does not effectively conceal HTML elements when set to false

In the HTML file, I have the following code: <p *ngIf="!checklistsready"> not ready </p> <p *ngIf="checklistsready"> Ready </p> And in my TypeScript file, it looks like this: checklistsready: boolean = false; constructor( ...

Issue with Angular reactive forms when assigning values to the form inputs, causing type mismatch

I'm a beginner when it comes to reactive forms. I'm currently working on assigning form values (which are all string inputs) from my reactive form to a variable that is an object of strings. However, I am encountering the following error: "Type ...

A step-by-step guide on creating a Decorator using the TypeScript compile API

How can I create a custom class in TypeScript with multiple 'class-validator' decorators to ensure the property types are correct? I am considering using `ts.factory.createDecorator`, but I'm unsure how to obtain a `ts.Expression` for it. ...

Storing the subscription value retrieved from an API in a global variable

I am trying to find a way to make the data retrieved from an API accessible as a global variable in Typescript. I know that using subscribe() prevents this, so I'm looking for a workaround. Here is the API code: getResultCount(category:any):Obs ...

New data field is created with AngularFire2 update instead of updating existing field

I am facing an issue with updating a Firestore model in Angular 6. The model consists of a profile name and a list of hashtags. The "name" is stored as the value of a document field, while the "hashtags" are stored as keys in an object. However, every time ...

The OrderBy Pipe in Angular 4 fails to sort correctly when the name of the item being sorted

How can I sort names ending with numbers using a custom pipe? I have successfully implemented a custom pipe for sorting and it is working as expected. $Apple fruit -symbol 1Apple fruit -numbers Apple fruit -alphabetically However, the custom pip ...

Moment.js is stating that there is no property called 'toISOString' on the type '{}'

I'm facing an issue with my code - the `value.toISOString()` function was working fine until now, but suddenly it's throwing a compiler error. I recently upgraded from Angular 7 to 8, which also bumped up the Typescript version to 3.4.5. Any sugg ...

CPU usage spikes after launching a Cordova project in Visual Studio 2015 RTM

If you're looking for the source code of the project, you can find it at https://github.com/Yaojian/Ionic-TypeScript-Starter/. I decided to create a Visual Studio project by forking https://github.com/Justin-Credible/Ionic-TypeScript-Starter/ and fol ...

Encountering issues with accessing the clientWidth and clientHeight references of the DOM in Vue

Issue with 'clientWidth' and 'clientHeight' properties on Vue and Element types. <div class="invoice-step-detail" id="invoice" ref="invoice"> @Component({ name: 'CreateInvoice', co ...

Understanding how to efficiently map through FontAwesome icons using React TypeScript and effectively showcase them on the frontend

I am in the process of developing a versatile component that allows me to input the href, target, and rel attributes, along with specifying the FontAwesome Icon I want to utilize. My goal is to be able to pass multiple icons into this list, which will then ...

typescript Object that consists of properties from an array with a defined data type

I have an array consisting of strings. I am trying to transform this array into an object where each string is a property with specific attributes assigned to them. export interface SomeNumbers { name: string; value: number; } const arr = ['apple& ...

Uploading Files with Typescript Promises

Hello everyone, I'm facing an issue where a dialog window is opening before all the files are uploaded to the server. Can anyone please guide me on what might be going wrong in my code? public UploadAll() { this.doAsyncTask().then(() => ...

How can I properly include DefinitelyTyped TypeScript definition files in a .NET Core project?

Previously, under asp.net for .net framework, I utilized NuGet to incorporate TypeScript type definitions from third-party libraries (*.d.ts files) provided by DefinitelyTyped. However, with the shift to .NET Core, it seems that NuGet is no longer recommen ...

What methods does the TypeScript compiler use to locate npm packages containing types?

When configuring the typescript compiler, you can utilize the tsconfig.json file. This will also give you access to options for finding type definition files using the typeRoots key. By default: All visible "@types" packages are automatically included in ...

How can you specify the active route in Angular?

I am curious about whether it is possible to set the active route from a script instead of just from the HTML template. Let me provide an example: @Component({ template: `<input type="button" (click)="back()" value="back" ...

Issue with Angular/Jasmine: Undefined property 'pipe' not readable

I have been struggling to resolve a problem with Angular 9, Jasmine, and RxJS without much success. While my unit tests run successfully in Jasmine, there are certain lines of code that do not get executed. Despite scouring multiple posts for assistance, ...

Methods for transforming a TypeScript class instance containing getter/setter properties into a JSON format for storage within a MySQL database

I am currently working on a TypeScript class that includes a getter and setter method: export class KitSection { uid: string; order: number; set layout(layout: KitLayout) { this._layout = new KitLayout(layout); } get layout( ...

What is the best way to simulate an overloaded method in jest?

When working with the jsonwebtoken library to verify tokens in my module, I encountered a situation where the verify method is exported multiple times with different signatures. export function verify(token: string, secretOrPublicKey: Secret, options?: Ve ...

Icon for TypeScript absent from npm package listings

Recently, I created a package and uploaded it to the npm repository. The package was displayed with an icon labeled "ts" on the website. https://i.stack.imgur.com/LoY1x.png The accompanying package.json showcased the inclusion of the "ts" icon - https:// ...