[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.
[TypeScript] Understanding Generics with RxJS的更多相关文章
- [TypeScript] Understanding Decorators
Decorators are a feature of TypeScript that are becoming more and more common in many major librarie ...
- [RxJS] Creating Observable From Scratch
Get a better understanding of the RxJS Observable by implementing one that's similar from the ground ...
- TypeScript 零基础入门
前言 2015 年末看过一篇文章<ES2015 & babel 实战:开发 npm 模块>,那时刚接触 ES6 不久,发觉新的 ES6 语法大大简化了 JavaScript 程序的 ...
- RxJS - Subject(转)
Observer Pattern 观察者模式定义 观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态 ...
- 10 Essential TypeScript Tips And Tricks For Angular Devs
原文: https://www.sitepoint.com/10-essential-typescript-tips-tricks-angular/ ------------------------- ...
- 8分钟为你详解React、Angular、Vue三大前端技术
[引言] 当前世界中,技术发展非常迅速并且变化迅速,开发者需要更多的开发工具来解决不同的问题.本文就对于当下主流的前端开发技术React.Vue.Angular这三个框架做个相对详尽的探究,目的是为了 ...
- springcloud starter(一)
Spring Cloud - Getting Started Example, 转载自:https://www.logicbig.com/tutorials/spring-framework/spri ...
- angular2版本迭代之特性追踪
一. 2.0.0 升级到 2.4 升级前: 1.确保没有使用extends关键字实现OnInit的继承,以及没有用任何的生命周期中,而是全部改用implements. 2.停止使用deep impor ...
- angularCli打包遇到的一些问题
有时在运行项目或者打包项目的时候会遇到报错信息:found version 4, expected 3, 这个大概意思是说该插件需要的依赖当前不支持,需要提高依赖的版本. 比如:@angular/co ...
随机推荐
- 安装ImageMagick扩展出现configure: error: not found. Please provide a path to MagickWand-config or Wand- config program
安装ImageMagick扩展报错: checking ImageMagick MagickWand API configuration program... checking Testing /u ...
- User Commands
archive Creates a hadoop archive[v.存档; n.档案文件; 档案室; ]. More information can be found at Hadoop Archi ...
- SQL脚本小笔记
--表添加字段.说明--- --脚本 alter table 表名 ADD 字段名 FLOAT(类型) NOT NULL Default 0(默认值) EXECUTE sp_addextendedpr ...
- MVC3的一个意外的异常 String was not recognized as a valid Boolean. @using (Html.BeginForm())
客户的网站放在一个虚拟空间,之间都没有修改过程序.可是网站的后台登录页面报错 String was not recognized as a valid Boolean. ,错误指向@using (H ...
- Windows常见蓝屏故障分析
转自Windows常见蓝屏故障分析 症状描述: 当您在运行Microsoft Windows 2000/XP/Server 2003.Microsoft Windows Vista/Server 20 ...
- Android 使用HttpClient方式提交POST请求
final String username = usernameEditText.getText().toString().trim(); final String password = passwr ...
- Keil_C51程序调试过程
调试一般都是在发生错误与意外的情况下使用的.如果程序能正常执行,调试很多时候都是用不上的.所以,最高效率的程序开发还是程序员自己做好规范,而不是指望调试来解决问题. 单片机的程序调试分为两种,一种是使 ...
- 详解Linux配置iSCSI方法
iSCSI技术是在2001年初由IBM及Cisco联合制定的技术,在2003年5月微软在 Windows 2003中 开始自己正式支持iSCSI微软此举很大程度上的推动了iSCSI技术的发展.下面为大 ...
- Apache HBase RPC身份验证中间人安全措施绕过漏洞(CVE-2013-2193)
漏洞版本: Apache Group HBase 0.94.x Apache Group HBase 0.92.x 漏洞描述: BUGTRAQ ID: 61981 CVE(CAN) ID: CVE-2 ...
- vs2008 提示msdbg.dll未正确安装的解决办法
开始-->运行-->输入: regsvr32.exe "%ProgramFiles(x86)%\Common Files\Microsoft Shared\VS7Debug\ms ...