TypeScript 基础知识
TypeScript(简称 TS)是微软公司开发的一种基于 JavaScript (简称 JS)语言的编程语言。
TypeScript 可以看成是 JavaScript 的超集(superset),即它继承了后者的全部语法,所有 JavaScript 脚本都可以当作 TypeScript 脚本(但是可能会报错),此外它再增加了一些自己的语法。
TypeScript 对 JavaScript 添加的最主要部分,就是一个独立的类型系统。
基本类型
TypeScript 继承了 JavaScript 的类型设计
原始类型
boolean
boolean 类型只包含 true 和 false
const x: boolean = true
const y: boolean = falsestring
const name: string = 'Aximy'
const hello: string = `hello ${name}`number
number 类型包含所有整数和浮点数。
const x: number = 111
const y: number = 1.23
const z: number = 0xffffbigint
bigint 类型包含所有大整数,与 number 类型不兼容。
const x: bigint = 1000n;
const y: bigint = 0xffffn;TIP
注意,bigint 类型是 ES2020 标准引入的。如果使用这个类型,TypeScript 编译的目标 JavaScript 版本不能低于 ES2020(即编译参数target不低于es2020)。
symbol
symbol 类型代表独一无二的值,使用构造函数创建。
const x: symbol = Symbol('Aximy')object
object 类型包含了对象、数组和函数
const obj: object = { foo: 123 }
const arr: object = [1, 2, 3]
const func: object = (n: number) => n + 1undefined 和 null
这两种类型是独立的类型,各自只有一个值。
const x: undefined = undefined; // 未定义
const y: null = null; // 空在关闭编译设置 noImplicitAny 和 strictNullChecks 时,它们的类型会被推断为 any
特殊类型
any
any 类型表示没有限制,可以赋予任意类型的值。
let x: any = 0
x = 'hello'
x = true适用场景:需要关闭变量的类型检查时
WARNING
不宜使用 any 的主要原因之一:污染其它变量,运行时报错
let x: any = 'hello'
let y: number
y = x // 编译不报错
y * 123 // 编译不报错
y.toFixed() // 编译不报错unknown
为了解决 any 污染问题,TypeScript 3.0 引入了 unknown 类型。
可以看作严格版的 any 类型,相似之处是可以分配任意类型,不同之处在于:unknown 类型不能直接使用
let v: unknown = 123;
let v1: boolean = v // 报错
let v2: number = v // 报错需要“类型缩小”后使用:
let v: unknown = 123
if (typeof v === 'boolean') {
let v1: boolean = v // 正确
} else if (typeof v === 'number') {
let v2: number = v // 正确
}never
never 类型表示不存在的值的类型,常用于一个从来不会有返回值的函数,或者一个总是会抛出错误的函数。
// 不会有返回值
function infiniteLoop(): never {
while (true) {}
}
// 总是会抛出错误的函数
function error(message: string): never {
throw new Error(message)
}数组
数组有 类型[] 和 泛型 两种声明方式:
/* 示例:声明 number 类型数组 */
// 方式一:
const arr: number[] = [1, 2, 3]
// 方式二:
const arr: Array<number> = [1, 2, 3]元组 Tuple
元组(Tuple)是 TypeScript 特有的数据类型,用来表示“成员类型可以自由设置的数组”
const user: [string, number] = ['Aximy', 1]
// 可选成员,可选成员必须在必选成员之后
const a: [number, number?] = [1]
// 不定数量的成员
const b: [number, ...string[]] = [0, '1', '1']
// 不确定元组成员的类型和数量
type Tuple = [...any[]]枚举 Enum
TypeScript 中引入了 enum 类型,是对 JavaScript 标准数据类型的补充
enum Color {
Red,
Green,
Blue,
}
const green: Color = Color.Green- 都没有初始值时,默认从
0开始递增 - 如果只设定第一个成员的值,后面成员的值就会从该值递增
- 成员的值可以是任意数值,但不能是
bigint
type 类型别名
type 关键字用来定义类型别名,主要用来定义一些复杂类型,还可以增加代码的可读性。
type Name = string
const name: Name = 'Aximy'字面量类型
字面量类型是以单个值作为类型。
// 字符串字面量类型
type Name = 'Aximy' | 'Xmy' | 'Yang'
// 数字字面量类型
type Age = 18 | 19 | 20
// 布尔字面量类型
type isFlag = true联合类型
联合类型由多个类型组成,使用 | 符号连接,表示值为其中的一种
let x: string | number
x = 123
x = 'a'WARNING
读取变量时,除非访问公有的成员。先区分类型再处理,否则编译报错
function getLength(value: string | number): number {
// Error: 类型 “string | number” 上不存在属性 “length”(类型 “number”上 不存在属性 “length”)
return value.length
}交叉类型
交叉类型由多个类型组成,使用 & 符号连接,表示必须同时符合这些类型
let obj: { foo: string } & { bar: string }
obj = {
foo: 'hello',
bar: 'world'
}函数
对函数进行类型约束时,需要指定函数的参数类型和返回类型。
// 函数声明
function add(x: number, y: number): number {
return x + y
}
// 函数表达式
const add: (x: number, y: number) => number = function (x, y) {
return x + y
}
// 箭头函数
const add = (x: number, y: number): number => x + y可选参数
使用 ? 表示可选参数,注意:可选参数必须在必选参数后边!
const add = (x: number, y?: number): void => console.log(x + y)参数默认值
ES6 允许参数设置默认值,在 TS 中有默认值的参数就是可选的,但是参数位置不受限制。
function add(x: number = 10, y: number): number {
return x + y
}
add(20, 20) // 40
/* 必须显示传递一个 undefined 进行占位 */
add(undefined, 10) // 20rest 剩余参数
ES6 使用 ...变量名 的方式获取函数的剩余参数
getTotal(1, 2, 3, 4)
function getTotal(a: number, ...rest: number[]) {
console.log(a) // 1
console.log(rest) // [2, 3, 4]
}对象类型 — 接口
使用接口(interface)定义对象的类型,接口对类型做出了限制,并不会编译到 JS 中
TIP
对象的属性必须与接口中规定的一致,否则编译出错
interface User {
name: string
age: number
}
const user: User = {
name: 'Aximy',
age: 0
}可选属性
使用 ? 符号标记可选属性。意味着该属性可以不存在。
interface User {
name: string
age?: number
}
const user: User = {
name: 'Aximy'
}只读属性
使用 readonly 关键字,表示属性为只读属性,不能更改。
interface User {
readonly name: string
age?: number
}如果对象属性只读的话,不能替换掉整个对象,修改对象的属性是可以的。
任意属性
使用 []:类型 方式允许接口中有任意的属性
interface User {
name: string
[propName: string]: any
}
const user: User = {
name: 'Aximy',
age: 0
}WARNING
如果定义了任意属性,确定属性以及可选属性的类型必须是任意类型的子集
interface User {
name: string
[propName: string]: string
}
const user: User = {
name: 'Aximy',
age: 0 // Error: 属性 "age"与索引签名不兼容,不能将 "number" 分配给类型 "string"
}使用联合类型即可解决 👇
interface User {
name: string
[propName: string]: string | number
}