typescript学习二
window.pageYOffset || document.documentElement.scrollTop获取滑动距离。
1.问题一:typescript既有type annotations也有type inference,那么问题来了,如果定义一个变量,但是既不显示说明类型,又不进行赋值的话,那么他在typescript里面是什么类型呢?
答案:是any类型。但是呢,最佳实践是尽量少用any类型。
2.void类型,应用场景举例:加入一个函数只是打印日志的话,那么显然它是不具备什么返回值的,那么我们可以显示声明他的返回值是void,也可以借助typescript的type inference来推断出返回类型是void类型。如下所示:
1 | // 可以不type annotations,借助type inference |
3.never,这里粗略带过,与void所不同的是,void表示函数会把执行权力给移交出去,但是不具有返回值;而never表示的是函数永远执行,不返回。同时,typescript对于never的实现还不完善。比如下面这个例子如果把type annotations给去掉,借助typescript的type inference的话,那么会被推断为void。
1 | function loop(taskName: string): never { |
4.enum类型,话不多说,直接看例子:
1 | enum Status { |
枚举默认从0开始,但是也可进行修改:
1 | enum Status { |
也可以我都要插一手:
1 | enum Status { |
5.interface是啥子:An interface is a contract that defines a type with a collection of property and method definitions without any implementation。注意对于方法而言,interface无需实现。
使用interface所定义的类型去声明变量的时候,如果约定的东西和实际赋值的东西不同的话那么则会报错。
interface之optional properties:
1 | interface OrderDetail { |
function之optional param:
1 | function fun(s1?: string) { |
interface之readonly properties:
1 | interface Product { |
interface之extending interfaces:Interfaces can extend other interfaces so that they inherit all the properties and methods from its parent. 看个例子:
1 | interface Product { |
6.type关键字定义一个类型,啥我都当,如下所示:
1 | type getTotal = (discount: number) => number; // type关键字指代函数类型 |
type aliases can also define the shape of an object.
1 | type Product = { |
7.typescript中的class,有点像interface和type,如下所示:
1 | class Product { |
从上面也有一个疑问,引入了类型,但是price类型是number,输出却是undefined?其实,在typescript里面像下面这样定义也是行的:
1 | let a: number = undefined; |
这一点,很让人失望。
class之implementing interfaces,有什么好处暂时也不知道:
1 | interface IOrderDetail { |
class之extend class,举例如下所示:
1 | class Parent { |
如果父类中含有构造函数的话,那么子类也会将constructor给继承过来:
1 | class Parent { |
由于将父类的constructor也给继承过来了,所以在new的时候如果不传入参数的话将会报错。
如果子类也实现了constructor的话,那么必须调用super方法。
1 | class Parent { |
class之abstract classes:
关于定义:Abstract classes are a special type of class that can only be inherited from and not instantiated,可以看一个例子:
1 | abstract class AClass { |
class之Access modifiers:
对于一个类中所定义的方法和属性来说,访问权限都是默认为public的。这意味着这些属性以及方法在实例中以及子类下都是可访问的。同时,我们也可以显式的使用Access modifiers,只需要在属性名或者方法名之前加上Access modifiers谓词即可。
Access modifiers之private:这意味属性成员或者方法成员只能在class里面访问到,在class instance和child class中是无法访问到的。
1 | class OrderDetail { |
class之Property setters and getters:
我们可以对property应用一个getter方法和setter方法,对于class的private属性来说这将会变得特别有用,下面是一个例子:
1 | class MyClass { |
class之static:
我们可以对property和methods使用static,这表明这些被声明为static的property以及methods都是属于class自身的,因此在static方法内部是访问不到类实例的,下面介绍一个例子:
1 | class MyClass { |
8.typescript工程中的模块机制:默认情况下,你在A文件顶部作用域中所定义的变量都会被挂载到全局作用域中,除非你使用export关键字导出。因此这就造成了一个情况:如果你在A文件中定义了一个interface A的话,并且没有export的话,那么你在B文件中直接使用interface A也不会报错,因为他被挂载到了全局作用域之下。而这就造成了一个问题,那就是容易造成命名冲突问题。
9.turple之open-ended turples
1 | type Scores = [string, ...number[]]; |
10.turple function parameters之作为函数的参数处理,避免js自身利用rest参数作为函数参数的不足。
1 | type Scores = [string, ...number[]]; |
11.对于spread运算符来说,可以先看看js和ts的不同之处:
1 | function fun(a, b, c) { |
对于上面这个例子,在js中是能够正常运行的。但是在typescript中,同样的代码,则会报错。那么在typescript中,如何在函数中使用spread操作符呢?稍作修改,如下所示:
1 | function fun(a, b, c) { |
12.empty tuple,如果一个tuple被声明为空的话,那么便不可以具备值,如下所示:
1 | type EmptyTuple = []; |
13.tuple之optional tuple elements:
需要注意的是,可选参数需要放在最后面。可选参数后面要是有非可选参数的话,那么将会发生错误。
1 | type Scores = [number, number?, number?]; |
14.unknown type:在typescript3出来之前,对于不确定的属性一般都是使用any来定义变量的,但是如果使用了any的话,那么将用不上typescript的类型检查了。所以使用any是不到万不得已尽量是不要使用的,但是typescript3的unknown类型,在带来了不确定类型的场景使用下,还带来了类型检查,因此建议使用unknown类型替代any。
一个应用场景,利用unknown type来实现type guard。(测试下来好像和unknown没什么用,都是type guard的功劳)
1 | const typeCheck = (obj: any): obj is { firstName: string; age: number } => { |
15.Type narrowing with a type assertion:好像也和unknown没什么关系,还是多亏了类型断言。如下所示:
1 | type Big = { name: string; age: number }; |