Bootstrap

HarmonyOS4.0 TypeScript高级

一、数据类型

JavaScript的类型分为两种,原始数据类型和对象类型

原始数据类型包括:布尔值、数值、字符串、null、undefined以及ES6中的新类型Symbol和ES10中的新类型BigInt

1、布尔值

布尔值是最基础的数据类型,在TypeScript中,使用boolean定义布尔值类型

TS

let flag:boolean = false;
console.log(flag);
let Boo:Boolean = new Boolean(1);
  

2、数值

TS

let age:number = 24;
console.log(age);
let ageNumber:number = NaN;

3、字符串

TS

let username:string = "admin";
let id:number = 1001;
let str:string = 
用户的ID为:${id}
;
console.log(str);

4、空值

在JavaScript中没有空值(void)的概念,但是在TypeScript中可以使用

TS

let nallValue:void = undefined;
console.log(nallValue);

声明一个void类型的变量没有什么用,因为你只能赋值为undefined和null

在严格模式下,void类型只能赋值undefined 在非严格模式下,void类型只能赋值undefined和null

5、Null&Undefined

在TypeScript中,可以使用null和undefined来定义两个原始数据类型。

TS

let u:undefined = undefined;
let n:null = null;
console.log(u,n);

与void的区别是,undefined和null是所有类型的子类型,也就是说undefined类型的变量,可以赋值给number类型的变量

TS

let num1:number = undefined;
let num2:number = null;
let num3:number = num1;

void类型的变量不能赋值给number类型的变量

let v:void;
let num4:number = v; // error TS2322: Type 'void' is not assignable to type 'number'.【不能将类型“void”分配给类型“number”。ts(2322)】

6、任意值

任意值(any)用来表示允许赋值为任意类型 任意类型:如果是一个普通类型,在赋值过程中改变类型是不被允许的,但如果是any类型,则允许被赋值为任意类型

TS

let num:any = 1;
console.log(num);
num = "admin";
console.log(num);
console.log(num.handler);

注意:如果变量在声明的时候,没有指定类型,那么默认为任意值类型

TS

let message;
message = 1;
message = "描述内容";

8、数组类型

// 声明数组
let array:number[] = [1,2,3,4,5];
console.log(array);
array.push(6);
console.log(array);
array[6] = 7;
console.log(array);

数组中不允许出现其他类型

9、元组类型

TS对数组中存储的数据进行了严格规范,为了可以同时存储不同类型的数据,又提供了元组类型 元组:数量和类型固定的数组

let array:[string,number] = ["admin",24]

10、枚举

枚举:用于取值被限定在一定范围内的场景,比如一周只能有七天,颜色限定为红绿蓝等

// 定义枚举
enum UserStatus{
    enable,disable,a = 22,b,c,d
}
// 获取枚举变量
console.log(UserStatus.enable); // 0
console.log(UserStatus.disable); // 1
console.log(UserStatus.a); // 22
console.log(UserStatus.b); // 23
console.log(UserStatus.c); // 24
// 获取枚举变量
console.log(UserStatus["a"]); // 22
// 赋值
let sts:UserStatus = UserStatus.disable; // 1
console.log(sts);

11、void

void:专门提供给函数的返回值的类型,表示函数没有返回值

function handler():void{
  console.log("该函数没有返回值");
}

12、never

never:表示一种不存在的数据,一般存储异常数据、错误数据等 never类型是那些总是会【抛出异常】或根本就【不会有返回值的函数表达式】或【箭头函数表达式的返回值类型】

never类型是任何类型的子类型,也可以赋值给任何类型,但是没有类型是never的子类型或可以赋值给never类型,除了本身,any也不可以赋值给never

function error(message:string):never{
  throw new Error(message);
}

13、联合类型

联合类型,表示取值可以为多种类型中的一种

let code:string | number;
code = 1;
code = "admin";

联合类型使用|分隔每个类型,code变量类型允许是string或number,但是不能是其他类型

访问联合类型的属性或方法

