typescript学习笔记(下)

简介: typescript学习笔记

## 静态属性

类的静态成员存在于类本身上面而不是类的实例上,在这个例子里,我们使用static定义origin,因为它是所有网格都会用到的属性,如同在实例属性上使用this,前缀来访问属性一样,这里我们使用Grid.来访问静态属性

```
class Grid {
    static origin = {x: 0, y: 0};
    getOrigin(){
        return Grid.origin.x;
    }
}
```

## 抽象类

抽象类作为其他派生类的基类使用。它们一般不会直接被实例化。不同于接口,抽象类可以包含成员的实现细节。abstract关键字是用于定义抽象类和在抽象类内部定义抽象方法。抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。

```
abstract class Animal {
    abstract makeSound(): void; // 若继承必须实现makeSound方法
    move(): void {
        console.log('roaming the earch...');
    }
}
```


# 函数


## 函数类型

typescript支持给每个参数添加类型之后再为函数本身添加返回值类型

``` 
function add(x: number, y: number): number {
    return x + y;
}
```


## 书写完整函数类型

函数的类型由参数类型和返回值组成,书写完整的函数类型以保证API信息的完整


## 可选参数

typescript中传递给一个函数的参数个数必须与函数期望的参数个数一致,在javascript中,每个参数都是可选的,可传可不传,在typescrip中要实现类似的功能,可以在参数名旁使用?实现可选参数的功能

```
function buildName(firstName: string, lastName?: string) {
    if(lastName) {
        return firstName + " " + lastName;
    }else {
        return firstName;
    }
}
```

可选参数必须跟在必须参数后面,如果上例想让first name可选的,那么就必须调整它们的位置,把first name放在后面。


## 默认参数

typescript可以为参数提供一个默认值

```
function buildName(firstName: string, lastName = "Smith") {
    return firstName + "" + lastName;
}
```

## 剩余参数

如果想同时操作多个参数,或者你并不知道会有多少参数传递进来,可以在...后面给定名字来定义这样剩余参数

```
function buildName(firstName: string, ... restOfName: string[]) {
    return firstName + " " + restOfName.join("");
}
let employeeName = buildName("joseph", "samuel", "lucas", "mackinzie");
```


## 重载

为了让编译器能够选择正确的检查类型,它与javascript里的处理流程相似。它查找重载列表,尝试使用第一个重载定义。如果匹配的话就使用这个。因此,在定义重载的时候,一定要把最精确的定义放在最前面。

```
function pick(x; {suit: string; card: number;}[]): number;
funciton pick(x: number): {suit: string; card: number;};
function pick(x): any {}
```

# 泛型

对于大型系统时,需要考虑组件API的可重用性,组件不仅要能够支持当前数据类型,同时还需要支持未来的数据类型,所以引入泛型的概念来创建可重用的组件


可能有些同学会觉得可以使用any类型,但是这样会导致类型的不确定性,你给到一个number类型的参数希望结果也是number类型,any类型并不能实现这个效果


** 泛型的最大特点在于通过变量来表示类型,而不是具体的值 **


## 泛型接口

```
function identity<arg: T>: T{
    return arg;
}
```


## 泛型类

```
class GenericNumber<T> {
    zeroValue: T;
    add: {x: T, y: T} => T;
}
```

## 泛型约束

当需要操作某个类型的某个属性,比如数组的length,但是因为用的是泛型,并不能确定这个属性是否有length,这里可以定义一个接口来描述约束条件,创建一个包含.length属性的接口,使用这个接口和extends关键字来实现约束

```
interface Lengthwise{
    length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T{
    console.log(arg.length);
    return arg;
}
```


## 在泛型约束中使用类型参数

可以声明一个类型参数,且它被另一个类型参数所约束,比如我们想要用属性名从对象里获取这个属性,且要确保这个属性存在于对象obj上

```
function getProperty(obj: T, key: K){
    return obj[key];
}
```

## 在泛型里使用类类型

在Typescript使用泛型创建工厂函数时,需要引用构造函数的类类型

```
function create<T>(c: {new(): T;}): T {
    return new c();
}
```

# 枚举

使用枚举可以定义一些带名字的常量,可以清晰地表达意图或者创建一组有区别的用例,typescript支持数字和基于字符串的枚举


## 数字枚举

通过枚举的属性来访问枚举成员,和枚举的名字来访问枚举类型

```
enum Response {
    No = 0,
    Yes = 1
}
function respond(recipient: string, message: Response): void {
    // ...
}
respond("Princess Caroline", Response.Yes);
```

## 字符串枚举

```
enum Direction {
    Up = "Up",
    Down = "Down",
    Left = "Left",
    Right = "Right"
}
```

