TypeScript infers the return type by analyzing the callback property of an object parameter

I am facing a challenge while trying to determine the return type for the function post. The function's second parameter is an object that contains a transform property. If the transform parameter is provided, then the return type of post should be the same as the return type of transform. Otherwise, it should default to the first generic type provided for the post function. I hope this explanation is clear.

type DefaultHttpCallInit = {  
  throttle?: number;
  baseUrl?: string;
  url?: string;
  onSend?(e: HttpCallInit): void | Promise<void>;
}

export type HttpCallInit = RequestInit & DefaultHttpCallInit 

export type HttpCallInitOf<T> = RequestInit & DefaultHttpCallInit & {
  transform?: <TOut>(v: T) => TOut
};

export type HttpCallerInstance = {  
  post<T, TInit extends HttpCallInitOf<T>>(data?: T, init?: TInit): Promise<TInit extends {transform(e: T): infer XOut} ? XOut : T>;
  
}

//hack reference
let r = {} as HttpCallerInstance;

interface Post {
    id?: number;
    title: string;
}

interface User {
  id: number;
  userName: string;
}

interface UserPost extends Post{
  user: User
}

const user = {/* info props */} as User;

r.post({title: 'New post'} as Post, {
  //First: infer 
  transform(post) { 
    return Object.assign(post, {user}) as UserPost
  }
})
Compiler Options
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true,
    "strictBindCallApply": true,
    "noImplicitThis": true,
    "noImplicitReturns": true,
    "alwaysStrict": true,
    "esModuleInterop": true,
    "declaration": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "target": "Latest",
    "module": "ESNext",
    "moduleResolution": "node"
  }
}

Try it out on Typescript Playground

Here is the error message I encountered:
https://i.sstatic.net/tZXEx.png

Answer №1

When defining the generic TOut on the transform itself, it may not accurately represent its intended purpose. Generics in a method or function dictate behavior when called. To specify the transform output type at declaration (alongside T), designate it as a generic of the post function like this:

export type HttpCallInitOf<T, TransformedType = T> = RequestInit & DefautlHttpCallInit & {
  transform?: (v: T) => TransformedType
};

export type HttpCallerInstance = {  
  post<T, TransformedType = T>(data?: T, init?: HttpCallInitOf<T,TransformedType>): Promise<TransformedType>;
  // TransformedType is defaults to T so if it can't be infered it stays as T
}

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

Utilizing Jest to Simulate a Class - Incorporation via Imported Module

I'm having difficulty mocking a constructor of a class from an imported module. Interestingly, it works perfectly when my mock implementation is directly inserted into the jest.mock() factory function, but fails when the implementation is imported fro ...

Adding a method to an object with TypeScript: A step-by-step guide

In my current scenario, I am faced with a challenge where I need to test a function with a specific use of this. However, typescript poses constraints by either disallowing me from adding the method to the object, or if I define it as any, then my interfac ...

Access the raw data value of the parent node using the "val()" method from a child reference within Cloud Functions for Realtime Database

Suppose I'm indicating a path in my TypeScript/JavaScript code function like this: exports.sendNotification = functions.database.ref('shops/countries/{countryName}/shopAddress/{currentShopAddress}') .onWrite((snapshot,context) => { ...

What is the best way to locate and access a JSON file that is relative to the module I am currently working

I am in the process of creating a package named PackageA, which includes a function called parseJson. This function is designed to accept a file path pointing to a JSON file that needs to be parsed. Now, in another package - PackageB, I would like to invok ...

Utilizing AWS CDK with Node.jsFunction to import a module that is exported as "export="

Is it possible to utilize modules (such as sharp) that are exported as export = someModule in a Lambda function defined with the NodejsFunction from the aws-cdk-lib? It seems like the require statement (const xxx = require('module')) does not w ...

Error: Unable to locate the reference for "foo" while utilizing TypeScript in combination with Webpack

My Chrome extension is functioning properly when using JavaScript alone. However, when attempting to incorporate TypeScript with Webpack, I encountered an issue where the function foo could not be found. Uncaught ReferenceError: foo is not defined Here ...

Deactivate the Discord JS button

Looking to create a Discord bot in TypeScript and wanting to disable two buttons when one is clicked, but unsure how to accomplish this. This is my command with the two buttons (warn.ts): import { PermissionsBitField, ButtonBuilder, ActionRowB ...

Typescript's conditional types define unique object fields based on specified conditions

I am looking to create a function (which will eventually be used as a React function component) in Typescript that receives a props object containing a list of lists of objects of any type. The goal is for the function to output a "key" for each object - i ...

The challenge of resizing dialog elements in Angular Material

I am currently working on developing a text dialog for my app that will be reused frequently. The text dialog consists of a header, a message displayed above the text input, the text input area, and "Ok" and "Cancel" buttons. Upon my observation, I have f ...

Can we verify if strings can serve as valid property names for interfaces?

Let's consider an interface presented below: interface User { id: string; name: string; age: number; } We also have a method defined as follows: function getUserValues(properties:string[]):void { Ajax.fetch("user", properties).then( ...

How can I indicate separate paths for the identical dependencies listed in package.json?

Currently, I am in the process of working on an npm package that consists of an example directory designed to run and test the actual package. Within this example directory, I have re-integrated the parent package using "file:..". While this set ...

Saving data from rowclicked event in ag-grid with Angular

My goal is to save the event data from the onRowClicked event in a Component member. This way, when the user clicks a button, the data can be deleted. However, I am facing an issue where the member variable becomes undefined when trying to access it in t ...

When utilizing destructuring in React.js with TypeScript, incorrect prop values are not being alerted as expected

I recently started using TypeScript and I have been enjoying it so far. However, I came across an issue today that I couldn't solve. Imagine a scenario where a parent component A passes a function that expects a numeric value to the child component B ...

A guide on incorporating a button into a column within ng2table in Angular 2

I am currently using ng2table and I have all the columns being appended from ts. However, I would like to add a button to each of these columns. Can someone please assist me with how to achieve this? Thank you. columns: Array<any> = [ {tit ...

External node modules written in TypeScript can occasionally be transpiled into both `module.exports` and `

Currently, I am in the process of transforming my node application to utilize TypeScript external modules. While everything runs smoothly when executing the app, I encountered an issue with my mocha tests "exploding" after converting some of my .ts files d ...

retrieve user input from various angular 6 components

Currently, I am in the process of developing a small web-based game using Angular 6. Within this project, I have two key components - play.component and setup.component. The main concept is to allow users to customize elements such as difficulty within the ...

typescript declaring a namespace with a restricted identifier

I have created a custom Http client in typescript with the following definition: declare namespace Http { type HttpOptions = ...; type HttpPromise<T> = ... function get<T>(url: string, options?: HttpOptions): HttpPromise<T>; ...

Transforming JavaScript to TypeScript in Angular: encountering error TS2683 stating that 'this' is implicitly of type 'any' due to lacking type annotation

While in the process of migrating my website to Angular, I encountered an error when attempting to compile the JS into TS for my navbar. After searching around, I found similar issues reported by other users, but their situations were not quite the same. ...

Creating a shared singleton instance in Typescript that can be accessed by multiple modules

Within my typescript application, there is a Database class set up as a singleton to ensure only one instance exists: export default class Database { private static instance: Database; //Actual class logic removed public static getInstance() ...

Is it possible to use export default Enum in TypeScript?

I am facing an issue with exporting an enum object as default at the top level in my code. Here is what I tried: export default enum Hashes{ FOO = 'foo', BAR = 'bar', } However, this resulted in an error message: Module parse failed ...