当TypeScript不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法

let myMessage:string|number;
// console.log(myMessage.length); 报错
console.log(myMessage.toString());
// length不是string和number的共有属性,所以会报错
// toString()方法是string和number共有的方法,所以不会报错

二、类型操作

1、类型推断

声明变量同时直接赋值,可以不用指定变量的类型,TS会根据变量中存储的数据,推断变量应该存储什么类型的数据

// 声明变量
// 没有指定变量的数据类型,TS根据存储的具体数据
tom
反向推断变量类型
// 底层就会指定myName变量存储字符串数据
let myName = "tom"
console.log(
myName: ${myName}
)
// myName = true
// 不能将类型“boolean”分配给类型“string”
console.log(myName: ${myName})

2、类型转换

TS中和JS一样,支持基本类型数据转换操作,遵循JS中类型转换的语法,原生JS中的各种类型转换函数,在TS中可以直接使用

// 2、类型转换
// 字符串类型strAge
let strAge: string = "20"
// 类型转换
// 数值类型:age
let age: number = parseInt(strAge)
console.log(age: ${age})

3、类型断言

TS语法包含了编译时检查,会根据代码语法对开发人员编写的代码进行预检查排除基础语法操作,但是这样的错误排查在有些情况下误伤正确代码,需要编写代码的同时通过类型断言指定变量当成什么类型进行处理 TS本身编译时检查,导致某些数据的操作出现错误提示,类型断言,可以让指定的代码进行类型强调

// 3、类型断言
let result: number | string = "list ok"
// 严格校验语法:result可能是number类型所以会提示result不能调用length属性
let res: number = result.length
// 类型断言:开发人员比代码更清楚某个变量的取值
// 语法1:   <类型>变量,通过断言指定这个变量现在属于什么类型进行操作
// let res: number = (<string>result).length
// 语法2: 变量 as 类型,通过as关键字指定变量现在属于什么类型进行操作
let res: number = (result as string).length
console.log(
数据长度:${res}
)
// 类型断言在函数参数中的一个测试
// 类型断言测试
function fn(msg: string | number): void {
  // msg可能是number类型或者string类型
  // 类型“number”上不存在属性“length”
  // console.log("消息长度:", msg.length)
  // console.log("消息长度:", (<string>msg).length)
  console.log("消息长度:", (msg as string).length)
}
fn("hello typescript")

三、运算符

四、流程控制语句

五、函数

TS中的语法对原生JS中的函数进行了良好的支持,配合变量的数据类型约束,增强了函数中对数据安全性的控制

1、声明函数

// 基础语法
function 函数名称([参数]){
  函数体
  [return 返回值]
}
// TS扩展语法
function 函数名称([参数名:数据类型,....]) : 返回值类型{
  
}

基础语法:严格校验模式下,参数没有指定类型,编译不会通过 TS扩展语法:对函数的参数、函数的返回值数据类型都进行了约束,提高函数的可读性 TS语言环境:函数声明的形式参数,必须传递对应的实际参数,否则编译不通过

function handler(message:any){
    console.log(message);
    
    return 123;
}
console.log(handler("数据"));
function handler1(message:string):void{
    console.log(message);
}
console.log(handler1("新的数据"));

2、匿名函数

匿名函数:函数声明的时候没有命名,将声明创建的函数直接赋值存储到变量中

let handler = function(msg:string):void{
  console.log(msg);
}
handler("内容描述");

3、函数的参数

函数声明的时候,包含在函数声明后面的括号中的变量,称为函数的形式参数 形式参数:描述了函数内部代码执行时需要的数据,调用函数时必须给形式参数传递数据

