鸿蒙开发--TypeScript(学习笔记)

138 阅读10分钟

学前班

TypeScript官网

官网
工具

image.png

JavaScript 与 TypeScript 的区别

TypeScript 是 JavaScript 的超集,扩展了 JavaScript 的语法,因此现有的 JavaScript 代码可与 TypeScript 一起工作无需任何修改,TypeScript 通过类型注解提供编译时的静态类型检查

TypeScript 的编译

TypeScript 可处理已有的 JavaScript 代码,并只对其中的 TypeScript 代码进行编译。 image.png

TypeScript 语法学习

输出日志

学习编程第一步,Hello World先输出!

console.log('Hello World!');
console.warn('Hello World!');
console.error('Hello World!');

变量

变量声明

TypeScript是JavaScript的超集,在JavaScript的基础上加入了静态类型检查功能,所以每一个变量都有固定的数据类型。

// msg 是变量名,string表示类型是字符串,等号右侧的东西会赋值给左侧的变量
let msg: string = 'Hello ArkTS'; // let 声明变量

const KEY: string = "key"        // const 声明常量

// 在JS/TS中,使用'' "" 都可以表示字符串
// 语句结尾的 ; 可加可不加,最好是加上,你不加编译器也会帮你补充

数据类型

  • string: 字符串,单引号双引号都可以
  • number: 数值,整数、浮点数都可以
  • boolean:布尔,true、fasle
  • any: 不确定类型,可以是任意类型
  • union:联合类型,可以是多个指定类型中的一种
  • void:空类型,一般用于函数的返回值
  • null:空对象
  • undefined: 未定义,创建变量未赋值,或者对象没有这个变量但引用这个变量时的值
  • Object :对象
  • array:数组
  • 元组

字符串类型

使用单引号('')或双引号("")来表示字符串,使用反引号(``)来定义多行字符串或内嵌表达式

let sa: string = '我学习,我进步!';
let ss: string = "加油自己,加油中国!";
let se: string = 
`
    我是第一行
    我是第二行
    我是第三行
`;
let sd = `${sa}${ss}`;

// 注意,string是小写

数字类型

双精度64位浮点数。可以用来表示整数和浮点数。TS中没有整数类型

let : number = 0b1010;                            // 二进制 0b
let octabinaryLiterallLiteral: number = 0o744;    // 八进制 0o
let decLiteral: number = 6;                       // 十进制 
let hexLiteral: number = 0xf00d;                  // 十六进制 0x
let floatLiteral: number = 0.98;                  // 浮点数

布尔

表示逻辑值:true 和 false。

let flag: boolean = true;

any 任意类型

因为any表示任意类型,所以给它赋值什么类型的数据都不犯毛病。意思也是告诉编译器,这个变量的类型不用你去给我推导,我想咋用咋用。但是这样做就让TypeScript失去了意义,那还不如用JavaScript了,费那劲写个any干啥。

let a:any = 'ArkUI';
a = 21;
a = true;

union 联合类型

变量赋值类型,可以是多个指定类型中的一种

let k: number|string|boolean = 'ItemAlign'  // ✅
k = true; // ✅
k = 12;// ✅

k=[]; // ❌会报错:Type 'never[]' is not assignable to type 'string | number | boolean'.

void

变量有数据类型,函数同样有返回类型,void 用来表示函数没有任何返回值。

function hello(): void {
  alert("Hello Bro!");
}

undefined

未定义,创建变量未赋值,或者对象中没有这个变量,但引用这个变量时的值

let a;
console.log(a); // undefined

console.log(b); // [ERR]: b is not defined

let c = {};

console.log(c.name); //  undefined

Object

匿名对象,其实就是个Json,或者叫字典

//定义
let p = { name: "DaZui", age: 18 }

// 使用
p.name
p['name']

数组类型

数组的定义,有两种形式

// 1.在元素类型后面加上[]
let arr: number[] = [1, 2];

// 2.使用数组泛型
let arr: Array<number> = [1, 2];

// 使用
arr[0]; // 使用下标 访问数组元素

举例

let err : string[] = ["1",1] // 会报错,元素类型不一致

let arr : string[] = ["1","2"]; // ✅

let a = 1
let b = 'a'
let c : string[] = ["1",'1',`${a}${b}`] // c ["1", "1", "1a"],这个例子注意元素外的引号

元组

元组类型用来表示已知元素数量和类型的数组,各元素的类型不必相同对应位置的类型需要相同。

//定义
let d : [number,string];
d= [1,"2"]

//使用起来和数组一样,只是需要注意数据类型
d[0];
d[1];

条件控制

if

if else if esle

条件语句是嘎嘎常用的语句。

if(变量|表达式){

}else{

}

if(变量|表达式){

}else if(变量|表达式){

}else{

}

if 后面通常情况下会跟一个 boolean 类型的变量

let isSuccess: boolean = true;
if(isSuccess){
    console.log('哇偶成功啦!');
}else{
    console.log('哇去,失败了?');
}

当然,也可以跟一个返回值为boolean的表达式