## 混合枚举

从技术的角度来说,枚举可以混合字符串和数字成员,但是不建议这么做


## 计算和常量成员

每个枚举成员都带有一个值,它可以是常量或计算出来,当满足如下条件时,枚举成员被当作是常量:

- 它是枚举的第一个成员且没有初始化器,这种情况下它被赋予值0

```
enum E{x}
```

- 它不带有初始化器且它之前的枚举成员是一个数字常量。这种情况下,当前枚举成员的值为它上一个枚举成员的值加1

```
enum E{
    A = 1,B,C
}
```

- 枚举成员使用常量枚举表达式初始化。常数枚举表达式是typescript表达式的子集,它可以在编译阶段求值。


# 类型兼容性

与js中不同的,typescript的object的类型会区分各种各样的类,并不能像js中随意赋值


## 基本规则

如果x要兼容要,那么y至少具有与x相同的属性,即y是否能赋值给x,编译器检查x中的每个属性,看是否能在y中也找到对应属性


# 高级类型

## 交叉类型

把多种类型叠加到一起成为一种类型,下面是如何创建混入的一个简单例子:

```
function extend<T, U>(first: T, second: U): T&U {
    let result = <T & U>{};
    for(let id in first) {
        (<any>result)[id] = (<any>first)[id];
    }
    for(let id in second) {
        if(!result.hasOwnProperty(id)) {
            (<any>result)[id] = (<any>second)[id];
        }
    }
    return result;
}
```

# 模块


typescript与ES5一样,任何包含顶级import或者export的文件都被当作一个模块。相反地,如果一个文件不带顶级的import或者export声明,那么它的内容被视为全局可见的


# 命名空间

我们需要一种手段来组织代码,以便于在记录它们类型的同时还不用担心与其它对象产生命名冲突。因此,我们把验证器包裹到一个命名空间内,而不是把它们放在全局命名空间下


## 分离到多文件

当应用变得越来越大时,我们需要将代码分离到不同的文件中以便于维护

```
// Validation.js
namespace Validation {
    export interface StringValidator {
        isAcceptable(s: string): boolean;
    }
}
```

## 别名

另一种简化命名空间操作的方法是使用`import q = x.y.z;`给常用的对象起一个短的名字

```
namespace Shapes {
    export namespace Polygons {
        export class Triangle{};
        export class Square{};
    }
}
import polygons = Shapes.Polygons;
let sg = new polygons.Square();
```


# 声明合并

"声明合并"是指编译器将针对同一个名字的两个独立声明合并为单一声明。合并后的声明同时拥有原先两个声明的特性,任何数量的声明都可被合并;不局限两个声明


## 合并接口

最简单也是最常见的合并类型是接口合并。从根本上说,合并的机制是把双方的成员放到一个同名的接口里。

```
interface Box {
    height: number;
    width: number;
}
interface Box {
    scale: number;
}
```

这两个接口将合并成一个声明:

```
interface Box {
    height: number;
    width: number;
    scale: number;
}
```


## 合并命名空间

同接口


## 非法合并

typescript并非允许所有的合并。目前,类不能与其它类或者变量合并

目录
相关文章
|
6月前
|
JavaScript 前端开发
TypeScript 学习笔记(六):TypeScript 与前端框架的结合应用
笔记,进一步提升 TypeScript 编程技能。
76 1
|
5月前
|
JavaScript 安全 前端开发
TypeScript 基础学习笔记:interface 与 type 的异同
TypeScript 基础学习笔记:interface 与 type 的异同
65 0
|
5月前
|
JavaScript 安全 编译器
TypeScript 基础学习笔记:泛型 <T> vs 断言 as
TypeScript 基础学习笔记:泛型 <T> vs 断言 as
106 0
|
6月前
|
JavaScript 前端开发 编译器
TypeScript 学习笔记
TypeScript 学习笔记
|
JavaScript
TypeScript 学习笔记2
TypeScript 学习笔记2
68 0
|
资源调度 JavaScript 前端开发
TypeScript 学习笔记1
TypeScript 学习笔记
77 0
|
JavaScript C++ Windows
TypeScript学习笔记
TypeScript学习笔记
|
前端开发 JavaScript
Vue3+TypeScript学习笔记(三十五)
本节记录Web Component相关知识内容
69 0
|
缓存 JavaScript
Vue3+TypeScript学习笔记(三十四)
本节记录Vue3相关高级性能优化技巧
126 0
|
JavaScript 前端开发
Vue3+TypeScript学习笔记(三十三)
本节记录函数式编程——h函数相关内容
93 0