安装TypeScript
TypeScript安装方式
npm install -g typescript
第一个TypeScript程序
一、手动编译typescript
tsc 文件名
二、自动编译typescript
1). 生成配置文件 tsconfig.json
tsc --init
2). 修改tsconfig.json配置
"outdir": "./js"
"strict": "false"
3). 启动监听服务
终端 --> 运行任务 --> 监视tsconfig.json
三、类型注解
类型注解:一种轻量级的为函数或变量添加约束
function showAge(num:number){
return '我今年'+num
}
四、接口
接口是对象的状态和行为的抽象
(()=>{
// 定义一个接口
interface IPerson{
firstName:string
lastName:string
}
function showFullName(person:IPerson){
return person.firstName+person.lastName
}
let person ={
firstName:'上官',
lastName:'婉儿'
}
console.log(showFullName(person));
})()
五、类
// ts中书写js中的类,演示效果
(function(){
//定义一个接口
interface IPerson{
firstName:string
lastName:string
}
// 定义一个类型
class Person{
firstName:string
lastName:string
fullName:string
constructor(firstName:string,lastName:string){
this.firstName=firstName
this.lastName=lastName
this.fullName = this.firstName+'-'+this.lastName
}
}
// 定义一个函数
function showFullName(person:IPerson){
return person.firstName+'_'+person.lastName
}
// 实例化一个对象
const person =new Person('诸葛','孔明')
console.log(showFullName(person));
})()
TypeScript常用语法
一、基础类型
1.布尔值
最基本的数据类型,类型为boolean,结果只有true和false
let flag:boolean = false
2.数字型
TypeScript中的数字和JavaScript中的数字都是浮点数,类型为number,支持二进制、八进制、十进制、十六进制
let binaryLiteral: number = 0b1010; // 二进制
let octalLiteral: number = 0o744; // 八进制
let decLiteral: number = 8; //十进制
let hexLiteral: number = 0xf00d; //十六进制
3.字符串型
类型为string,用 ’ ’ 或者 " " 表示
let str1:string='碧玉妆成一树高'
let str2:string='万条垂下绿丝绦'
let str3:string='不知细叶谁裁出'
let str4:string='二月春风似剪刀'
console.log(`${str1},${str2},${str3},${str4}`);
字符串和数字拼接
// 字符串和数字拼接
let num:number = 2020
console.log(str5 + num);
ts中变量一开始定义什么类型就以后修改时只能改为这种类型
4.undefined和null
let udf:undefined = undefined
let nul:null = null
undefined和null都可以作为其他类型的子类型,前提是必须关闭tsconfig.json的严格模式
let num1:number = null
let num2:number = undefined
5.数组
①定义数组方式1:
语法格式:let 变量名:数据类型 = [value1,value2,value3]
let arr1:number[] = [1,2,3,4,5,6]
②定义数组方式二:泛型写法
语法格式:let 变量名:Array<数据类型> = [value1,value2,value3]
let arr2:Array<number> = [7,8,9,10,11]
注:数组类型定义后,里面的数据类型必须和定义时保持一致,否则就会报错,编译也不会通过。
6.元祖
数组定义时,它的类型合格书就已经限定了。
语法格式:let 变量名:[number,string,boolean] = [value1,value2,value3]
let arr3:[number,string,boolean] = [2.12,'张三',false]
注:数据的类型和个数要和定义时保持一致。
7.枚举
它是对js基本数据类型的补充,枚举中的每个值称为元素,每个元素有自己的编号,编号默认从0开始递增
语法格式:
enum 变量名{ 元素1,元素2,元素3}
示例:
enum Fruits{
pear,
apple,
orange
}
console.log(Fruits[2]); // orange
console.log(Fruits.pear); // 1
当然我们也可以手动去设置编号
enum Fruits{
pear = 1,
apple,
orange
}
console.log(Fruits.pear) // 1
console.log(Fruits.orange) // 3
8.any
当一个数组中存储多个数据,但是数据的类型和个数都不确定,我们可以使用any类型来定义数组
语法格式:let 数组名:any[ ] = [value1,value2,value3]
let arr:any[] = [99,'青春不常在,抓紧谈恋爱',true]
9.void
在函数声明时,小括号后面使用:void,代表的该函数没有任何返回值
语法格式:
function 函数名():void{
console.log('')
}
示例:
function showInfo():void{
console.log('你好啊,玛卡巴卡');
}
10.object
定义一个函数,参数和返回值必须是object类型(必须要有返回值)
语法格式:
function 函数名(变量名:object):object{
console.log(obj)
return{对象}
}
示例:
function showObj(obj:object):object{
console.log(obj);
return{
name:'张三',
age:18
}
}
11.联合类型
表示取值可以为多种类型中的一种
语法格式:
function 函数名(变量名:数据类型1|数据类型2){
return 变量名.方法()
}
示例:
function getStr(str:number|string){
return str.toString()
}
12.类型断言
告诉编译器,我知道我自己在干什么,也知道自己是什么数据类型
语法格式:
①:<类型>变量名
②:值 as 类型
示例:
function getStr1(str1:string|number){
if((<string>str1).length){
return (<string>str1).length
}else{
return str1.toString().length
}
}
function getStr1(str1:string|number){
if((str1 as string).length){
return (str1 as string).length
}else{
return str1.toString().length
}
}
(13)类型推断
当没有明确指定类型时推测出一个类型
let number = 100 // number
二、接口
1.接口是对象的状态和行为的抽象
接口类型的对象:多了或者少了不允许 只读属性readonly 可选属性:?
语法格式:
定义接口
interface 接口名{
变量名1:变量数据类型
变量名2:变量数据类型
...
}
使用接口
const student:IStudent={
变量名1:变量值1
变量名2:变量值2
...
}
示例
定义接口
interface IStudent{
id:number
readonly name:string // 代表此属性为只读,不能修改
hobby?:string // 代表此属性是可选属性
age:number
}
使用接口
const student:IStudent = {
id:1,
name:'张三',
hobby:'打篮球',
age:18
}
2.函数类型
给参数列表的每一项规定一个名字和类型
语法格式:
定义接口
interface 接口名{
(变量名1:变量类型,变量名2:变量类型):返回值的类型
}
声明函数
const 函数名:接口名 = function 变量名1:变量类型,变量名2:变量类型):返回值的类型{
return 表达式
}
示例:
定义接口
interface IFindFunc{
(source:string,subString:string):boolean
}
函数中使用
const search:IFindFunc=function(source:string,subString:string):boolean{
return source.search(subString) > -1 // 查找source中是否存在subString元素,返回布尔值
}
3.类类型
定义一个类,可以实现(implements)接口定义的属性和方法
// 定义一个接口
interface 接口名{
属性或方法
}
// 定义一个类
class 类名implements 接口名{
属性或方法
}
// 实例化一个对象
示例:
//定义一个接口
interface ISing{
sing()
}
interface IDance{
dance()
}
// 定义一个类
class Person1 implements ISing{
sing() {
console.log('我唱歌贼好听');
}
}
// 实例化一个对象
const person1 = new Person1()
person1.sing()
当然,一个类可是实现多个接口
// 定义接口
interface ISing{
sing()
}
interface IDance{
dance()
}
// 一个类可以实现多个接口
class Person2 implements ISing,IDance{
sing() {
console.log('我唱歌很好听');
}
dance(){
console.log('我跳舞也好看');
}
}
一个接口也可以继承多个接口
interface ISingAndIDance extends ISing,IDance{}
class Person3 implements ISingAndIDance{
sing() {
console.log('我唱歌真的很好听');
}
dance(){
console.log('我跳舞也真的很好看');
}
}
注意:接口与接口之间叫继承(extends),接口与类之间叫实现(implements)
三、类
1.基本示例
类:可以理解为是个模板,通过模板可以实例化对象
// 定义一个类
class Student{
name:string
age:number
grade:string
// 定义构造函数:为了将来实例化对象时直接对属性的值初始化
constructor(name = '张三',age = 15,grade = '八'){
this.name = name
this.age = age
this.grade = grade
}
// 定义实例方法:
sayHello(str:string){
console.log(`我叫${this.name},今年${this.age}岁,我已经${this.grade}年级了`,str);
}
}
// 实例化一个对象
const stu = new Student()
stu.sayHello('你今年几年级了啊')
2.继承
继承是类与类之间的关系
继承后类与类之间的叫法:
A类继承了B类,此时A类叫子类,B类叫基类
子类---->派生类
基类---->超类(父类)
示例:
class Person{
// 定义属性
name:string
age:number
sex:string
// 定义构造函数
constructor(name,age,sex){
this.name = name
this.age = age
this.sex = sex
}
// 定义一个方法
sayHello(str:string){
console.log(`你好啊${this.name},${str}`);
}
}
// 定义一个类,继承Person
class Student extends Person{
constructor(name,age,sex){
super(name,age,sex)
}
// 可以调用父类中的方法
sayHello(){
console.log('我是父类的方法');
super.sayHello('哈哈')
}
}
// 实例化person
const person =new Person('张三',18,'男')
person.sayHello('呵呵')
// 实例化student
const stu = new Student('李四',18,'女')
stu.sayHello()
多态
父类型的引用指向了子类型的对象,不同类型的对象针对相同方法产生不同行为
// 创建父类
class Language{
name:string
constructor(name:string){
this.name = name
}
read(source:number = 0){
console.log(`我每天学习${source}个${this.name}词`);
}
}
class English extends Language{
name:string
constructor(name:string){
super(name)
}
read(source:number = 5){
console.log(`我每天学习${source}个${this.name}词`);
}
}
// 实例化父类
const lan:Language = new Language('语言')
lan.read()
// 实例化子类
const eng:English = new English('英语')
eng.read()
// 父类类型创建子类的对象
const eng1:Language = new English('英语')
eng1.read()
// 该函数需要的参数是Language类型的
function showLanguage(lan1:Language){
lan1.read()
}
showLanguage(eng1)
类中的成员修饰符
TypeScript 可以使用三种访问修饰符(Access Modifiers),分别是 public、private 和 protected。主要是可以描述类成员的可访问性。
(1)public
public修饰的属性和方法是公有的,可以在任何地方被访问到。
class Person{
// 设置公有访问 public
public name:string
public constructor(name:string){
this.name = name
}
public sayName(){
console.log('你好啊'+this.name);
}
}
const per = new Person('丽丽')
console.log(per.name); // 丽丽
per.sayName() // 你好啊丽丽
(2)private
修饰的属性或方法是私有的,不能在声明它的类的外部访问,当然子类也无法访问
class Person{
// 设置私有访问 private
private name:string
public constructor(name:string){
this.name = name
}
public sayName(){
console.log('你好啊'+this.name);
}
}
class Student extends Person{
constructor(name:string){
super(name)
}
}
// 实例化父类
const per = new Person('丽丽')
console.log(per.name); // ts(16,19) TS2341: Property 'name' is private and only accessible within class 'Person'.
per.sayName()
// 实例化子类 子类也无法访问
const stu = new Student('嘻嘻')
console.log(stu.name); // .ts(24,19)TS2341: Property 'name' is private and only accessible within class 'Person'
(3)protected
修饰的属性和方法受保护,与private相似,区别在于子类可以访问
class Person{
// 设置受保护的 protected
protected name:string
public constructor(name:string){
this.name = name
}
sayName(){
console.log('你好啊'+this.name);
}
}
class Student extends Person{
constructor(name:string){
super(name)
}
sayHello() {
console.log('我可以被访问',this.name);
}
}
// 实例化父类
const per = new Person('丽丽')
console.log(per.name); // ts(16,19) TS2341: Property 'name' is private and only accessible within class 'Person'.
per.sayName() // 你好啊,丽丽
// 实例化子类
const stu = new Student('嘻嘻')
stu.sayHello() // 我可以被访问 嘻嘻
readonly修饰符
readonly修饰符,对类中的属性成员进行修饰,修饰后该属性成员无法在外部修改。
class Person{
// 定义属性
readonly name:string
// 构造函数
constructor(name:string){
this.name = name
}
sayHello(){
console.log('你好啊'+this.name);
}
}
// 实例化对象
const person:Person = new Person('阿辉')
person.name = '小刘' // Cannot assign to 'name' because it is a read-only property
类中的方法也无法修改属性成员。
注意:如果 readonly 和其他访问修饰符同时存在的话,需要写在其后面。
class Person{
// 构造函数
constructor(public radonly name:string){
this.name = name
}
sayHello(){
console.log('你好啊'+this.name);
}
}
存取器
可以让我们有效控制对 对象成员中的访问,通过get 和 set 进行操作
class Person{
firstName:string
lastName:string
constructor(firstName:string,lastName:string){
this.firstName = firstName
this.lastName = lastName
}
// 读取器
get fullName(){
console.log('get中...');
return this.firstName + "_" + this.lastName
}
// 设置器
set fullName(val){
console.log('set中...');
let names = val.split('_')
this.firstName = names[0]
this.lastName = names[1]
}
}
// 实例化对象
const person:Person = new Person('上官','婉儿')
console.log(person);
console.log(person.fullName);
// 设置该属性的数据
person.fullName = '阿里_爸爸'
console.log(person.fullName);
静态成员
在类中通过static修饰的属性和方法,就叫做静态成员,构造函数不能通过static来修饰
语法格式:类名.静态属性/方法
class Person{
static name1:string = '张三'
static sayName(){
console.log('你好啊');
}
}
// 通过类名.静态属性方式访问成员数据
console.log(Person.name1);
// 通过类名.静态属性方式来设置成员数据
Person.name1 = '李四'
console.log(Person.name1);
// 通过类名.静态方法方式来设置成员数据
Person.sayName()
抽象类
包含抽象方法,也可以包含实例方法,抽象类不能被实例化,为了让子类进行实例化及实现内部抽象方法
abstract class Animal{
abstract eat()
// 会报错,抽象方法不能有具体实现
// console.log('吃');
// 实例方法
sayHi(){
console.log('你好啊');
}
}
// 定义一个子类
class Dog extends Animal{
eat(){
console.log('真好吃');
}
}
// 实例化Dog对象
const dog:Dog = new Dog()
dog.eat()
dog.sayHi()
// 无法实例化抽象类的对象
// const ani:Animal = new Animal()
四、函数
函数基本语法
语法格式:let 函数名(参数1:数据类型,参数2:数据类型) => 返回值类型 = function(参数1:数据类型,参数2:数据类型):返回值类型{ 函数表达式 }
// 函数声明,命名函数
function add(x:number,y:number):number{
return x + y
}
const result = add(4,3)
console.log(result);
// 函数表达式,匿名函数
const reduce = function(x:number,y:number):number{
return x - y
}
const result2 = reduce(4,3)
console.log(result2);
// 函数完整写法
const reduce1:(x:number,y:number) => number = function (x:number,y:number):number{
return x / y
}
const result3 = reduce1(4,3)
console.log(result3);
可选参数、默认参数和剩余参数
可选参数、默认参数
// firstName:string='李' 默认参数
// lastName?:string 可选参数
const getFullName = function(firstName:string='李',lastName?:string):string{
if(lastName){
return firstName + '_' + lastName
}else{
return firstName
}
}
console.log(getFullName());
剩余参数
语法格式:…args: 数据类型 [ ]
function add(a:number,...args: number[]){
console.log(a);
console.log(args);
}
add(1,5,6,2,4)
函数重载
函数名字相同,函数的参数及个数不同,如果传入非法数据,会提示错误信息
function add (x: string,y: string): string
function add (x: number,y: number): number
function add(x: string| number,y:string | number): string | number{
if(typeof x === 'string' && typeof y === 'string'){
return x + y // 字符串拼接
}else if(typeof x === 'number' && typeof y === 'number'){
return x + y // 数字相加
}
}
console.log(add('上官','婉儿'));
console.log(add(10,20));
五、泛型
泛型基本用法
在定义接口、类和函数不能确定是什么类型,而是在使用函数、接口、类的时候菜鸟确定数据的类型
语法格式:
function 函数名<T>(变量名:T,变量名:数据T):T[]{
}
调用时
函数名<数据类型>()
示例:
function getArr<T>(value:T,count:number):T[]{
const arr = []
for(let i = 0;i < count; i++){
arr.push(value)
}
return arr
}
const arr1 = getArr<number>(3.1415926,5)
const arr2 = getArr<string>('我爱你',3)
console.log(arr1);
console.log(arr2);
console.log(arr1[0].toFixed(2));
console.log(arr2[0].split(''));
多个泛型参数的函数
function showMessage<K,V>(value1:K,value2:V):[K,V]{
return [value1,value2]
}
const arr = showMessage<string,number>('abc',123.4567)
console.log(arr);
console.log(arr[0].split('-'));
console.log(arr[1].toFixed(2));
泛型接口
在定义接口时,为接口中的属性或方法定义泛型类型,在使用接口时,再指定具体的泛型类型
interface IBaseCRUD<T>{
data:Array<T>
add:(t:T) => T
getUserId:(id:number) => T
}
class User{
id:number
name:string
age:number
constructor(name:string,age:number){
this.name = name
this.age = age
}
}
class UserCRUD implements IBaseCRUD<User>{
data:Array<User>=[]
add(user:User):User{
user.id = Date.now()+Math.random()
this.data.push(user)
return user
}
getUserId (id: number):User{
return this.data.find(user => user.id === id)
}
}
const userCRUD:UserCRUD = new UserCRUD()
userCRUD.add(new User('jack',20))
userCRUD.add(new User('tom',25))
userCRUD.add(new User('lucy',23))
userCRUD.add(new User('rousi',21))
console.log(userCRUD.data);
泛型类
类中的属性值类型是不确定的,方法中的参书返回值类型也是不确定的。
class Add<T>{
count:T
add:(a:T,b:T) => T
}
const a1:Add<number> = new Add<number>()
a1.count = 10
a1.add = function(a,b){
return a + b
}
console.log(a1.add(1,2));
const a2:Add<string> = new Add<string>()
a2.count = '10'
a2.add = function(a,b){
return a + b
}
console.log(a2.add('亮亮','真帅'));
泛型约束
如果我直接对一个泛型参数取length属性会报错,因为这个泛型根本就不知道它有这个属性
interface ILength{
length:number
}
function getLength<T extends ILength>(x:T):number{
return x.length
}
console.log(getLength<string>('bilibili'));