3.1、位置参数
// 形式参数:位置参数/普通参数,调用执行函数时必须给参数传递数据
function fn(name: string, age: number): void {
  console.log(name, age)
}
// 调用函数时,传递实际数据/实际参数 给 形式参数/位置参数
// 位置参数:按照参数位置顺序,依次传递和赋值的过程
fn("admin", 18)
3.2、参数默认值
// 形式参数:可以在声明参数的时候,添加默认值
function fn(name: string, age: number=18): void {
  console.log(name, age)
}
// 调用函数时,如果没有给默认值参数传递数据,age就会使用默认值参与数据运算
fn("admin")
// 如果给默认值参数传递了数据,age就会使用传递的实际数据
fn("管理员", 22)
3.3、可选参数
// 形式参数:TS中在调用函数时,位置参数必须传递数据
// 声明函数时也可以设置可选参数,可选参数允许调用函数时不传递数据
function fn(name: string, age?: number):void {
  // 一旦设置了可选参数,函数中对可选参数进行判断输出
  console.log(
姓名: ${name}, ${age ? '年龄:' + age : ''}
)
}
// 调用函数时,可选参数可以不用传递数据
fn("admin")
fn("管理员", 20)
3.4、剩余参数

剩余参数/可变参数

// 剩余参数:需要数组类型的约束
function fn(name, ...jobs: string[]): void{
  console.log(name, jobs)
}
fn("admin")
fn("admin", "html")
fn("admin", "html", "css")
fn("admin", "html", "css", "js")

4、各种函数用法

4.1、匿名函数
// 声明了一个没有名称的函数,赋值给变量进行使用
const sayHello = function(name: string):void {
  cosnole.log("hello " + name)
}
// 自执行:匿名函数
;(function() {
  // 声明就会立即执行的匿名函数
  ...
}) ()
4.2、递归函数
4.3、自执行函数

自执行函数,结合匿名函数,实现一种声明函数的同时就自动执行函数内部代码的语法

;(function() {
  // 函数内部的代码
  // 当前函数一旦声明完成,(运行程序时不需要调用)就会立刻执行!
})()
4.4、回调函数

一般处理异步任务时,多个异步函数执行过程中,需要让多个异步函数按照顺序执行而不是同时执行,需要回调函数语法的支持 回调函数:执行完一个函数,回头再去调用另一个函数的过程 回调执行的函数:一般作为参数传递给第一个函数

function fun1(){
    setTimeout(function(){
        console.log("fun1");

    }, 2000);
}
function fun2(){
    setTimeout(function(){
        console.log("fun2");

    }, 1000);
}
// 常规调用
fun1();
fun2();
// 按照顺序,执行fn1,fn2
// 回调函数语法支持:将fn2函数 当成参数传递 给fn1函数
// fn1函数执行完成后,再去/回头 调用fn2函数
function fn1(f){
    setTimeout(function(){
        console.log("fn1");
        f();

    }, 2000);
}
function fn2(){
    setTimeout(function(){
        console.log("fn2");

    }, 1000);
}
fn1(fn2);
4.5、箭头函数

TS借鉴ES6的语法实现,简化函数语法的声明提高开发效率

// 基础语法
function fn():void{
  console.log("普通函数");
}
// 箭头函数优化
let fn = ():void=>{
  console.log("普通函数");
}
// 带参数
function fn(name:string):void{
  console.log("箭头函数" + name);
}
let fn = (name:string):void=>{
  console.log("箭头函数" + name);
}
// 带返回值
function fn(name:string):string{
  console.log("箭头函数" + name);

  return name;
}
let fn = (name:string):string=>{
  console.log("箭头函数" + name);

  return name;
}

5、函数的重载

TS中参考了其他高级语言,提供了函数重载的语法机制 函数重载:在同一个作用域中,可以同时存在相同名称不同参数的多个函数 函数重载在TS中就是一种语法糖,也是给以后可能进行语法升级做好了铺垫

// 1、函数签名
function echo(name: string): void;
function echo(name: string, age: number): void;
// 2、函数实现
function echo(name: string, age?: number):void {
  console.log("你好 " + name + ";年龄:" + age)
}

六、内置对象

1、String&Number

String/Number都属于基本类型的内置对象,它们的操作方式和原生JS中一模一样

2、Array

