[TypeScript] Understanding Generics with RxJS
Libraries such as RxJS use generics heavily in their definition files to describe how types flow through different interfaces and function calls. We can provide our own type information when we create Observables to enable all of the auto-complete & type-safety features that you would expect from Typescript. This can be achieved with minimal annotations thanks to the power of generics.
import Rx = require('rx'); Rx.Observable.interval(100) .subscribe( (x) => { console.log(x); });
The way Typescript can understand the 'x' inside console.log() is type of number is because its type defination.
rx.all.d.ts:
export interface ObservableStatic { /** * Returns an observable sequence that produces a value after each period. * * @example * 1 - res = Rx.Observable.interval(1000); * 2 - res = Rx.Observable.interval(1000, Rx.Scheduler.timeout); * * @param {Number} period Period for producing the values in the resulting sequence (specified as an integer denoting milliseconds). * @param {Scheduler} [scheduler] Scheduler to run the timer on. If not specified, Rx.Scheduler.timeout is used. * @returns {Observable} An observable sequence that produces a value after each period. */ interval(period: number, scheduler?: IScheduler): Observable<number>; }
As we can see, the return type is number.
So interval return a number, but how in subscribe function also know 'x' is number type.
To understand that, we can go subscribe defination:
export interface Observable<T> { /** * Subscribes an o to the observable sequence. * @param {Mixed} [oOrOnNext] The object that is to receive notifications or an action to invoke for each element in the observable sequence. * @param {Function} [onError] Action to invoke upon exceptional termination of the observable sequence. * @param {Function} [onCompleted] Action to invoke upon graceful termination of the observable sequence. * @returns {Diposable} A disposable handling the subscriptions and unsubscriptions. */ subscribe(observer: IObserver<T>): IDisposable; /** * Subscribes an o to the observable sequence. * @param {Mixed} [oOrOnNext] The object that is to receive notifications or an action to invoke for each element in the observable sequence. * @param {Function} [onError] Action to invoke upon exceptional termination of the observable sequence. * @param {Function} [onCompleted] Action to invoke upon graceful termination of the observable sequence. * @returns {Diposable} A disposable handling the subscriptions and unsubscriptions. */ subscribe(onNext?: (value: T) => void, onError?: (exception: any) => void, onCompleted?: () => void): IDisposable; /** * Subscribes to the next value in the sequence with an optional "this" argument. * @param {Function} onNext The function to invoke on each element in the observable sequence. * @param {Any} [thisArg] Object to use as this when executing callback. * @returns {Disposable} A disposable handling the subscriptions and unsubscriptions. */ subscribeOnNext(onNext: (value: T) => void, thisArg?: any): IDisposable; /** * Subscribes to an exceptional condition in the sequence with an optional "this" argument. * @param {Function} onError The function to invoke upon exceptional termination of the observable sequence. * @param {Any} [thisArg] Object to use as this when executing callback. * @returns {Disposable} A disposable handling the subscriptions and unsubscriptions. */ subscribeOnError(onError: (exception: any) => void, thisArg?: any): IDisposable; /** * Subscribes to the next value in the sequence with an optional "this" argument. * @param {Function} onCompleted The function to invoke upon graceful termination of the observable sequence. * @param {Any} [thisArg] Object to use as this when executing callback. * @returns {Disposable} A disposable handling the subscriptions and unsubscriptions. */ subscribeOnCompleted(onCompleted: () => void, thisArg?: any): IDisposable; /** * Subscribes an o to the observable sequence. * @param {Mixed} [oOrOnNext] The object that is to receive notifications or an action to invoke for each element in the observable sequence. * @param {Function} [onError] Action to invoke upon exceptional termination of the observable sequence. * @param {Function} [onCompleted] Action to invoke upon graceful termination of the observable sequence. * @returns {Diposable} A disposable handling the subscriptions and unsubscriptions. */ forEach(observer: IObserver<T>): IDisposable; /** * Subscribes an o to the observable sequence. * @param {Mixed} [oOrOnNext] The object that is to receive notifications or an action to invoke for each element in the observable sequence. * @param {Function} [onError] Action to invoke upon exceptional termination of the observable sequence. * @param {Function} [onCompleted] Action to invoke upon graceful termination of the observable sequence. * @returns {Diposable} A disposable handling the subscriptions and unsubscriptions. */ forEach(onNext?: (value: T) => void, onError?: (exception: any) => void, onCompleted?: () => void): IDisposable; }
As we can see 'onNext' method it use '<T>' it get from the 'Observable<T>' interface. How's how TypeScript understand console.log(x)'s x should be number type.
So how can we create a type safe Observable by ourselves?
Rx.Observable.create( (observer) => { observer.onNext({ path: '/user/share', event: 'add' }) }).subscribe( (x) => { console.log(x); });
For this part of code, we want Typescipt help us autocomplete and report error if we pass something like 'x.path1' which not exists.
First we add an interface:
interface FileEvent{ path: string, event: 'add' | 'change' }
We can add the interface to the subscribe, it will give the type checking and autocomplete:
Rx.Observable.create( (observer) => { observer.onNext({ path: '/user/share', event: 'add' }) }).subscribe( (x: FileEvent) => { console.log(x); });
The problem for this is if you have multi subscriber, you don't want to copy this everywhere.
What actually we should do is provide the interface at the topest level:
Rx.Observable.create<FileEvent>( (observer) => { observer.onNext({ path: '/user/share', event: 'add' }) }).subscribe( (x) => { console.log(x); });
To recap, create is a generic function which means we can pass a type when we call it. Then, thanks to the type definitions that are provided by the RxJS library, this type can now flow into the observer as you can see here, it enables type safety on the onNext method, and even makes it all the way through to the subscribe method.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具