Skip to content

TypeScript 简介 #101

@coconilu

Description

@coconilu

概述

TypeScript是JavaScript的超集。主要提供了类型系统和对 ES6 的支持。
TypeScript支持与JavaScript几乎相同的数据类型,此外还提供了实用的枚举类型方便我们使用。
TypeScript的核心原则之一是对值所具有的结构进行类型检查。 它有时被称做“鸭式辨型法”或“结构性子类型化”。

  1. 类型系统
    • 基础类型
    • 接口
    • 函数
    • 泛型
    • 枚举
    • 高级类型
    • 模块
    • 命名空间
    • 其它
  2. 类型操作
    • 类型断言
    • 类型推断
    • 类型兼容性
    • 声明合并
  3. 高级特性
    • 装饰器
    • Mixins
    • 三斜线指令
    • JavaScript文件类型检查
  4. 书写声明文件
    • 规范
    • 声明文件的原理
  5. 工程配置

类型系统

基础类型

  1. boolean
  2. number
  3. string
  4. 数组
  5. 元组
  6. 枚举
  7. any
  8. void
  9. null
  10. undefined
  11. never
  12. object,{x: base-type}

接口

接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约。
接口能够描述JavaScript中对象拥有的各种各样的外形,包括函数对象。

接口只关注外形(属性是否存在),不会在乎顺序。
可选属性:?
只读属性:readonly
可以添加任意数量的其它属性:[propName: string]: any;
函数声明:(source: string, subString: string): boolean;
可索引类型
类类型,实现接口,静态部分与实例部分
继承接口
混合类型
接口继承类

继承:extends
公共,私有与受保护的修饰符:public(默认)、private、protected
readonly修饰符
参数属性
存取器
静态属性
抽象类:abstract
构造函数
把类当做接口使用

函数

函数类型包含两部分:参数类型和返回值类型:

(x: number, y: number) => number

可选参数:?
默认参数:=
剩余参数:...
箭头函数:=>
this参数:this参数是个假的参数,它出现在参数列表的最前面
重载:为了让编译器能够选择正确的检查类型,它与JavaScript里的处理流程相似。 它查找重载列表,尝试使用第一个重载定义。 如果匹配的话就使用这个。 因此,在定义重载的时候,一定要把最精确的定义放在最前面。

泛型

在像C#和Java这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。

泛型类型

泛型类

泛型类使用( <>)括起泛型类型,跟在类名后面。

泛型约束

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

枚举

使用枚举我们可以定义一些带名字的常量。 使用枚举可以清晰地表达意图或创建一组有区别的用例。

数字枚举
字符串枚举
异构枚举

高级类型

交叉类型

符号: &

联合类型

符号: |

类型保护与区分类型

typeof类型保护,只有两种形式能被识别: typeof v === "typename"和 typeof v !== "typename"
instanceof类型保护,通过构造函数来细化类型的一种方式

可以为null的类型

string | null, string | undefined和 string | undefined | null是不同的类型。

如果编译器不能够去除 null或 undefined,你可以使用类型断言手动去除。 语法是添加 !后缀: identifier!从 identifier的类型里去除了 null和 undefined

类型别名

类型别名会给一个类型起个新名字。 类型别名有时和接口很像,但是可以作用于原始值,联合类型,元组以及其它任何你需要手写的类型。

字符串字面量类型

字符串字面量类型允许你指定字符串必须的固定值。

数字字面量类型

TypeScript还具有数字字面量类型。

枚举成员类型

当每个枚举成员都是用字面量初始化的时候枚举成员是具有类型的。

可辨识联合

你可以合并单例类型,联合类型,类型保护和类型别名来创建一个叫做 可辨识联合的高级模式,它也称做 标签联合或 代数数据类型。

多态的 this类型

多态的 this类型表示的是某个包含类或接口的 子类型。 这被称做 F-bounded多态性。 它能很容易的表现连贯接口间的继承

索引类型

keyof T, 索引类型查询操作符

映射类型

