# TypeScript 基本语法
# 名词解释
# 类型注解
作用:相当于强类型语言中的类型声明
语法:(变量/函数): type
,这种语法也叫做类型后置语法
let str: string = 'abc'
# 联合类型
联合类型(Union Types)表示取值可以为多种类型中的一种。
let count: number | string = 10
# 枚举
一组有名字的常量集合,可以类比手机里的通讯录。
# 泛型
泛型可以理解为一个类型层面的函数,泛型变量可以类比函数参数,是代表类型的参数,即类型参数化。不预先确定的数据类型,具体的类型在使用的时候才能确定。
# 语法
# ES6 的数据类型
- Boolean
- Number
- String
- undefined
- null
- Symbol
- BigInt
- Object
# TS 的数据类型
- boolean
- number
- bigint (target 低于 ES2020 时不可用)
- string
- undefined
- null
- symbol
- array
- function
- object
- void
- any
- unknown
- never
- 元组
- 枚举
- 高级类型
# 常规类型注解
/*******原始值*******/
const isDone: boolean = false
// 可以使用 number 类型表示 JavaScript 已经支持或者即将支持的十进制整数、浮点数,以及二进制数、八进制数、十六进制数
const amount: number = 6
const integer: number = Number(2)
const binary: number = 0b1010 // 二进制整数
const octal: number = 0o27 // 八进制整数
const hex: number = 0xff // 十六进制整数
const big: bigint = 100n // 大整数,需要 target es2020 及以上
// 所有 JavaScript 支持的定义字符串的方法,我们都可以直接在 TypeScript 中使用
const letter: string = String('S') // 显示类型转换
const address: string = 'beijing' // 字符串字面量
const greeting: string = `Hello World` // 模板字符串
const sym: symbol = Symbol(1)
/*******数组*******/
const list: string[] = ['x', 'y', 'z']
const numList: Array<number> = [1, 2, 3] // 使用 Array 泛型定义数组类型
/*******元组*******/
const name: [string, string] = ['Sean', 'Sun']
/*******枚举*******/
enum Color {
Red,
Green,
Blue,
}
const c: Color = Color.Green
// any 任意类型
let anyTypes: any = 4
anyTypes = 'any'
anyTypes = false
// 空值
function doSomething(): void {
return undefined
}
// 类型断言
let someValue: any = 'this is a string'
let strLength: number = (someValue as string).length
# 注意:
- 虽然
number
和bigint
都表示数字,但是这两个类型不兼容。 - TypeScript 还包含 Number、String、Boolean、Symbol 等类型(注意这些都是首字母大写的),千万别将它们和小写格式对应的 number、string、boolean、symbol 进行等价。基本上我们不会使用到 Number、String、Boolean、Symbol 类型,因为它们并没有什么特殊的用途。这就像我们一般不用 JavaScript 的 Number、String、Boolean 等构造函数 new 一个相应的实例一样。
- TS 报错的状态码 2322 是比较常见的,这是静态类型检查的错误码,在注解的类型和赋值的类型不同时会抛出这个错误。
- 除了 never 类型,可以把 any 类型的值赋值给任意类型的变量。
# Interface
# TypeScript 中的 Interface 可以看做是一个集合,这个集合是对对象、类等内部结构的约定
// 定义接口 Coords
// 该接口包含 number 类型的 x,string 类型的 y
// 其中 y 是可选类型,即是否包含该属性无所谓
interface Coords {
x: number
y?: string
}
// 定义函数 where
// 该函数接受一个 Coords 类型的参数 l
function where(l: Coords) {
// doSomething
}
const a = { x: 100 }
const b = { x: 100, z: 'abc' }
// a 拥有 number 类型的 x,可以传递给 where
where(a)
// b 拥有 number 类型的 x 和 string 类型的 y1,可以传递给 where
where(b)
// 下面这种调用方式将会报错,虽然它和 where(b) 看起来是一致的
// 区别在于这里传递的是一个对象字面量
// 对象字面量会被特殊对待并经过额外的属性检查(是不是新鲜?)
// 如果对象字面量中存在目标类型中未声明的属性,则抛出错误
where({ x: 100, z: 'abc' })
// 最好的解决方式是为接口添加索引签名
// 添加如下所示的索引签名后,对象字面量可以有任意数量的属性
// 只要属性不是 x 和 y,其他属性可以是 any 类型
interface Coords {
x: number
y?: string
[propName: string]: any
}
# 接口还常用于约束函数的行为
// CheckType 包含一个调用签名
// 该调用签名声明了 getType 函数需要接收一个 any 类型的参数,并最终返回一个 string 类型的结果
interface CheckType {
(data: any): string
}
const getType: CheckType = (data: any): string => {
return Object.prototype.toString.call(data)
}
getType('abc')
// => '[object String]'
# Interface 也可以用于约束类的行为
interface ClockConstructor {
new (hour: number, minute: number): ClockInterface
}
interface ClockInterface {
tick()
}
function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {
return new ctor(hour, minute)
}
class DigitalClock implements ClockInterface {
constructor(h: number, m: number) {}
tick() {
console.log('beep beep')
}
}
class AnalogClock implements ClockInterface {
constructor(h: number, m: number) {}
tick() {
console.log('tick tock')
}
}
let digital = createClock(DigitalClock, 12, 17)
let analog = createClock(AnalogClock, 7, 32)
# 除了 ES6 增加的 Class 用法,TypeScript 还增加了 C++、Java 中常见的 public / protected / private 限定符,限定变量或函数的使用范围。
TypeScript 使用的是结构性类型系统,只要两种类型的成员类型相同,则认为这两种类型是兼容和一致的,但比较包含 private 和 protected 成员的类型时,只有他们是来自同一处的统一类型成员时才会被认为是兼容的
class Animal {
private name: string
constructor(theName: string) {
this.name = theName
}
}
class Rhino extends Animal {
constructor() {
super('Rhino')
}
}
class Employee {
private name: string
constructor(theName: string) {
this.name = theName
}
}
let animal = new Animal('Goat')
let rhino = new Rhino()
let employee = new Employee('Bob')
animal = rhino
// Error: Animal and Employee are not compatible
animal = employee
# 函数类型
函数类型可以先定义再使用,具体实现时就可以不用注明参数和返回值类型了,而且参数名称也不用必须跟定义时相同。
let compute: (x: number, y: number) => number
compute = (a, b) => a + b
# 类型谓词
在 TypeScript 中,函数支持一种特殊的类型描述。就是在添加返回值类型的地方,通过 “参数名 + is + 类型”的格式明确了参数的类型,进而引起类型缩小,所以类型谓词函数的一个重要的应用场景是实现自定义类型守卫。
function isString(s: any): s is string {
return typeof s === 'string'
}
function isNumber(n: any) {
return typeof n === 'number'
}
function operator(x: unknown) {
if (isString(x)) {
x.toUpperCase() // x 的类型缩小为 string,可以使用 toUpperCase 方法
}
if (isNumber(x)) {
console.log(x) // x 的类型还是 unknown
x.toFixed() // 报错,
}
}