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.
As for why that happens, check the answer to this issue:
Type variable constrained to primitive or union type not assignable to it .
You can fix it like this:
export function makeSet<V>(...vals: Array<V & WithEquality>): Set<V>;
And then:
const y = makeSet2(1,2,3);
y.add(4); // fine
const z = makeSet(/a*/); // error
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.