TypeScript 学习笔记
一、基本数据类型
基本数据类型与 JavaScript 一致,包含了 number, string, boolean,增加了一个任意值类型 any、unknown、never、void
- any:任意类型的变量
- unknown: 表示未知类型
unknown与any类似 但使用前必须进行断言或守卫- never:永不存在的值的类型
- void: 无任何类型,没有类型
用于函数时,never表示函数用于执行不到返回值那一步(抛出异常或死循环)的返回值类型,
即永不存在的值的类型。 而void则表示没有返回值,不返回或返回undefined
使用原则上
- 能不用any,就不用any声明时如果不确定具体的类型,则可以使用unknown代替,在使用时用类型断言或类型守卫进行类型收缩
- never 常用于构造条件类型来组合出更灵活的类型定义
- void 常用于表示函数没有返回值
定义变量
const num: number = 1
const str: string = 'a'
定义数组
const num: number[] = [1, 2, 3, 4, 5]
const str: string[] = ['a', 'b', 'c', 'd', 'e']
联合类型
let other: number | string = 1
other = 'a'
二、函数
函数的定义大致与 JavaScript 一致,仅仅有类型的区分
普通函数
function fun(){
console.log('fun')
}
有入参的函数
function fun(num: number, str: string) {
console.log(num, str)
}
有返回值的函数
function fun(): number {
return 1
}
函数表达式
简写方式
fun 的类型不指定类型,通过 = 赋值决定类型
const fun = (n1: number, n2: number):number => n1+n2
console.log(fun(1, 2))
手动指定 fun 的类型
需要注意 TypeScript 中的 => 与 JavaScript 中的 => 意义不同
TypeScript 中:(入参名称: 入参类型) => 返回类型
JavaScript 中: (入参名称) => 函数体
// 1 简写前变量值为一个函数体
const fun: (n1: number, n2: number) => number = function(n1: number, n2: number) {return n1+ n2}
// 2 简写一次后 function 更改为代码段的表达式
const fun: (n1: number, n2: number) => number = (n1: number, n2: number): number => {return n1 + n2}
// 3 简写二次后去掉代码段改为一行执行
const fun: (n1: number, n2: number) => number = (n1: number, n2: number): number => n1 + n2
入参解构函数
// 解构对象
function fun({num, str}: {num: number, str: string}) {
console.log(num, str)
}
fun({num: 1, str: 'a'})
// 解构数组
function fun2([num, str]: [num: number, str: string]) {
console.log(num, str)
}
fun2([1, 'a'])
三、接口(一)
接口关键字是 interface 。接口的主要作用是对对象的结构进行类型检查,当结构或者类型不匹配时将会报错
普通接口定义
错误示例
interface Person {
name: string
age: number
}
const li_lei: Person = {
name: '李雷',
age: 18,
sex: '男' // Person 接口中没有定义这个属性,则不得擅自增加属性
}
const han_meimei: Person = { // 当对象中缺失 Person 接口中规定的必传属性, 则会报错
name: '韩梅梅'
}
正确示例
const zhang_san: Person = {
name: '张三',
age: 10
}
可选属性接口定义
interface Person {
name: string
age: number
sex?: string // 通过 ? 将属性标记为可选属性
}
const li_lei: Person = {
name: '李雷',
age: 18,
sex: '男'
}
const han_meimei: Person = {
name: '韩梅梅',
age: 18
// sex: '女' // 可以选择不要这个属性
}
只读属性接口定义
定义只读的关键字 readonly
interface Person {
readonly id: number
name: string
}
const li_lei: Person = {
id: 1,
name: '李雷'
}
li_lei.id = 3 // [编译报错] 设置了 readonly 的属性被初始化后无法再次修改
任意属性接口定义
interface Person {
name: string
age: number
sex?: string
[propName: string]: unknown
}
const li_lei: Person = {
name: '李雷',
age: 18,
sex: '男', // Person 接口中没有定义这个属性,则不得擅自增加属性
like: '开车',
birthday: '2000-01-01'
}
const han_meimei: Person = { // 当对象中缺失 Person 接口中规定的必传属性, 则会报错
name: '韩梅梅',
age: 18,
like: '购物',
birthday: '2000-01-01'
}
接口函数字段定义
interface Person {
readonly id: number
name: string,
eat(food: string): void // 第一种函数定义方式
drink: (food: string) => void // 第二种函数定义方式 [TypeScript 中:(入参名称: 入参类型) => 返回类型]
}
四、类
类的关键字是 class 作为对象的模板被引入,class 的本质是一个 function
类的定义
类的定义分为匿名类和命名类,在定义类时需要注意,类不能同名
// 匿名类
let clazz = class {}
// 命名类
class Clazz{}
构造器与属性定义
constructor: 构造器,类在被 new 的时候将会被调用。不写时默认是无参构造。一个 class 只能有一个 constructor
注意,当 constructor 被定义为 private 属性后,class 将无法被 new
public: 共有属性,属性被 new 以后可以通过 .(点) 的方式进行访问
private: 私有属性,属性仅仅在 class 内部可以进行访问,外部无法访问
let clazz = class {
public msg: string
private num: number
// 构造函数
constructor(msg: string) {
this.msg= msg
}
}
class Clazz{
public msg: string
private num: number
// 构造函数
constructor(msg: string) {
this.msg = msg
}
}
console.log(new clazz('abc').msg)
console.log(new Clazz('abc').msg)
// console.log(new clazz('abc').num) // 无法访问
// console.log(new Clazz('abc').num) // 无法访问
get & set
class Person {
private age: number
constructor(age: number) {
this.age = age
}
getAge(){
console.log('getAge')
return this.age
}
setAge(num: number) {
this.age = num
console.log('setAge: ' + num)
}
}
const person = new Person(18)
console.log(person.getAge())
person.setAge(19)
console.log(person.getAge())
继承
-
继承使用关键字 extends
-
子类中访问父类使用 super 关键字
-
实例化子类时会优先实例父类,super() 必须在 constructor 的第一行位置
class Clazz{
public msg: string
constructor(msg: string) {
this.msg = msg
}
}
class Student extends Clazz {
constructor() {
super('父')
console.log(super.msg) // undefined
}
say(): void {
console.log(super.msg) // undefined
console.log(this.msg) // 父
}
}
new Student().say()
五、接口(二)
接口定义
interface Person {
readonly id: number
name: string,
eat(food: string): void
drink: (food: string) => void
}
实现一
const li_lei: Person = {
id: 1,
name: '李雷',
eat: (food: string) => console.log(li_lei.name + ' 吃 ' + food),
drink: (food: string) => console.log(li_lei.name + ' 喝 ' + food)
}
li_lei.eat('包子')
li_lei.eat('西瓜汁')
实现二
class han_meimei implements Person{
id = 2
name = '韩梅梅'
eat = (food: string) => console.log(this.name + ' 吃 ' + food)
drink(food: string) {
console.log(this.name + ' 喝 ' + food)
}
}
const hmm: han_meimei = new han_meimei()
hmm.eat('包子')
hmm.drink('西瓜汁')
六、断言 (as)
断言的作用在于当函数中出现了多种类型时,但是又必须使用某一种类型。如果不使用断言,在编译过程中会无法编译
断言更像是告诉编译器:你不需要管我,我自己知道我在干什么
但是断言虽然编译通过了,但是容易在运行中出现异常。所以在使用过程中需要更加的谨慎
注意,断言不是类型转换。
示例
断言先就这样吧,稍微理解一下,先学点别的
interface ApiError extends Error{
code: number
}
interface HttpError extends Error{
statusCode: number
}
// function isApiError(error: Error) {
// return typeof error.code !== 'undefined'; // 没有使用断言,编译器无法编译 code 编译会报错
// }
function isApiError(error: Error) {
return typeof (error as ApiError).code !== 'undefined'; // 将 error 断言为 ApiError,才可以访问到 code 属性
}
function isHttpError(error: Error) {
return typeof (error as HttpError).statusCode !== 'undefined';
}
const apiError: ApiError = {
code: 1,
name: 'apiError',
message: ''
}
const httpError: HttpError = {
statusCode: 200,
name: 'httpError',
message: ''
}
console.log(isApiError(apiError)) // true
console.log(isHttpError(apiError)) // false
console.log(isApiError(httpError)) // false
console.log(isHttpError(httpError)) // true
七、元组
元祖可以理解为更高一级的数组,元组的数据只能是规定的联合类型
示例
const arr: [string, number] = [] // 元类型 [string, number]
arr.push('a')
arr.push(1)
arr.push('b')
arr.push(2)
arr.push(true) // boolean 不在元类型中,将会报错
八、枚举
枚举要求值必须是唯一的
枚举的定义
enum Week {
Mon, Tue, Wed, Thu, Fri, Sat, Sum
}
// 枚举默认从 0 开始例如
console.log(Week.Mon === 0) // true
console.log(Week[0] === 'Mon') // true
手动指定枚举的值
enum Week {
Mon = '一',
Tue = '二',
Wed = '三',
Thu = '四',
Fri = '五',
Sat = '六',
Sum = '天'
}
console.log(Week.Sum) // 天
网友评论