Skip to content

'infer' in mapped type may lose specificity  #39295

@aloifolia

Description

@aloifolia

TypeScript Version: 3.8.3 - 3.9.5 (probably more)

Code

// suppose that IRL this type does something more useful 
type MakeOptional<TObject extends object> = {
  // the "extends infer TValue" is crucial - without it, everything works as expected
  [TKey in keyof TObject]?: TObject[TKey] extends infer TValue
    ? TValue
    : never;
};

type BaseType = { a: number; b: { c: string } };
type ConcreteType = { a: 42; b: { c: 'stuff' }; };

declare const value: ConcreteType;

declare function doNothing<
  // Here, ConcreteType would entail the same result
  TValue extends BaseType, 
  TMappedValue extends MakeOptional<TValue>
>(
  value: TValue,
  mappedValue: TMappedValue,
): {
  value: TValue;
  mappedValue: TMappedValue;
};

const result = doNothing(value, {
  a: 42,
});

Expected behavior:
The inferred type of result should be

{
    value: ConcreteType;
    mappedValue: {
        a: number
    };
}

Actual behavior:
The inferred type of result is

{
    value: ConcreteType;
    mappedValue: MakeOptional<ConcreteType>;
}

There is a workaround: If you pass the argument for the parameter mappedValue with as const, the compiler will instead infer the concrete type. However, if you do this you lose code completion for the fields of mappedValue. So basically, you are left with what I would consider another bug/shortcoming of the compiler.

Playground Link:
https://www.typescriptlang.org/play/index.html?ssl=15&ssc=18&pln=15&pc=26#code/C4TwDgpgBAsghgawgeTMAlgewHZwDYA8AKsgEYBWEAxsFBAB7ATYAmAzlJhdcAHxQBeKAG8AUFCgBtIgGkIIKOmxQkITADMoJbjQC6AfgBcWspRrS5IXXUbN2i7OogAnLQDV8AVwjiJUfe5ePn5QxtgQAG4uANyiAL6xoqCQUADCOFTOEExE4NBCYhJwxgAsAEyxEqTGwlBUxgDkbMCe6uoNUAnxiSzUeHBZdTjNUBFBxunYmdkQuZA9fQPQ6p5TGDhQLJgAcpjAABZKAOYEvkQeeN42TKwck9M5eQA0Z-BgkCwXVww39vBIqHWuEI5yCvFEvAAFL4xpcIMZQXCXhIALZwd4QT7jLRvD5fCAvACUNRh2MR3kqUDRGKxcIRuMx+NiXVEVGGtCybE8eFoQi2uwOx0hsO8TxEvmKUHKLzihOiQA

Related Issues:

Metadata

Metadata

Assignees

No one assigned

    Labels

    UnactionableThere isn't something we can do with this issue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions