Typescript: Incorrect code hint for mapped (in keyof) property types

Created on 27 Jun 2020  路  6Comments  路  Source: microsoft/TypeScript


TypeScript Version: 3.9.2


Search Terms: incorrect code hint for mapped keyof property types

Code

type Numbers = {
    [key: string]: number
}

type Strings<T extends Numbers> = {
    [K in keyof T]: string
}

function test<T extends Numbers>(input: T): Strings<T> {
    const output = {} as any

    for (const key of Object.keys(input)) {
        output[key] = input[key].toString()
    }

    return output
}

// hover over `mapped` to see the property type is `number` (incorrect)
const mapped = test({ value: 100 })
// hover over `value` to see the property type is `string` (correct)
mapped.value

Expected behavior:

Code hint should show property types as string

Actual behavior:

Code hint shows property types as number

However, hovering over a property shows its type as string

Playground Link:
This example code highlights the issue

Working as Intended

Most helpful comment

@simon-robertson The type you are seeing Strings<{ value: number }> resolves to { value: string; } but TS does not always expand out type aliases in tooltips. So there is no conflict between what you are seeing.

If you want to always expand out a type alias add {} & to the mapped type to force expansion (note that {} & is not documented and should not be relied upon, it's just a useful debugging trick)

type Numbers = {
    [key: string]: number
}

type Strings<T extends Numbers> = {} & {
    [K in keyof T]: string
}

function test<T extends Numbers>(input: T): Strings<T> {
    const output = {} as any

    for (const key of Object.keys(input)) {
        output[key] = input[key].toString()
    }

    return output
}

// Now you see { value: string; }
const mapped = test({ value: 100 }) 
mapped.value // string

Playground Link

All 6 comments

It seems that

{
  value: number;
}

in

const mapped: Strings<{
    value: number;
}>

in the mapped's hint defines the test function input's (T) type, not the __return type__ of the function.

I'm curious if there is any way to return the result type of Strings<T> from the function instead of the "unresolved" one to improve the hint. It would be great.

The tooltip says, reading it in its entirety, Strings<{ value: number }>, which is exactly what this type is.

The tooltip says, reading it in its entirety, Strings<{ value: number }>, which is exactly what this type is.

@RyanCavanaugh, could you please explain how that is the case when the test function is returning a [key: string]: string type? I assume there is a misunderstanding on my part regarding the way [K in keyof T] works when mapping objects this way

@simon-robertson The type you are seeing Strings<{ value: number }> resolves to { value: string; } but TS does not always expand out type aliases in tooltips. So there is no conflict between what you are seeing.

If you want to always expand out a type alias add {} & to the mapped type to force expansion (note that {} & is not documented and should not be relied upon, it's just a useful debugging trick)

type Numbers = {
    [key: string]: number
}

type Strings<T extends Numbers> = {} & {
    [K in keyof T]: string
}

function test<T extends Numbers>(input: T): Strings<T> {
    const output = {} as any

    for (const key of Object.keys(input)) {
        output[key] = input[key].toString()
    }

    return output
}

// Now you see { value: string; }
const mapped = test({ value: 100 }) 
mapped.value // string

Playground Link

Thank you for the explanation @dragomirtitian, using {} & does indeed work even though its use in this case is counter-intuitive

This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

blendsdk picture blendsdk  路  3Comments

bgrieder picture bgrieder  路  3Comments

wmaurer picture wmaurer  路  3Comments

remojansen picture remojansen  路  3Comments

Antony-Jones picture Antony-Jones  路  3Comments