TypeScript Version: 2.6.0-dev.20170826 and 2.4.2
I'm questioning whether I've encountered a TypeScript inference bug or limitation, or if my code is simply incorrect. If the code is valid and it's an issue with type inference, I will report it on the TypeScript GitHub repository.
The goal is to restrict the builder for the Set
to only accept types for which equality is properly defined, to avoid encountering a specific problem as mentioned in a Stack Overflow post.
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:
Based on my understanding, the code should compile without any errors. TypeScript should infer the type number
for both examples, given that number
is an option in WithEquality
and the constraint is T extends WithEquality
.
Actual behavior:
Although the call to makeSetUnsafe
compiles without errors, the call to makeSet
fails with an error message indicating the argument '4' is not assignable to the parameter '1 | 2 | 3'.
Adding the generic constraint to ensure the type of the Set
interface extends
WithEquality</code causes the inference to select <code>1|2|3
instead of number
for T
.
Explicitly specifying the type with
const y = S.makeSet<number>(1,2,3);
resolves the build issue, suggesting that adding the generic constraint alters the type inference decision.
Interestingly, the same issue can be replicated even with a simpler code snippet:
export type WithEquality = number;
An ideal response would clarify why this code is incorrect, provide a TypeScript implementation that expresses these constraints with successful type inference, or confirm whether this is a limitation of TypeScript.