我一直在研究如何更改Observable的返回类型。
我正在使用Angular 5.
以下是一个例子:
public getButterfly(): Observable<Butterfly[]> {
return http.get<Larva[]>('url').pipe(
map( larva => new Butterfly(larva.dna))
);
}
此代码导致错误,因为编译器期望幼虫对象因为返回值而成为Butterfly,并抛出错误:
“错误TS2339:'蝴蝶[]'类型中不存在属性'id'。”
似乎打字稿不允许在observable中进行类型更改,但如果你知道一种方法,我就是全部的耳朵。
感谢您对我的问题感兴趣。
答案 0 :(得分:5)
我认为已接受的答案掩盖了更大的问题,也许您对map
在rxjs中的实际作用感到困惑。
在“普通” JavaScript中,map()
函数直接在数组上操作,并为数组中的每个项目运行一个函数。例如。 [1,2,3].map(x => x + 1)
。您立即取回与原始长度相同的完整数组-包含转换后的项目。
在rxjs
中,它是rxjs的一部分,它是一个完全不同的函数,仅与Array的map
具有相同的名称(如果您敢,请查找源代码!)。
您传递给rxjs map()
的实际函数仍然采用单个值并返回单个值(因此,它看起来非常像纯JavaScript映射),但是它不是在数组上进行操作,而是在单个上进行操作流中值。
好的,所以您已经知道RXJS与流有关!而且您有幼虫流! (我不知道这是恐怖还是可爱!)
实际上你不知道。 使用http.get
确实有一个流,但是它仅包含一个值,并且该值是http调用的整个响应,无论它是什么。
从外观上看,您正在从get
调用中返回一个幼虫对象数组,但是就RXJS而言,这是一个唯一的流。
这是您的原始代码(带注释):
public getButterfly(): Observable<Butterfly[]> {
return http.get<Larva[]>('url').pipe(
map( larva => {
// We are now inside the RXJS 'map' function, NOT a Javascript map
// here larva is an ARRAY (assuming your HTTP call actually returns an array)
// So if you execute larva.dna you'll get 'undefined'
// (because dna is not a property on a javascript array!)
// So you will return a butterfly OBJECT, but initialized with 'undefined' DNA. Scary!
return new Butterfly(larva.dna);
})
);
}
所以我认为您真正想要的是:
public getButterflies() {
return http.get<Larva[]>('url').pipe(
map( larvae => larvae.map(larva => new Butterfly(larva.dna)))
);
}
如果那没有立即意义,那就是发生了什么:
map
函数,并为每个项目创建一个蝶形。然后,您将该新的蝶形数组作为流中的替换项返回。Butterfly[]
通过坚持使用<Larva, Butterfly>
,您只是告诉就是这样的编译器,因此不会出现编译时错误。您永远不会更改任何内容。
PS。有时,我喜欢指定输出类型,这很简单-为了显示“管道”内部的错误。如果我有多个代码路径,则每个路径必须返回相同的代码,我将执行此操作。通过限制输出类型,它揭示了更多的错误。
提示:在管道中使用tap(x => console.log('Message', x)
将每个阶段的内容写到控制台,如下所示:
public getButterflies() {
return http.get<Larva[]>('url').pipe(
tap( x => console.log('Before map', x) ),
map( larvae => larvae.map(larva => new Butterfly(larva.dna)),
tap( x => console.log('After map', x) )
));
}
为什么叫水龙头?因为管道有水龙头!而且,(普通水)水龙头可以让您看到(普通水)管道内的东西:-)
答案 1 :(得分:3)
map
运算符的类型定义如下:
export declare function map<T, R>(
project: (value: T, index: number
) => R, thisArg?: any): OperatorFunction<T, R>;
如您所见,您可以在map
运算符调用中设置泛型类型。在您的示例中,T
值为Butterfly,R
值为Larva。
public getButterfly(): Observable<Butterfly[]> {
return http.get<Larva[]>('url').pipe(
map<Larva, Butterfly>(larva => new Butterfly(larva.dna))
);
}