let num:number = 2;
if(num % 2 === 0){
  console.log(num+ '是偶数');
}else{
  console.log(num+ '是奇数');
}

当然,还可以是一个返回值为boolean 的函数

function isSuccess():boolean {
    return true;
}

if(isSuccess()){
 console.log('哇偶成功啦!');
}else{
    console.log('哇去,失败了?');
}

甚至,可以是任何你能想到的值

let a = 0;
let b = 1;
let c = '';
let d = "hh"
let e = {};
let f: number[] = [];

if(a || b || c || d || e || f){
 console.log('哇偶成功啦!');
}else{
    console.log('哇去,失败了?');
}

特别注意: 在TypeScript中,false、空字符串''、数字0nullundefined,都被认为是false,其余值则为true

//所以if判断可以简写成这样
let num ;

if(num){
  console.log('num有值');
}else{
  console.log('num没有值');
}

switch-case

针对一个变量存在多种值进行判断时使用,switch()的参数一般情况下估计没人传boolean吧,彪呵的。

let grade : string = 'A';
switch(grade){
    case 'A':{
        console.log('真特么的好');
        break;
    }
    case 'B' :{
        console.log('一般好');
         break;
    }
    case 'C':{
        console.log('不咋地');
         break;
    }
    default :{
        console.log('胡说八道了');
    }
}

循环迭代

循环迭代 forwhile,应该所有语言都包含这两种循环语句

for

普通for循环

for(let i = 1 ; i < 10 ; i ++){
    if(i == 5){
        continue; // 跳过本次循环,继下次循环
    }
    if(i == 7){
        break; // 直接跳出循环体
    }
     console.log(i);
}
 console.log('循环执行完毕!');

for-in: 迭代index,即数组的角标

let arr: string[] = ["a","b","c"]

for(let i in arr){
     console.log(i);
}

//输出 "0" "1" "2"

for-of: 迭代value,即数组的元素

let arr: string[] = ["a","b","c"]
for(let i of arr){
     console.log(i);
}
// 输出 "a" "b" "c"

while

普通 while,但是一般这样的迭代会用 for

let j: number = 1;
while( j <= 10){
    console.log(j);
    j++;
}

while 常用场景

let isContinue : boolean = true;
while(isContinue){
    if(当发生特定条件时){
        isContinue = false;
    }
}

函数

TypeScript通常使用function关键字声明函数,并且支持可选参数、默认参数、箭头函数等特殊语法。
函数通常用来封装可复用的操作,代码的可维护性更强。 函数的编写按照软件设计思想是有一定的要求的,要有明确的输入输出,不应该传递引用返回void,这样的函数可测性非常低。

无返回值,可以省略void,这样可读性会差一些,尽量不要这样做,养成好的编程习惯。

普通function

function sayHello(name: string): void{
    console.log('你好,' + name + '!')
}
sayHello('Tom');

function赋值给变量,因为function本身也是一种数据类型,它当然可以赋值给变量了。

let a = function(name: string): void{
    console.log('你好,' + name + '!')
}
a('Bob');

自调用函数

let a = function (name: string): void{
     console.log('你好,' + name + '!')
}('Jarry');

箭头函数

//完整写法
let a : (name:string) => void = (name: string):void =>{
     console.log('你好,' + name + '!')
}
a('Tommy');

// 简写
let a = (name: string) => {
     console.log('你好,' + name + '!')
}
a('Tommy');

可选参数函数

function sayHello(name?: string){
    console.log('你好,' + name + '!')
}

sayHello(); // [LOG]: "你好,undefined!"

为参数添加默认值
(name: string = '陌生人')

// 添加默认值
function sayHello(name?: string){
    name = name? name : '陌生人';
    console.log('你好,' + name + '!')
}
sayHello();

//上面这种写法可以,但是很麻烦

function sayHello(name: string = '陌生人'){
    console.log('你好,' + name + '!')
}
sayHello();

类和接口

TypeScript具备面向对象编程的基本语法,interfaceclassenum等。同时也具备抽象、封装、继承、多态等面向对象的基本特征。

enum

enum是很常用的,可以明确定义边界,使程序降低出错的风险,同时也增强了扩展性,下面这种是很常见的不使用枚举的写法,每个地方都要考虑溢出的风险,后续想要增加一种类型,需要修改的地方就会很多,同时这些修改是不是覆盖的比较全面,也很不容易发现

// 不使用枚举时, 维护很困难
const RED: string = 'red';
const GREEN: string = 'green';
const BLUE: string = 'blue';

interface IPrintColor{
    print(type: string): void; // 注意 type 是RED、GREEN、BLUE中的一个,使用时请注意判断越界
}

class Printer implements IPrintColor{
   
     print(type: string) : void{
        if(type !== RED && type !== GREEN && type !== BLUE){
             console.log('ERR: 输入不合法,请重新输入!');
             return;
        }
        console.log('颜色:' + type + '!')
    }
}

比较好的实现方式

enum ColorType{
  RED   = '红色',   
  GREEN = '绿色', 
  BLUE  = '蓝色'
}

interface IPrintColor{
    print(type: ColorType): void;
}

