TypeScript: Incorrect inference of arrow function with intersected mapped type argument under strictFunctionTypes

TypeScript Version: 3.6.0-dev.20190801

Search Terms: inference intersection type strictFunctionTypes

Code

type MappedIntersection<T extends {}> = { [P in keyof T]: string } & {};
type MappedRaw<T extends {}> = { [P in keyof T]: string };

// Case 1: Intersection + no arrow = succeed
type ToInferNoArrowIntersection<T extends {}> = {
    fn(params: MappedIntersection<T>): void;
};

type NoArrowIntersection<T extends ToInferNoArrowIntersection<any>> = void;
declare const case1: NoArrowIntersection<{
    fn: (params: MappedIntersection<{a: 1}>) => string,
}>;


// Case 2: No intersection + arrow = succeed
type ToInferArrowNoIntersection<T extends {}> = {
    fn: (params: MappedRaw<T>) => void;
};

type ArrowNoIntersection<T extends ToInferArrowNoIntersection<any>> = void;
declare const case2: ArrowNoIntersection<{
    fn: (params: MappedRaw<{a: 1}>) => void,
}>;


// Case 3: Intersection + arrow = fail
type ToInferArrowIntersection<T extends {}> = {
    fn: (params: MappedIntersection<T>) => void;
};

type ArrowIntersection<T extends ToInferArrowIntersection<any>> = void;
declare const case3: ArrowIntersection<{ // Fails here
    fn: (params: MappedIntersection<{a: 1}>) => void,
}>;

Expected behavior: Expected case 3 to succeed.

Actual behavior: Case 3 produces:

 Type '{ fn: (params: { a: string; }) => void; }' does not satisfy the constraint 'ToInferArrowIntersection<any>'.
  Types of property 'fn' are incompatible.
    Type '(params: { a: string; }) => void' is not assignable to type '(params: { [x: string]: string; }) => void'.
      Types of parameters 'params' and 'params' are incompatible.
        Property 'a' is missing in type '{ [x: string]: string; }' but required in type '{ a: string; }'.

Seems relevant that compilation succeeds without strictFunctionTypes

Playground Link: Playground

Related Issues: https://github.com/microsoft/TypeScript/issues/29123#issuecomment-453884098 https://github.com/microsoft/TypeScript/issues/31081

About this issue

  • Original URL
  • State: open
  • Created 5 years ago
  • Comments: 17 (5 by maintainers)

Most upvoted comments

I would, too, but as it turns out a Readonly<any> isn’t structurally compatible with a Readonly<{x: number}> because of how any feeds into mapped types…

Unreliable is supposed to be “fallback to structural if varianced-based check fails” while Unmeasurable is “don’t use the variance result at all”. It was a bit of a compromise to continue to allow some things that checked with variance but not by structure, so the change would break less, iirc. In theory the only thing that would change by converting all Unreliable into Unmeasurable is performance, in practice I’m not sure that’s the case.