type Partial<T> = {
    [P in keyof T]?: T[P];
}

模块

导出

  1. 导出声明:export ...
  2. 重新导出:export * from ...
  3. 默认导出:export default ...

导入

  1. 导入一个模块中的某个导出内容:import {} from ...
  2. 将整个模块导入到一个变量,并通过它来访问模块的导出部分:import * as ... from ...
  3. 具有副作用的导入模块:import ...

命名空间

使用命名空间(之前叫做“内部模块”)来组织代码:namespace

其它

只读数组:ReadonlyArray

类型操作

类型断言

两种形式:

  1. 尖括号
  2. as

类型推断

TypeScript里,在有些没有明确指出类型的地方,类型推论会帮助提供类型。
当需要从几个表达式中推断类型时候,会使用这些表达式的类型来推断出一个最合适的通用类型
当需要从几个表达式中推断类型时候,会使用这些表达式的类型来推断出一个最合适的通用类型

类型兼容性

TypeScript里的类型兼容性是基于结构子类型的。 结构类型是一种只使用其成员来描述类型的方式。
TypeScript结构化类型系统的基本规则是,如果x要兼容y,那么y至少具有与x相同的属性。
要查看x是否能赋值给y,首先看它们的参数列表。 x的每个参数必须能在y里找到对应类型的参数。
类型系统强制源函数的返回值类型必须是目标函数返回值类型的子类型。

声明合并

指编译器将针对同一个名字的两个独立声明合并为单一声明。

  1. 合并接口
  2. 合并命名空间
  3. 命名空间与类和函数和枚举类型合并
  4. 非法的合并
  5. 模块扩展

高级特性

装饰器

装饰器(Decorators)为我们在类的声明及成员上通过元编程语法添加标注提供了一种方式。

若要启用实验性的装饰器特性,你必须在命令行或tsconfig.json里启用experimentalDecorators编译器选项。

装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上。装饰器使用 @expression这种形式。

创建装饰器

装饰器工厂,如下:

function color(value: string) { // 这是一个装饰器工厂
    return function (target) { //  这是装饰器
        // do something with "target" and "value"...
    }
}

装饰器组合

@f 
@g 
x  

等同于 

f(g(x))

类装饰器

类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。
如果你要返回一个新的构造函数,你必须注意处理好原来的原型链。 在运行时的装饰器调用逻辑中不会为你做这些。

方法装饰器

被应用到方法的 属性描述符上,可以用来监视,修改或者替换方法定义。

方法装饰器表达式会在运行时当作函数被调用,传入下列3个参数:

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  2. 成员的名字。
  3. 成员的属性描述符。

访问器装饰器

访问器装饰器应用于访问器的 属性描述符并且可以用来监视,修改或替换一个访问器的定义。

问器装饰器表达式会在运行时当作函数被调用,传入下列3个参数:

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  2. 成员的名字。
  3. 成员的属性描述符。

属性装饰器

属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数:

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  2. 成员的名字。

参数装饰器

参数装饰器应用于类构造函数或方法声明。

参数装饰器表达式会在运行时当作函数被调用,传入下列3个参数:

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  2. 成员的名字。
  3. 参数在函数参数列表中的索引。

元数据

实验性的API。

Mixins

除了传统的面向对象继承方式,还流行一种通过可重用组件创建类的方式,就是联合另一个简单类的代码。

使用implements把类当成了接口。这意味着我们需要在类里面实现接口。 但是这是我们在用mixin时想避免的。

混入操作。 遍历mixins上的所有属性,并复制到目标上去,把之前的占位属性替换成真正的实现代码。

三斜线指令

/// <reference path="..." />指令是三斜线指令中最常见的一种。 它用于声明文件间的依赖。三斜线引用以它们在文件里出现的顺序,使用深度优先的方式解析。

/// <reference types="..." />,声明了对某个包的依赖。

/// <reference no-default-lib="true"/>,这个指令把一个文件标记成默认库。

/// <amd-module />,指令允许给编译器传入一个可选的模块名

