非规范化数组<a> and Array<b> where clause is true, set B as named property on A

时间:2017-11-29 14:16:25

标签: typescript generics

I'm trying to 'denormalize' two arrays (IObservableArray and IObservableArray) where array A has objects with id's that point to id's of objects in array B. I would like to put objects from array B that match the id of the object in array A on object A as a dynamically named property. The arrays are IObservableArrays from mobx but that should not be of importance.

I'm trying to achieve this:

var aArr: IObservableArray<A extends { bId: number }>;
var bArr: IObservableArray<B extends { id: number }>;

var d = denormalize(aArr, bArr, (a, b) => a.bId === b.id, "b");
console.log(d[0].b) // => B 

I tried the following:

export function denormalize<A, B, K extends string, TRet extends A & {[asProperty: K]: B}>(
    arr1: IObservableArray<A>,
    arr2: IObservableArray<B>,
    where: (a: A, b: B) => boolean,
    asProperty: K
): IObservableArray<TRet> {
    return observable.array(); // stub
}

But it says [ts] An index signature parameter type must be 'string' or 'number'. (parameter) k: K extends string

Is there a way to make the A[asProperty]: B work so that the compiler knows that the type returned by denormalize has an additional property with name asProperty and it autocompletes as such?

1 个答案:

答案 0 :(得分:2)

您不能在索引签名中使用泛型类型,索引器参数必须为stringnumber(这取决于spec)。

您可以使用映射类型语法([Prop in Key] : Type

export function denormalize<A, B, K extends string, TRet extends A & { [P in K]: B}>(
    arr1: IObservableArray<A>,
    arr2: IObservableArray<B>,
    where: (a: A, b: B) => boolean,
    asProperty: K
): IObservableArray<TRet> {
    // ...
}

会工作:

console.log(d[0].b) // => B 

修改

正如@jcalz在评论中提到的,签名也可以使用与Record<K extends string, T>相同的{ [P in K]: B}>类型。使用此签名将是:

export function denormalize<A, B, K extends string, TRet extends A &  Record<K,B>>(
    arr1: IObservableArray<A>,
    arr2: IObservableArray<B>,
    where: (a: A, b: B) => boolean,
    asProperty: K
): IObservableArray<TRet>