数组类型,TS中针对数组进行了数据类型约束,同一个数组中必须约束类型的数据

2.1、数组的声明
// 只能存储字符串数据的数组
let arrStr:string[] = [];
// 只能存储数值类型的数组
let arrNum:number[] = [];
// 可以存储任意类型的数组
let arrAny:any[] = [];
2.2、数组的操作

数组中的操作函数,和原生JS数组的操作函数一模一样

3、Map

Map类型也是TS语法中借鉴了ES6中的类型,是对JSON字面量对象的补充 JSON字面量对象的key值只能是基础类型 Map对象的key值可以是任意类型 操作方式和操作函数,和原生JS/ES6操作语法一模一样

4、元组

TS中的数组有了数据类型的限制,正常情况下一个数组中只能存储限定的某种类型的数据 数组的功能受到了限制 数组中的数据保护得到了提升

代码中需要原生JS数组的功能支持,TS中提供了一个新的类型:元组 元组中可以存储指定不同类型的数据,类似原生JS数组对象

// 直接赋值和操作
// 没有写类型约束,执行过程中根据实际数据进行反向判断
    // let jobs = ["java工程师",false,12];
    let jobs:[string,boolean,number] = ["java工程师",false,12];
console.log(jobs);
// 添加数据
jobs.push("架构师");
console.log(jobs);
console.log(jobs.length);
// 截取数据
console.log(jobs.slice(1,3));
// 删除数据
// 从后递减
jobs.pop();
console.log(jobs);
// 从头递减
jobs.shift();
console.log(jobs);
// 修改数据
jobs[0] = "前端工程师";
console.log(jobs);

七、接口

接口interface,描述了一种数据格式的规范 一些属性的声明 一些函数的模板

1、认识接口

原生JS中的问题

// 声明一个展示信息的函数
// Info参数:按照字面量对象的方式进行传递,包含name和age两个数据
function show(info= {name:'', age: 18}) {
  console.log("个人信息: 姓名" + name + ";年龄:" + age)
}
// 调用执行函数时,传递的数据可能不满足要求
// 满足
show({name: "admin", age: 22})
// 不满足:传递的数据和要求的数据不一致,但是函数还可以正常执行
show({name: "admin"})
show({age: 20})
show({gender: "male"})

TS中的语法约束

针对函数接受的这个对象参数,参数中需要包含name属性、age属性,可以通过定义一个接口类型,对参数的类型进行强制约束,保障函数执行过程中对象参数的属性描述 接口:主要用于自定义数据类型约束

// TS接口方式
interface PersonInfo{
  name:string;
  age:number
}
function show (info:PersonInfo){
  // 
}

2、接口语法

// interface 声明接口
// 接口名称:命名规范和类名称一致,帕斯卡命名法/大驼峰命名法
// 2.1. 基本语法
interface Person {
  // 普通属性
  name: string;
  // 标准函数
  show(): void;
  // 箭头函数
  show2: () => void;
}
let tom: Person = {
  name: "汤姆",
  show() {
    console.log("姓名:" + this.name)
 },
  show2: (): void => {
    console.log("箭头函数声明")
 }
}
// 访问数据
console.log(tom.name)
// 调用方法
tom.show()
tom.show2()

接口中的可选属性

// 可以通过TS特定语法,将某个属性添加为可选属性
interface Person {
  name: string; // 必选属性
  age: number;      // 必选属性
  address ?: string   // 可选属性,通过?:方式进行声明
}
// 完整属性,正确
let tom: Person = {
  name: "汤姆",
  age: 22,
  address: "国际郑"
}
  
// 省略address属性,正确
let jerry: Person = {
  name: "杰瑞",
  age: 18
  }

3、接口中联合类型

TS接口声明过程中,接口内属性也可以指定联合类型,某个属性值可以取值多种类型的数据

