Closed
Description
TypeScript Version: 3.7.5
Search Terms: union intersection type conflict empty inference generics
Expected behavior:
TypeScript can determine when type intersections are empty. For example,
const t1 = (t: "a" | ("b" & "c")): "a" => t;
const t2 = (t: number | ("b" & "c")): number => t;
is perfectly valid. This is very useful, and it even works through generics:
type Container<Type extends string> = {
type: Type;
}
const t3 = (t: Container<"a"> | (Container<"b"> & { dataB: boolean } & Container<"a">)): Container<"a"> => t;
I'd expect t3
to be validly typed even when the left side of the union and the return type are changed to another type, like so:
const t4 = (t: number | (Container<"b"> & { dataB: boolean } & Container<"a">)): number => t;
Actual behavior:
However, this is a type error:
Type 'number | (Container<"b"> & { dataB: boolean; } & Container<"a">)' is not assignable to type 'number'.
You can find context for where this is relevant here on Stack Overflow, or in this playground.
Related Issues: None found.
Code
const t1 = (t: "a" | ("b" & "c")): "a" => t;
type Container<Type extends string> = {
type: Type;
}
const t2 = (t: Container<"a"> | (Container<"b"> & Container<"c">)): Container<"a"> => t;
const t3 = (t: Container<"a"> | (Container<"b"> & { dataB: boolean } & Container<"a">)): Container<"a"> => t;
const t4 = (t: number | (Container<"b"> & { dataB: boolean } & Container<"a">)): number => t;
Compiler Options
{
"compilerOptions": {
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": true,
"strictBindCallApply": true,
"noImplicitThis": true,
"noImplicitReturns": true,
"useDefineForClassFields": false,
"alwaysStrict": true,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"downlevelIteration": false,
"noEmitHelpers": false,
"noLib": false,
"noStrictGenericChecks": false,
"noUnusedLocals": false,
"noUnusedParameters": false,
"esModuleInterop": true,
"preserveConstEnums": false,
"removeComments": false,
"skipLibCheck": false,
"checkJs": false,
"allowJs": false,
"declaration": true,
"experimentalDecorators": false,
"emitDecoratorMetadata": false,
"target": "ES2017",
"module": "ESNext"
}
}
Playground Link: Provided