Description
I encountered a strange behavior of type inference about the generic arguments and intersection type. The error described below occurs only when the strictFunctionTypes
option is enabled.
TypeScript Version:
Version 3.3.0-dev.20181221
Search Terms:
strictFunctionTypes
argument intersection type
generic argument
generic intersection type
Code
tsconfig.json:
{
"compilerOptions": {
"moduleResolution": "node",
"target": "es6",
"module":"commonjs",
"strictFunctionTypes": true,
"outDir": "dist"
},
"include": ["*.ts"]
}
source:
const run = <P1, P2>(
makeProps1: (s: string) => P1,
makeProps2: () => P2,
useBoth: (props: P1 & P2) => void
) => {};
const foo = (props: { n: number; b: boolean }) => {};
// This works as expected.
run(() => ({ n: 1 }), () => ({ b: true }), foo);
// But if the first argument function takes a parameter `s`, it results in a compile error.
run(s => ({ n: 1 }), () => ({ b: true }), foo);
Expected behavior:
The type of run
is inferred correctly from run(s => ({ n: 1 }), () => ({ b: true }), foo)
as below and the code compiles.
const run: <{ n: number; }, { b: boolean; }>(makeProps1: (s: string) => { n: number; }, makeProps2: () => { b: boolean; }, useBoth: (props: { n: number; } & { b: boolean; }) => void) => void
This type is generated from run(() => ({ n: 1 }), () => ({ b: true }), foo)
. I copied it from Playground's tooltip.
Actual behavior:
It results in the compile error.
output of npx tsc
:
repro.ts:9:43 - error TS2345: Argument of type '(props: { n: number; b: boolean; }) => void' is not assignable to parameter of type '(props: { b: boolean; }) => void'.
Types of parameters 'props' and 'props' are incompatible.
Property 'n' is missing in type '{ b: boolean; }' but required in type '{ n: number; b: boolean; }'.
9 run(s => ({ n: 1 }), () => ({ b: true }), foo);
~~~
repro.ts:7:23
7 const foo = (props: { n: number; b: boolean }) => {};
~
'n' is declared here.
Found 1 error.
This is because the return type of makeProps1
is inferred as {}
instead of { n: number; }
.
const run: <{}, { b: boolean; }>(makeProps1: (s: string) => {}, makeProps2: () => { b: boolean; }, useBoth: (props: { b: boolean; }) => void) => void
Playground Link:
Here. Note that this problem occurs only when the strictFunctionTypes
option is enabled.
Related Issues:
I could not find.
Other Investigation:
In the code below, the type inference works as expected:
const run2 = <P1, P2>(
makeProps1: (s: string) => P1,
makeProps2: () => P2,
useProps1: (p: P1) => void,
useProps2: (p: P2) => void
) => {};
// The first argument function takes a parameter `s` but it does not change the type inference behavior.
run2(
s => ({ n: 1 }),
() => ({ b: true }),
(p1: { n: number }) => {},
(p2: { b: boolean }) => {}
);
So it seems that the error only occurs when the generic types (P1
, P2
) are used as intersection type.