Skip to content

Type assertion on unspecified generic return type changes the type #36062

@bradzacher

Description

@bradzacher

TypeScript Version: nightly (on playground).

Search Terms:
generic, return, assertion, inference, checker api.

Code

declare function genericGet<TValue>(object: any, path: string): TValue

const object = { foo: { bar: 123 } };
const result1 = genericGet(object, 'foo.bar');
const result2 = genericGet(object, 'foo.bar') as number;

Expected behavior:
In both cases, the return type of genericGet(object, 'foo.bar') reported by the type checker API (checker.getTypeAtLocation) should be unknown.

Actual behavior:
In the first case, the return type of genericGet(object, 'foo.bar') reported by the type checker API is unknown.
image

In the second case, the return type is number.
image

(best shown via ts-ast-viewer, link below).

Playground Link:
https://www.typescriptlang.org/play/?ssl=1&ssc=1&pln=7&pc=56#code/CYUwxgNghgTiAEAzArgOzAFwJYHtXwHMRUQYswBxEDAHgBUA1KCZEAPgAocAjAK3AwAueFFQBPADTwADlAwALYQGcMZVAQCUwxs1YAoPWDwr4PfpngBeeAG8kOHMLvdYwgIwAmAMzwAvn4BuQ2MMeDglZAgMNytCYlJyKgwuPgEpAHJEBwA6Fxh0jSCjVBNwyIwPWKISMkpqFPMMDKycXNgCkSV4VGQAW25SAKA

https://ts-ast-viewer.com/#code/CYUwxgNghgTiAEAzArgOzAFwJYHtXwHMRUQYswBxEDAHgBUA1KCZEAPgAocAjAK3AwAueFFQBPADTwADlAwALYQGcMZVAQCUwxs1YAoPWDwr4PfpngBeeAG8kOHMLvdYwgIwAmAMzwAvn4BuQ2MMeDglZAgMNytCYlJyKgwuPgEpAHJEBwA6Fxh0jSCjVBNwyIwPWKISMkpqFPMMDKycXNgCkSV4VGQAW25SAKA

Related Issues:
#31435
Loosely related to: #35431

Related issue in typescript-eslint:
typescript-eslint/typescript-eslint#1410

Related rule logic:
https://github.com/typescript-eslint/typescript-eslint/blob/aee723813ec47ccac0a165cf1bc9674f6257b609/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts#L244-L292


I found #31435, which seems to suggest that this is entirely intentional.

However I would like to question this from the context of the type checker API.
This makes the type API pretty hard to use for certain use cases. Inspecting the type of the assertion expression (via checker.getTypeAtLocation) says it's of type number, and similarly inspecting the type of the call expression via the same API says it's of type number.

Is there any way to get the type that hasn't been inferred from a return type assertion?

In the context of our no-unnecessary-type-assertion rule, the rule warns about assertions that don't do anything, so that there is less useless code in a codebase..
(i.e. genericGet(object, 'foo.bar') as number is necessary, because it asserts unknown to number, but genericGet<number>(object, 'foo.bar') as number is unnecessary, because the return type is already number).

Metadata

Metadata

Assignees

No one assigned

    Labels

    QuestionAn issue which isn't directly actionable in code

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions