Repository navigation
Convert to async function refactoring loses generic parameter #28529
Description
Activity
typescript@3.2.0-dev.20181114
Simple repo:
async function foo<T>(x: T): Promise<T> { return x; } function bar<T>(y: T): Promise<T> { return foo(y).then<T>(foo) }
- addedBugA bug in TypeScriptA bug in TypeScriptDomain: LS: Refactoringse.g. extract to constant or function, rename symbole.g. extract to constant or function, rename symbol
on Nov 15, 2018 - assigned and unassigned
on Jan 3, 2019 7 remaining items
andrewbranch commented
on Feb 11, 2020 MemberMore actionsThis is a bug, but the expected behavior described is wrong. To explain why, take this example:
type Response<T> = { success: true, data: T } | { success: false }; function wrapResponse<T>(response: T): Response<T> { return { success: true, data: response }; } function get() { return Promise.resolve(undefined!).then<Response<{ email: string }>>(wrapResponse); }
The return type of
getisPromise<Response<{ email: string }>>. If we apply the refactor as suggested:async function get() { const response = await Promise.resolve((undefined!)); return wrapResponse<Response<{ email: string }>>(response); }
then the return type becomes
Promise<Response<Response<{ email: string }>>. The type argument provided towrapResponserepresents the type of its input, whereas the type argument provided tothenrepresents the type of the fulfilled handler’s output. In theparseJsonexample and in Matt Bierner (@mjbvz)’s minimal example, those happen to be the same thing, but it’s purely coincidental.I guess the best thing to do would be to move the type annotation to the return type if it was in a return expression:
async function get(): Promise<Response<{ email: string }>> { const response = await Promise.resolve((undefined!)); return wrapResponse(response); }
or to a constant, if it was originally a constant:
async function get() { const response = await Promise.resolve((undefined!)); const result: Response<{ email: string }> = await wrapResponse(response); // ... other stuff I guess }
but I’m not sure what to do if the original function declaration or constant already had a type annotation that doesn’t agree... I guess just keep ignoring the type argument like we do now, as the type would be discarded in the end result of the expression anyway.
Ah, I see. I think I was confusing myself by using the same name for both type parameters in my example.
Is there a mechanism to refuse to do the refactoring and present a useful message explaining why? Maybe that would be the best option (or a dialog presenting the user with a choice of which type to use, along with a cancel button)?
andrewbranch commented
on Feb 12, 2020 MemberMore actionsThere’s not, currently. If the refactor fails it simply isn’t shown as an option. I think annotating either the return type or the constant is reasonably correct here... the most important thing is that the inferred return type of the function doesn’t change because of the refactor, which this approach should ensure. Perhaps, though, we should bail out of the refactor if there’s an existing type error because of a conflict between a
thenorcatchtype argument and the contextual type of the expression it’s in, because we’re likely to erase that conflict during the refactor.- addedFix AvailableA PR has been opened for this issueA PR has been opened for this issue
on Mar 19, 2020 ❤️
- locked as resolved and limited conversation to collaborators
on Oct 21, 2025
Issue Type: Bug
This method
gets converted into this
it should keep the explicit parameter on
parseJson<T>.Here’s the
parseJsonfunction in case that helps:VS Code version: Code - Insiders 1.30.0-insider (5fc60ec, 2018-11-14T07:58:01.008Z)
OS version: Darwin x64 18.2.0
System Info
checker_imaging: disabled_off
flash_3d: enabled
flash_stage3d: enabled
flash_stage3d_baseline: enabled
gpu_compositing: enabled
multiple_raster_threads: enabled_on
native_gpu_memory_buffers: enabled
rasterization: enabled
video_decode: enabled
video_encode: enabled
webgl: enabled
webgl2: enabled
Extensions (14)
(1 theme extensions excluded)