TypeScript Version: 2.6.0-dev.20170826 and 2.4.2
I wonder if I hit some typescript inference bug/limitation, or if my code is simply incorrect. If the code is actually valid, and it's a type inference issue, I'll report a bug to the typescript github.
I'm trying to constrain the Set
builder to accept only types for which equality is properly defined (to avoid this problem).
strange.d.ts
declare module 'strange' {
export type WithEquality = string|number|boolean|{equals(other: any): boolean; hashCode(): number;};
export interface Set<T> {
add(other: T): Set<T>;
}
export function makeSetUnsafe<V>(...vals: V[]): Set<V>;
export function makeSet<V extends WithEquality>(...vals: V[]): Set<V>;
}
strange.ts
///<reference path="./strange.d.ts"/>
import * as S from 'strange';
const x = S.makeSetUnsafe(1,2,3);
x.add(4);
const y = S.makeSet(1,2,3);
y.add(4);
Expected behavior:
From my understanding the code should compile. Typescript should infer number
for both examples as the type, and since number
is an option in WithEquality
, and the constraint is T extends WithEquality
, all should be fine.
Actual behavior:
The call to makeSetUnsafe
compiles fine, but the call to makeSet
fails with this error:
strange.ts(9,7): error TS2345: Argument of type '4' is not assignable to parameter of type '1 | 2 | 3'.
Adding the generic constraint to check that the generic type of the Set
interface extends WithEquality
causes the inference to pick 1|2|3
instead of number
for T
.
Giving the type explicitly with const y = S.makeSet<number>(1,2,3);
makes it build, so it seems adding the generic constraint makes the type inference pick another type.
In fact I can reproduce the issue even with the simpler
export type WithEquality = number;
A good answer would explain why this code is wrong, hopefully give a typescript implementation allowing to express these constraints with the type inference working, or confirm that it's a typescript limitation.