// 声明一个指定运行命令你的接口
interface RunOperation {
  cmd: string; // 运行命令
  options: string | string[] | (() => string)
}
// 声明一个变量,存储查询ip命令的对象
let ip: RunOperation = {cmd: 'ipconfig', options: '/A'}
// 声明一个变量,存储查询使用端口的命令对象
let net: RunOperation = {cmd: 'netstat', options: ['-a', '-o',
'-n']}
// 声明一个变量,存储创建文件夹的命令
let mk: RunOperation = {cmd: 'mkdir', options: () => '-p
test'}

4、接口中的数组

TS中可以通过接口规范数组中的索引和对应的取值 数组也可以通过接口进行类型规范

interface MyArray{
    [index:number]:number
  
}
let arr:MyArray = [1,2,3,4];
console.log(arr);

5、接口继承

项目开发中,可能会出现多个接口规范了不同的数据,当部分数据需要组合使用时,可以通过接口继承的语法实现接口中的代码复用

// 技术类型接口
interface Techs {
  name: string
}
// 年份类型接口
interface Years {
  yyyy: string
}
// 需要一个描述某个技术和创建年份的接口
// 同时需要技术名称、完整年份
interface MyTech extends Techs, Years {}
// MyTech接口中,可以同时使用多个 父接口中规范的数据约束
let nodejs: MyTech = {name: "nodejs", yyyy: '2009'}

八、面向对象

1、属性/方法修饰符

TS中针对类型中的属性和方法,提供了访问限制,通过修饰符指定访问范围

  • public
    • 默认修饰符,公共的,修饰的属性和方法可以被任意位置访问
  • protected
    • 受保护的,修饰的属性和方法只能被自己和子类访问
  • private
    • 私有的,修饰的属性和方法只能被当前类型内部访问
class User{
    id:number;
    private username:string;
    password:string;
    constructor(id:number,username:string,password:string){
        this.id = id;
        this.username = username;
        this.password = password;
    }
    getUserName():string{
        return this.username;
    };
}
let u1:User = new User(1,"admin","admin");
console.log(u1.getUserName());

2、面向对象特性

面向对象特性有三种:

  1. 封装
    1. 将相关的数据统一封装在类型的内部,不让外界直接访问,而是通过提供的函数进行访问,访问函数中可以添加访问条件,达到保护数据的目的
  2. 继承
    1. 类型和类型之间的关联关系,通过继承可以复用类型中的代码
  3. 多态
    1. 程序运行过程中,一个对象的状态可以跟随正在执行的流程进行动态切换的过程
2.1、封装
class Pet {
  // 成员属性私有化:封装
 private nickname: string;
 // 提供访问函数
 getNickname(): string{
    return this.nickname
 }
 // 提供设置函数
 setNickname(nk: string):void{
    this.nickname = nk
 }
 constructor(nickname: string) {
    this.nickname = nickname
 }
}
var tom = new Pet("汤姆")
// tom.nickname = "tom"   // 报错:不让访问
console.log(tom.getNickname()) // 读取
tom.setNickname("tom") // 设置
2.2、继承

TS中提供了extends关键字,实现了类型和类型之间的关联继承关系,实现类型代码的复用

class Animal {
    name:string;
    constructor(name:string){
        this.name = name;
    }
}
class Dog extends Animal{
    weight:number;
    name:string;
    constructor(name:string,weight:number){
        super(name);
        this.weight = weight;
    }
}
2.3、多态
class Animal {
    name:string;
    constructor(name:string){
        this.name = name;
    }
    eat():void{

    }
}
class Dog extends Animal{
    weight:number;
    name:string;
    constructor(name:string,weight:number){
        super(name);
        this.weight = weight;
    }
    eat():void{
        console.log("狗吃骨头");

    }
}
class Cat extends Animal{
    weight:number;
    name:string;
    constructor(name:string,weight:number){
        super(name);
        this.weight = weight;
    }
    eat():void{
        console.log("猫吃鱼");

    }
}
let dog:Animal = new Dog("泰迪",10);
let cat:Animal = new Cat("妮妮",10);
dog.eat();
cat.eat();
;