TypeScript是什么?
- 以JavaScript为基础构建的语言
- 一个JavaScript的超集
- 可以在任何支持JavaScript的平台上执行
- TypeScript扩展了JavaScript并添加了类型
- TS不能被JS解析器直接执行
TypeScript开发环境搭建
- 下载Node.js
- 安装Node.js
- 使用npm全局安装TypeScript,输入:
npm i -g typescript
- 创建一个ts文件:进入ts文件所在目录,执行
tsc xxx.ts
TypeScript类型声明
- 例如
let a:number
,设置了变量类型之后,使用过程中a只能是数字。 - 如果变量的声明和赋值是同时进行的,TS可以自动对变量进行类型检测
let c = false
。 - ts的类型声明同样可以用在参数上面。
function add(a:number,b:number){console.log(a+b)
}
add(1,1)
- 变量类型
- any:如果给变量声明为any则相当于关闭了ts变量的声明检测,就和js中一样。如果声明变量时不声明类型,会自动检测为any类型(隐式any)。
- unknown:any类型的变量可以赋值给任意变量,所以会影响到这个变量,但是unknown不会,如果想要赋值需要对这个变量进行类型判断之后再进行赋值或是使用类型断言之后再赋值。
- void:通常用于函数的返回值类型的定义,表示没有返回值
- never:通常用于函数的返回值类型的定义,表示永远都不会返回结果
let s:string
let e:unknown
if(typeof e === "string" ){s = e;
}
- 可以使用
|
来连接多个类型(联合类型)
let b:number|string
b = 1
b = '1'
- 类型断言:可以用来告诉解析器变量的实际类型。
s= e as string//方式一
s=<string>e//方式二
- 返回值的类型定义
function fun():void{return
}
- 对象类型用来指定时,就是指定这个对象包含的属性以及属性的类型,在属性名后面加一个?代表是可选属性。但如果加上
[propname:string]:any
,除了已经设置了类型的属性,其他的都是可以是任意类型。另外枚举也是设置对象的类型,
let f:{name:string,age?:number}
f={name:''
}let f:{name:string,[propname:string]:any}
f={name:'',age:10
}
- 函数设置
let g:(a:number,b:number)=>number
g = function(n1:number,n2:number):number{return 10
}
- 数组类型定义,还有一种方式是元组,则是固定长度的数组
let h:number[]
h = [1,2,3]
let d:Array<number>
d = [4,5,6]
let i:[string,string]
i = ['1','2']
- |表示或,&表示与,&的使用情景为
let j :{name:string} & {age:number}
- 类型的别名
type myType = 1 | 2 | 3 | 4
let m:myType = 1
m = 1
ts文件配置
- 自动监视
tsc app.ts -w
- 监视整个文件夹的ts并进行编译,需要新建一个配置文件,
tsconfig.json
- include:指定哪些文件需要被监听执行
"./src/**"
,**
表示任意目录,*
表示任意文件 - exclude:指定哪些文件不包含,写法与include一致
- compilerOptions:编译器的选项,他有很多子选项
- target,用来ts被编译的es版本
- module,指定要使用的模块化的规范
- lib,用来指定项目中要使用的库
- outDir,用来指定文件编译后所在的目录
- outFile,将代码合成为一个文件
- allowJs,是否对js文件进行编译,默认是false
- checkJs,是否检查js代码
- removeComments,是否移除注释,默认false
- noEmit,不生成编译后的文件,默认false
- noEmitOnError,存在错误时不生成编译后的文件
- alwaysStrict,设置编译后的文件是否使用严格模式,默认为false
- noImplicitAny,不允许隐式的any类型
- noImplicitThis,不允许不明确类型的this
- strictNullChecks,严格的检查空值
- strict,严格检查的总开关,设置为true时所有严格检查都打开
类的介绍
要想面向对象,操作对象,首先便要拥有对象,那么下一个问题就是如何创建对象。要创建对象,必须要先定义类,所谓的类可以理解为对象的模型,程序中可以根据类创建指定类型的对象,举例来说:可以通过Person类来创建人的对象,通过Dog类创建狗的对象,通过Car类来创建汽车的对象,不同的类可以用来创建不同的对象。
定义类
class 类名 {属性名:类型;constructor(参数:类型){this.属性名 = 参数}方法名(){....}
}
class Person{// 定义实例属性,需要创建对象实例进行访问name:string = '孙悟空'// 在属性前使用static关键字可以定义属性(静态属性,即不用创建对象实例能访问)static age:number = 12// 定义只读属性readonly sex:string = '男'// 定义只读静态属性static readonly love:string = '篮球'// 定义方法sayHello(){console.log('Hello!!!')}}
const per = new Person()console.log(per.name)
console.log(Person.age)
per.sayHello()
构造函数
在构造函数中通过传参并用this对类的属性进行赋值,才可以获得不同的实例对象。
class Dog{name:stringage:number// 构造函数会在对象创建时调用时constructor(name:string,age:number) {// 在实例方法中的this代表的是当前的实例,所以可以通过this给当前实例对象添加属性this.name = namethis.age = age}
}const dog = new Dog('旺财',1)
console.log(dog)
继承
// 使Dog继承Animal的类,Animal被称为父类,Dog被称为子类,继承后子类会继承所有的父类
// 如果需要在子类中添加一些父类中没有的属性或方法,直接加就行
// 如果在子类中添加了和父类中相同的方法,子类的方法会覆盖父类的方法,这个称为方法的重写
// 父类还有一个名字,那就是超类,在类的方法中,super就是当前类的父类
abstract class Animal{name:stringage:number// 构造函数会在对象创建时调用时constructor(name:string,age:number) {// 在实例方法中的this代表的是当前的实例,所以可以通过this给当前实例对象添加属性this.name = namethis.age = age}sayHello(){console.log('叫')}
}
class Dog extends Animal{run(){console.log(this.name+'在跑')}sayHello() {console.log('汪汪汪')}
}class Cat extends Animal{sayHello() {super.sayHello();}age:numberconstructor(name:string,age:number) {// 如果在子类中写了构造函数,在子类的构造函数中必须对父类的构造函数进行调用super(name,age);this.age = age}
}const dog = new Dog('旺财',1)
console.log(dog)
dog.sayHello()
dog.run()
const cat = new Cat('喵喵',2)
console.log(cat)
cat.sayHello()
抽象类
以abstract开头的类是抽象类,抽象类与其他类区别不大,只是不能用来创建对象,抽象类就是专门用来被继承的类,抽象类中可以添加抽象方法,抽象方法用abstract开头没有方法体,抽象方法只能定义在抽象类中子类必须对抽象方法进行重写。
abstract class Animal{name:stringage:number// 构造函数会在对象创建时调用时constructor(name:string,age:number) {// 在实例方法中的this代表的是当前的实例,所以可以通过this给当前实例对象添加属性this.name = namethis.age = age}// 抽象方法用abstract开头没有方法体,抽象方法只能定义在抽象类中子类必须对抽象方法进行重写abstract sayHello():void
}
接口
接口就是用来定义一个类的结构,接口是可以重复声明的,接口中的所有方法都是抽象方法,定义类是,可以使类去实现一个接口,实现接口就是满足接口的要求,即是对类的限制。
// 接口用来定义一个类结构,用来顶一个类中应该包含哪些属性和方法,同时接口也可以当成类型声明去使用
// 接口是可以重复声明的,
interface myInterface{name:stringage:number
}
interface myInterface{sex:string
}
const obj:myInterface = {name:'sss',age:11,sex:'男'
}//接口可以在定义类的适合去限制类的结构,接口中的属性都不能有实际的值,接口只定义对象的结构,而不考虑实际值
interface myInter{name:stringsayHello():void
}class Myclass implements myInter{name:stringconstructor(name:string) {this.name = nameconsole.log(name)}sayHello() {console.log(this.name+'在喵喵喵')}
}class Dog2 extends Myclass{}
const dog3 = new Dog2('旺财')
dog3.sayHello()
属性的封装
普通情况下类的属性可以被任意修改,会导致对象中的数据变得非常不安全。
TS可以再属性前添加属性的修饰符
- public 修饰的属性可以再任意位置访问(修改) 是默认值
- private 私有属性,私有属性只能在类的内部访问,可以通过在类中添加方法,使这个私有属性被外部访问,TS中可以设置getter方法的方式
- protected 受包含的属性,只能在自己和自己子类中访问
注意:可以直接将属性定义在构造函数中
class Friend{private _name:stringprivate _age:numberprotected _sex:stringconstructor(name:string,age:number) {this._name = '孙悟空'this._age = 12}// 获取getName(){return this._name}// 修改setAge(value:number){if(value >= 0){this._age = value}}get name(){return this._name}set name(value:string){this._name = value}
}
const fri = new Friend('竹巴吉',11)
console.log(fri.getName())
fri.setAge(-11)
fri.name = '旺财'
console.log(fri)
class C{constructor(public name:string,public age:number) {}}
const c = new C('SUNWU',1)
泛型
在定义函数或类时,如果遇到不明确类型的属性就可以使用泛型,可以直接调用具有泛型的函数。
function fn<T>(a:T):T{return a
}
fn(10)//不指定泛型,TS可以自动对类进行推断
fn<string>('hello')//指定泛型
function fn2<T,K>(a:T,b:K):T{return a
}
fn2<number,string>(1,"1")
function fn3<T extends myInter>(a:T):string{return a.name
}
class MyClass<T>{name:Tconstructor(name:T) {this.name = name}
}
const mc = new MyClass<string>('孙悟空')