class PrintColorZH implements IPrintColor{
    print(type: ColorType) : void{
        console.log('颜色:' + type + '!')
    }
}

定义枚举, 使用关键字 enum, 如果不指定值,其值默认从0开始。

enum Type{
  RED,    // 0
  GREEN,  // 1
  BLUE    // 2
}
// 使用
Type.RED
console.log('颜色:' + Type.RED + '!'); // [LOG]: "颜色:0!"

可以为每一个元素指定一个value

enum What {
    FOUR = 4,
    FIVE = '5',
}
console.log('数字:' + What.FIVE + '!') // [LOG]: "数字:5!"

class

类的定义使用关键字 classsconstructor 用来定义构造函数,也就是创建对象时,为对象的成员变量进行初始化。使用 new 关键字来创建对象。

什么是类什么是对象呢? 比如 猫 就是类,TOM 就是 一个对象,是一个活生生存在的东西,而类呢,相当于一个模板,可以使用这个模板去创建一个真实存在的实体,这个实体就是对象。

class View{
    private width: number ;
    private height: number ;
  
    // private index: number ; // 这一行会报错,定义时没有初始化,构造函数中又未定义

    constructor(width: number, height: number){ // constructor 构造函数
        this.width = width;
        this.height = height;
    }
    changeWidth(newWidth : number){
        this.width = newWidth;
    }
    logSelf(){
       console.log(`width: ${this.width} , height: ${this.height}`); // 
    }
}

// 创建 View 类的 对象

let view : View = new View(100,200);
view.logSelf();

view.changeWidth(160);

view.logSelf();

说到类,当然要说到继承,继承使用关键字 extends 来实现。

// 定义矩形
class Rectangle{
    private width: number ;
    private height: number ;
  
    // 构造函数
    constructor(width: number, height: number){ // constructor 构造函数
        this.width = width;
        this.height = height;
    }

    //成员方法
    public area() : number{
        return this.width * this.height;
    }
}
// 定义正方形
class Square extends Rectangle{
    constructor(side: number){
        // 调用父类构造函数
        super(side, side);
    }
}

let s = new Square(10);
console.log('正方形的面积为: ' + s.area()); // [LOG]: "正方形的面积为: 100"

interface

定义接口使用关键字 interface, 实现接口使用关键字 implements 接口就非常非常常用了,凡是学过面向对象编程语言的,都知道interface 在编程界的地位,通常我们说的callback其实也是基于interface去实现的。

interface CallBack{
    onCall():void; // 声明方法,不需要有具体的实现,具体的实现由 类 来完成
}

class View{
    callBack: CallBack;

    constructor(callBack: CallBack){
        this.callBack = callBack;
    }
    onClick(){
        //干了一些事
        this.callBack.onCall();
    }
}

class ClickCallBack implements CallBack{
    onCall(){
        console.log('发生了点击')
    }
}


let clickCallBack : ClickCallBack = new ClickCallBack();
let view = new View(clickCallBack);

view.onClick(); // [LOG]: "发生了点击"

比较全的案例:

enum ColorType{
  RED   = '红色',   
  GREEN = '绿色', 
  BLUE  = '蓝色'
}

interface IPrintColor{
    print(type: ColorType): void;
}

class PrintColorZH implements IPrintColor{
    print(type: ColorType) : void{
        console.log('颜色:' + type + '!')
    }
}

class PrintColorEN implements IPrintColor{
     print(type: ColorType) : void{
        let printResult = '';
        switch(type) {
            case ColorType.RED: {
                printResult = "Red"
                break;
            }
            case ColorType.GREEN: {
                printResult = "Green"
                break;
            }
            case ColorType.BLUE: {
                printResult = "Blue"
                break;
            }
        }
        console.log('This is :' + printResult + ' color!')
    }
}

let myColorPrint: IPrintColor = new PrintColorZH(); // 创建了PrintColorZH但是由IPrintColor承接,这就是多态
myColorPrint.print(ColorType.BLUE); // [LOG]: "颜色:蓝色!"

myColorPrint = new PrintColorEN();
myColorPrint.print(ColorType.BLUE); // [LOG]: "This is :Blue color!"

模块

应用复杂时,把代码全放到一个文件是非常蠢的,读起来不方便,改起来更不方便。可以把一类通用功能抽取放到单独的ts文件中,每个文件都是一个模块(module)。模块可以互相加载,提高代码的复用性。维护起来也更轻松一些。

模块的导出使用export关键字。
模块的导入使用import from 关键字。

模块的定义与导出

// regtangle.ts文件中
export class Rectangle{
    private width: number ;
    private height: number ;
  
    // 构造函数
    constructor(width: number, height: number){ // constructor 构造函数
        this.width = width;
        this.height = height;
    }
}

export function area(rec: Rectangle) : number{
    return rec.width * rec.height;
}

模块的导入

// index.ts文件中
import { Rectangle , area} from '../regtangle'

let r = new Rectangle(10, 20);
console.log('长方形的面积为: ' + area(r)); // [LOG]: "长方形的面积为: 200"