TypeScript版本: 2.6.0-dev.20170826和2.4.2
我想知道我是否遇到了一些打字稿推理错误/限制,或者我的代码是不正确的。如果代码实际上是有效的,并且它是类型推断问题,我会向typescript github报告错误。
我试图将Set
构建器限制为仅接受正确定义了相等性的类型(以避免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);
预期行为
根据我的理解,代码应该编译。打字稿应该推断number
这两个例子的类型,因为number
是WithEquality
中的一个选项,而约束是T extends WithEquality
,所以一切都应该没问题。
实际行为
对makeSetUnsafe
的调用编译正常,但对makeSet
的调用失败并出现此错误:
strange.ts(9,7): error TS2345: Argument of type '4' is not assignable to parameter of type '1 | 2 | 3'.
添加通用约束以检查Set
接口的泛型类型是否扩展WithEquality
会导致推断为1|2|3
选择number
而不是T
使用const y = S.makeSet<number>(1,2,3);
显式赋予类型使其构建,因此似乎添加泛型约束使类型推断选择另一种类型。
事实上,即使使用更简单的
,我也可以重现这个问题export type WithEquality = number;
一个好的答案可以解释为什么这段代码是错误的,希望给出一个打字稿实现,允许用类型推理工作来表达这些约束,或者确认它是打字稿限制。
答案 0 :(得分:2)
至于为什么会发生这种情况,请检查此问题的答案:
Type variable constrained to primitive or union type not assignable to it
你可以这样解决:
export function makeSet<V>(...vals: Array<V & WithEquality>): Set<V>;
然后:
const y = makeSet2(1,2,3);
y.add(4); // fine
const z = makeSet(/a*/); // error