在另一个中引用嵌套的泛型参数

时间:2018-02-06 10:29:04

标签: typescript

假设我有一个适用于ID为$ ./bin/month_roll enter +/- to inc/decrement month ('q' to quit) month : 6 : - month : 5 : - month : 4 : - month : 3 : - month : 2 : - month : 1 : - month : 12 : - month : 11 : - month : 10 : + month : 11 : + month : 12 : + month : 1 : + month : 2 : - month : 1 : - month : 12 : - month : 11 : - month : 10 : + month : 11 : + month : 12 : + month : 1 : + month : 2 : + month : 3 : q 个对象的函数,以及一个用于相同item

集合的接口
items

我想实现一个函数签名,用于将项添加到项集合中。为此,我需要强制嵌套在Collectable接口中的Item类型和Item类型是相同的

interface Item {
    id: string
}

interface Collectable<T extends Item> extends Object {
    entities: { [key: string]: T },
    ids: string[]
};

允许这样的事情

export function addToCollection<C extends Collectable<T>> (collection: C, item: T): C

问题是我找不到这样做的方法,也没有将嵌套类型T指定为类型参数

有什么建议吗?

1 个答案:

答案 0 :(得分:1)

您需要将T添加到函数类型参数列表中:

export function addToCollection<T extends Item, C extends Collectable<T>> (collection: C, item: T): C {
    return null;
}

declare var c: Collectable<{ id: string, n: string }>;
declare var d: { id: string, n: string };
addToCollection(c, d); // works T and C are inferred correctly 

这也适用于派生类型:

interface Apple extends Item {
    name : string;
    size: number;
}
interface AppleCollectable extends   Collectable<Apple>{
    bushelSize: number

}
declare var apples: AppleCollectable;
declare var a: Apple;
addToCollection(apples, a); // Works correctly, returns AppleCollectable
declare var applesBase: Collectable<Apple>;
addToCollection(applesBase, a); // returns Collectable<Apple> 

修改

上面实现的一个问题是以下代码编译:

addToCollection(apples, { id: "" })

typescript推断泛型参数的方式存在问题,它无法根据它所依赖的另一个类型参数推断T(在本例中为C extends Collectable<T>)。它可以检查它,但它不能推断它。

一种选择是锁定T是谁,并采取Collectable<T>

export function addToCollection<T extends Item>(collection: Collectable<T>) {
    return function (item: T): Collectable<T> {
        return null; // Actual code
    };
}
addToCollection(apples)(a); // Works
addToCollection(apples)({ id: "" }) // Does not work

此方法的问题是返回类型为Collectable<T>而不是AppleCollectable。对此的丑陋工作是指定参数两次,一次为Collection<T>,一次为C,但这绝对不是一个理想的解决方案:

export function addToCollection<T extends Item, C extends Collectable<T>>(collection: Collectable<T>, dummy: C) {
    return function (item: T): C {
        return null;
    };
}
addToCollection(apples, apples)({ id: "" }) // returns AppleCollectable

然而,最简单的解决方案是将add函数添加到接口:

interface Collectable<T extends Item> extends Object {
    entities: { [key: string]: T },
    ids: string[]
    addToCollection(item: T): this;
};
interface AppleCollectable extends Collectable<Apple> {
    bushelSize: number
}
apples.addToCollection(a).bushelSize // addToCollection return AppleCollectable 
apples.addToCollection({ id: "" }) // does not work