前期准备
1.下载并安装 Node.js
2. 进入命令行全局安装 typescript
npm i -g typescript
认识TS
介绍
-
TypeScript 是一种由微软开发的开源、跨平台的编程语言。它是为大型应用的开发而设计。
-
2012 年 10 月,微软发布了首个公开版本的 TypeScript,2013 年 6 月 19 日,在经历了一个预览版之后微软正式发布了正式版 TypeScript
-
TypeScript 扩展了 JavaScript 的语法,是 JavaScript 的超集,最终会被编译为 JavaScript 代码,所以任何现有的 JavaScript 程序可以运行在 TypeScript 环境中。
-
TypeScript 是 JavaScript 的一个超集,主要提供了类型系统和对 ES6+ 的支持。
特点
TypeScript 主要有 3 大特点:
-
始于 JavaScript,归于 JavaScript
TypeScript 可以编译出纯净、 简洁的 JavaScript 代码,并且可以运行在任何浏览器上、Node.js 环境中和任何支持 ECMAScript 3及以上版本的 JavaScript 引擎中。
-
强大的类型系统
类型系统允许 JavaScript 开发者在开发 JavaScript 应用程序时使用高效的开发工具和常用操作比如静态检查和代码重构。
-
先进的 JavaScript
TypeScript 提供最新的和不断发展的 JavaScript 特性,包括那些来自 2015 年的 ECMAScript 和未来的提案中的特性,比如异步功能和 Decorators,以帮助建立健壮的组件。
TS语法
类型注解
-
类型声明
- 通过类型声明可以指定 TS 中变量、参数、形参的类型。
- 变量、参数、形参等指定类型后,一旦重新赋值,TS 编译器会自动检查值是否符合类型声明,不符合则会直接报错
- 语法:
let 变量: 类型; let 变量: 类型 = 值; function fn(参数: 类型, 参数: 类型): 返回值类型{ ... }
- 类型:
类型 例子 描述 number 1, -1, 10.00 任意数字 string ‘a’, “a” 任意字符串 boolean true、false 布尔值true或false 字面量 其本身 限制变量的值就是该字面量的值 any * 任意类型 unknown * 类型安全的any void 空值(undefined) 没有值(或undefined) never 没有值 不能是任何值 object {name:‘小明’} 任意的JS对象 array [1,2,3] 任意JS数组 tuple [1,2,3,4,5] 元组,TS新增类型,固定长度数组 enum enum{A, B} 枚举,TS中新增类型 -
声明类型示例:
-
number:
let num1 = 1 // 字面量直接赋值 let num2: number // 类型注解
-
boolean
let boolean1 = true // 字面量直接赋值 let boolean2: boolean // 类型注解
-
string
let str1 = '小明' // 字面量直接赋值 let str2: string // 类型注解
-
any
声明 any 类型的变量,可赋值任意类型的值,也可赋值给除了 never 类型外的任意类型变量。
let any1: any // 声明 any 类型的变量可赋值任意类型的值 any1 = true any1 = 1 any1 = '小明'
-
unknown
声明 unknown 类型的变量,可赋值任意类型的值,但与 any 不同,unknown 类型的变量只可赋值给 any / unknown 类型的变量。
let unknown1: unknown let unknown2: unknown unknown1 = 1 unknown1 = true any1 = unknown1 // 可行 unknown2 = unknown1 // 可行 let num1: number num1 = unknown1 // 不可行!!
-
void
let void1: void = undefined const void2 = (): void => { console.log('没有返回值') }
-
never
neve r类型是任何类型的子类型,也可以赋值给任何类型;然而,没有类型是 never 的子类型或可以赋值给 never 类型(除了 never 本身之外)。 即使 any 也不可以赋值给 never。通常用于抛出异常。
const void2 = (): never => { throw new Error('出错了'); }
-
object
let obj1: object = { };
-
array
// number 类型的数组 let array1: number[] = [1, 2, 3] let array2: Array<number> = [1, 2, 3] // string 类型的数组 let array3: string[] = ['1', '2', '3'] let array4: Array<string> = ['1', '2', '3']
-
tuple
元组是固定长度数组。
let tuple1: [number, string, boolean] tuple1 = [1, 'aa', true]
-
enum
枚举默认从 0 开始,亦可以自定义枚举值。
// 枚举默认从 0开始 enum Sex { man, woman } let sex1: Sex = Sex.man let sex2: Sex = Sex.woman console.log(sex1) // 输出 0 console.log(sex2) // 输出 1 // 自定义枚举值 enum Color { blue = 1, red = 2, orange = 5 } let color1: Color = Color.blue let color2: Color = Color.red let color3: Color = Color.orange console.log(color1) // 输出 1 console.log(color2) // 输出 2 console.log(color3) // 输出 5
-
类型断言
有些情况下,变量的类型对于我们来说是很明确,但是TS编译器却并不清楚,此时,可以通过类型断言来告诉编译器变量的类型,断言有两种形式:
- 第一种
let value1: unknown = 'i am string' // value 类型为 unknown,ts编译器不知道它的类型,故用类型断言告诉 ts编译器它是字符串 let value1Length: number = (value1 as string).length
- 第二种
let value1: unknown = 'i am string' // value 类型为 unknown,ts编译器不知道它的类型,故用类型断言告诉 ts编译器它是字符串 let value1Length: number = (<string>value1).length
-
面向对象
类(Class)
-
定义类的语法:
class 类名 { 属性名: 类型; constructor(参数: 类型){ this.属性名 = 参数; } 方法名() { .... } }
-
示例:
// 定义一个类 class Car{ // 属性 name: string price: string constructor(name: string, price: string){ this.name = name this.price = price } // 方法 run() { console.log('running') } } // 实例化一个对象 const mycar1 = new Car('宝马', '100w') console.log(mycar1.name) console.log(mycar1.price) mycar1.run()
面向对象的特点
-
封装
-
对象实质上就是属性和方法的容器,它的主要作用就是存储属性和方法,这就是所谓的封装。
-
默认情况下,对象的属性是可以任意的修改的,为了确保数据的安全性,在 TS 中可以对属性的权限进行设置:
-
只读属性(readonly):用readonly 修饰的属性只可以读不可以改!
// 定义一个类去实现接口 class Car{ // readonly 修饰,name 是一个只读属性 readonly name: string constructor(name: string){ this.name = name } } const mycar1 = new Car('宝马') console.log(mycar1.name) // 可以读取 name mycar1.name = '奔驰' // 报错,不可以修改!!! ```
-
TS中属性具有三种修饰符:
- public:默认值,可以在类、子类和对象中修改
- private :可以在类和子类中修改
- protected:仅仅可以在类中修改
-
属性存取器
-
对于一些不希望被任意修改的属性,可以将该属性用 private 修饰
-
被 private 修饰的属性无法再通过对象修改其中的属性(也就是通过
对象.属性 = value
来修改)。 -
我们可以在类中定义一组读取、设置属性的方法,这种对属性读取或设置的方法被称为属性的存取器
-
读取属性的方法叫做 getter 方法,设置属性的方法叫做 setter 方法
class Car{ // 用 private 来修饰属性 _name private _name: string constructor(name: string){ this._name = name } // 设置属性存取器,get 是读取属性的方法, set 是设置属性的方法 get name() { return this._name } set name(value: string) { this._name = value } } const mycar1 = new Car('宝马') console.log(mycar1.name) // 设置属性存取器后可以读取 private 修饰的 _name
-
-
静态属性
-
使用 static 开头的属性(方法)就是静态属性(方法),也称为类属性。
-
使用静态属性无需创建实例,可直接通过类来使用
class Car{ // 用 static 开头的属性为静态属性 static Name = '我是静态属性' // 静态方法 static add(num1: number, num2: number) : number { return num1 + num2 } } console.log(Car.Name) // 可以直接通过类来读取静态属性 Name console.log(Car.add(1, 2)) // 可以直接通过类来执行静态方法 add
-
-
-
-
继承
-
通过继承可以将其他类中的属性和方法引入到当前类中
-
通过继承可以在不修改类的情况下完成对类的扩展
-
重写
子类继承父类时,如果子类中的方法有与父类中同名的方法,子类同名方法会替换掉父类的同名方法,这就称为方法的重写。
class Car{ // 父类属性 name: string price: string constructor(name: string, price: string) { this.name = name this.price = price } run() { console.log('汽车running...') } } class baoMa extends Car{ // 子类属性 address: string constructor(name: string, price: string, address: string) { // 通过 super 能将参数传给父类的构造器 super(name, price) this.address = address } // 同名方法,子类替换父类,实现重写 run() { console.log('宝马running....') } } let myCar1 = new baoMa('宝马', '100w', '德国') myCar1.run() // 调用的是子类的 run 方法,输出宝马running....
-
+抽象类
-
抽象类是专门用来被其他类所继承的类,它只能被其他类所继承不能用来创建实例!
-
使用 abstract 开头的属性叫做抽象属性,抽象属性只能定义在抽象类中,继承抽象类时必须拥有继承的抽象属性
-
使用 abstract 开头的方法叫做抽象方法,抽象方法没有方法体只能定义在抽象类中,继承抽象类时抽象方法必须要实现
// 定义一个抽象类 abstract class Car{ // 抽象属性 name abstract name: string // 抽象方法 run abstract run(): void } // 子类继承了抽象类,必须拥有抽象类中的抽象方法和抽象属性 class baoMa extends Car{ // 必须拥有抽象类中的抽象属性 name: string constructor(name: string) { super() this.name = name } // 同名方法,子类替换父类,实现重写 run() { console.log('宝马running....') } } let myCar1 = new baoMa('宝马') console.log(myCar1.name) // 输出的是 宝马
接口(Interface)
-
接口的作用类似于抽象类,不同点在于接口中的所有方法和属性都是没有实值的,换句话说接口中的所有方法都是抽象方法。
-
接口主要负责定义一个类的结构,接口可以去限制一个对象的结构,对象只有包含接口中定义的所有属性和方法时才能匹配接口。
-
可以让一个类去实现接口,实现接口时类中要包含接口中的所有属性。
-
检查对象类型示例:
// 定义一个接口来限制对象类型 interface Car{ name: string, price: string, run(): void } // 传入的形参类型必须符合 Car 接口 function showCar(car: Car) { console.log(car) car.run() } showCar({ name: '宝马', price: '100w', run() { console.log('running') } })
-
类实现接口示例:
// 定义一个接口来限制对象类型 interface Car{ name: string, price: string, run(): void } // 定义一个类去实现接口 class MyCar implements Car{ name: string price: string constructor(name: string, price: string){ this.name = name this.price = price } run() { console.log('running') } } const mycar1 = new MyCar('宝马', '100w') console.log(mycar1.name) console.log(mycar1.price) mycar1.run()
泛型(Generic)
-
定义一个函数或类时,有些情况下无法确定其中要使用的具体类型(返回值、参数、属性的类型不能确定),此时泛型便能够发挥作用。
-
使用泛型可以动态指定类型注解。
- 示例:
// 泛型用 <T> 表示,当然中间的字母可以是其他字母,仅仅是一个标识 function test<T>(arg: T): T{ return arg; } test(10) // 泛型就是 number test('哈哈') // 泛型就是 string test(true) // 泛型就是 boolean
-
可以同时指定多个泛型,泛型间用逗号隔开。
- 示例:
// 可以同时指定多个泛型,泛型间用逗号隔开。 function test<T, J, K>(a: T, b: J, c: K): K { console.log(a) // 输出 10 console.log(b) // 输出 哈哈哈 return c // 返回 true } test(10, '哈哈', true) // 泛型 T 就是 number, J 就是string, K 就是 boolean
-
类中同样可以使用泛型:
class Car<T>{ name: T constructor(name: T){ this.name = name } } const myCar1 = new Car<string>('宝马') // 泛型 T 就是 string
-
可以对泛型的范围进行约束
interface myInter{ length: number } // 泛型 T 继承了接口 myInter 的约束,必须拥有 length function getLength<T extends myInter>(arg: T): number { return arg.length } console.log(getLength('aaaa')) // string 有 length,故可行 console.log(getLength(10)) // number 没有 length ,故不可行!!!
转载:https://blog.csdn.net/m0_46627730/article/details/116207684