/// <amd-dependency />,告诉编译器有一个非TypeScript模块依赖需要被注入,做为目标模块require调用的一部分。

JavaScript文件类型检查

用JSDoc类型表示类型信息

下面的列表列出了当前所支持的JSDoc注解:

  1. @type
  2. @param (or @arg or @argument)
  3. @returns (or @return)
  4. @typedef
  5. @callback
  6. @template,声明泛型
  7. @Class (or @constructor),标记为构造函数
  8. @this,标记this类型
  9. @extends (or @Augments)
  10. @enum

属性的推断来自于类内的赋值语句

编译器从类内部的属性赋值语句来推断属性类型。
属性的类型是在构造函数里赋的值的类型,除非它没在构造函数里定义或者在构造函数里是undefined或null。
如果一个属性从没在类内设置过,它们会被当成未知的。

构造函数等同于类

编译器支持这种模式并能够将构造函数识别为ES2015的类。

支持CommonJS模块

对exports和module.exports的赋值被识别为导出声明。

类,函数和对象字面量是命名空间

对象字面量是开放的

.ts文件里,用对象字面量初始化一个变量的同时也给它声明了类型。
这个规则在.js文件里被放宽了;对象字面量具有开放的类型,允许添加并访问原先没有定义的属性。

null,undefined,和空数组的类型是any或any[]

任何用null,undefined初始化的变量,参数或属性,它们的类型是any,就算是在严格null检查模式下。
任何用[]初始化的变量,参数或属性,它们的类型是any[],就算是在严格null检查模式下。

函数参数是默认可选的

.js文件里所有函数参数都被当做是可选的。
需要注意的一点是,使用过多的参数调用函数会得到一个错误。

由arguments推断出的var-args参数声明

如果一个函数的函数体内有对arguments的引用,那么这个函数会隐式地被认为具有一个var-arg参数(比如:(...arg: any[]) => any))。

未指定的类型参数默认为any

由于JavaScript里没有一种自然的语法来指定泛型参数,因此未指定的参数类型默认为any。

书写声明文件

识别库的类型是书写声明文件的第一步:

  1. 全局库
  2. 模块化库、UMD库

规范:

普通类型

不要使用如下类型Number,String,Boolean或Object。
应该使用类型number,string,boolean或object。

回调类型

不要为返回值被忽略的回调函数设置一个any类型的返回值类型,使用void相对安全
不要在回调函数里使用可选参数除非你真的要这么做,应该写出回调函数的非可选参数
不要因为回调函数参数个数不同而写不同的重载,应该只使用最大参数个数写一个重载

函数重载

不要把一般的重载放在精确的重载前面,应该排序重载令精确的排在一般的之前
不要为仅在末尾参数不同时写不同的重载,应该尽可能使用可选参数
不要为仅在某个位置上的参数类型不同的情况下定义重载,应该尽可能地使用联合类型

声明文件的原理

类型:

  1. 类型别名声明(type sn = number | string;)
  2. 接口声明(interface I { x: number[]; })
  3. 类声明(class C { })
  4. 枚举声明(enum E { A, B, C })
  5. 指向某个类型的import声明

值:

  1. let,const,和var声明
  2. 包含值的namespace或module声明
  3. enum声明
  4. class声明
  5. 指向值的import声明
  6. function声明

命名空间:

类型可以存在于命名空间里。

内置组合:

class C { }声明创建了两个东西: 类型C指向类的实例结构, 值C指向类构造函数。

用户组合:

高级组合:有一些声明能够通过多个声明组合。 比如, class C { }和interface C { }可以同时存在并且都可以做为C类型的属性。

工程配置

如果一个目录下存在一个tsconfig.json文件,那么它意味着这个目录是TypeScript项目的根目录。
tsconfig.json文件中指定了用来编译这个项目的根文件和编译选项。

tsconfig.json

extends
compileOnSave
compilerOptions
    typeRoots
    types
files
include
exclude

参考

TypeScript 中文文档
TypeScript 入门教程

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions