typescript:泛型约束导致类型推断挑选错误的候选者?

时间:2017-08-27 07:40:56

标签: typescript generics

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这两个例子的类型,因为numberWithEquality中的一个选项,而约束是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;

一个好的答案可以解释为什么这段代码是错误的,希望给出一个打字稿实现,允许用类型推理工作来表达这些约束,或者确认它是打字稿限制。

1 个答案:

答案 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