自学内容网 自学内容网

HarmonyOS4.0开发-TypeScript快速入门

前端工程化的发展,衍生出的TS已将运用非常广泛,Vue+TS,React+Ts,华为推出的ArkTs(Ts的超集)等一系列,都表明TS的重要性,所以在此总结一下TS的基本语法,方便大家平滑过渡。

安装Ts-node

ts-node是⼀个 TypeScript 的运⾏环境, 它允许我们直接运⾏ TypeScript 代码 。ts-node 的安装和运⾏依赖于Node.js环境, 因此在安装ts-node之前, 我们需要准备好Node.js环
境。
准备Node.js环境需要完成以下两步操作

  • 安装Node.js
  • 配置环境变量

为了⽅便在终端执⾏Node.js相关的命令, 我们需要将Node.js的安装⽬录加⼊到path 环境变量下, 具体操作如下:
⾸先查看Node.js的安装⽬录
然后打开环境变量配置⾯板,按下Win + R ,唤起运⾏窗⼝,之后运⾏命令sysdm.cpl
在这里插入图片描述
之后点击⾼级选项卡, 并点击环境变量
在这里插入图片描述
然后在系统变量中选中 Path , 并点击编辑
在这里插入图片描述
之后点击新建, 并填⼊Node.js的安装⽬录, 完成后点击确定。
在这里插入图片描述
在配置完Node.js环境后 ,便可在终端执⾏以下命令来安装ts-node了。

npm install -g ts-node

注 :完成后需要重新启动VSCode, 另其重新加载环境变量和相关依赖。

语法声明

2.2.2.1.** 变量声明**
在这里插入图片描述
2.2.2.2. 常量声明
let ⽤于声明变量,⽽在赋值后便不能再修改。 const ⽤于声明常量,两者的区别是变量在赋值后可以修改,⽽常量在赋值后便不能再修改。

const b:number = 200;

2.2.2.3. 类型推断
如果⼀个变量或常量的声明包含了初始值 ,TS 便可以根据初始值进⾏类型推断 ,此时我们就可以 不显式指定其类型 ,例如

let c = 60;
console.log(typeof c); //number

2.2.3. 常⽤数据类型
2.2.3.1. number

number表示数字,包括整数和浮点数,例如: 100 、-33 、2.5 、-3.9

let a :number = 100
let b :number = -33
let c :number = 2.5
let d :number = -3.9

2.2.3.2. string

string表示字符串,例如:你好 、hello

let a:string = '你好 '
let b:string = 'hello'

2.2.3.3. boolean

表示布尔值, 可选值为:true 、false

let isOpen:boolean = true
let isDone:boolean = false

2.2.3.4. 数组
数组类型定义由两部分组成,元素类型[] , 例如number [] 表示数字数组,string [] 表示字符串数组, 数组类型的变量可由数组字⾯量——[item1,item2,item3] 进⾏初始化。

let a: number [] = []
let b: string [] = [ '你好 ', 'hello']

2.2.3.5. 对象
在TS中, 对象( object) 是⼀种⼀系列由属性名称和属性值组成的数据结构 ,例如’ 张三 ', 年龄 :10, 性别 : '男 ’ 。对象类型的声明需要包含所有属性的名称及类型 ,例如{name: string, age: number, gender: string} , 对象类型的变量可以通过对象字⾯量——{name: '张三 ', age:10, gender: '男 '} 进⾏初始化。

let person: {name:string, age:number, gender:string} = {name: '张三 ', age:10, g ender: '男 '};

2.2.4. 函数
2.2.4.1. 函数声明语法
声明函数的基础语法如下
在这里插入图片描述
2.2.4.2. 参数详解
2.2.4.2.1. 特殊语法
● 可选参数
可选参数通过参数名后的?进⾏标识, 如以下案例中的gender?参数。

function getPersonInfo(name: string, age: number, gender?: string): string {
if (gender === undefined) {
gender = '未知 '
    }
    return `name:${name},age:${age},gender:${gender}`;
}
let p1 = getPersonInfo( 'zhagnsan', 10, '男 '); 
let p2 = getPersonInfo( 'lisi', 15);
console.log(p1);
console.log(p2);

注 :调⽤函数时, 未传递可选参数 ,则该参数的值为undefined

默认参数
可在函数的参数列表为参数指定默认值, 如以下案例中的数。

function getPersonInfo(name: string, age: number, gender: string= '未知 '): string {
return `name:${name},age:${age},gender:${gender}`;
}
let p1 = getPersonInfo( 'zhagnsan', 10, '男 ') 
let p2 = getPersonInfo( 'lisi', 15);
console.log(p1);
console.log(p2);

2.2.4.2.2. 特殊类型
● 联合类型

⼀个函数可能⽤于处理不同类型的值, 这种情况可以使⽤联合类型 ,例如以下案例中的
sage: number | string

function printNumberOrString(message: number | string) { console.log(message)
}

printNumberOrString( 'a')
printNumberOrString(1)

若函数需要处理任意类型的值 ,则可以使⽤any类型 ,例如以下案例中的message: any

function print(message:any) { console.log(message)
}

print( 'a')
print(1)
print(true)

2.2.4.3. 返回值详解
2.2.4.3.1. 特殊类型
若函数没有返回值 ,则可以使⽤void作为返回值类型, 其含义为空。

function test(): void {   
console.log( 'hello');
}

2.2.4.3.2. 类型推断
函数的返回值类型可根据函数内容推断出来, 因此可以省略不写。

function test() {
console.log( 'hello');
}

function sum(a: number, b: number) { 
return a + b;
}

2.2.4.4. 函数声明特殊语法
● 匿名函数

匿名函数的语法结构简洁, 特别适⽤于简单且仅需⼀次性使⽤的场景。

let numbers: number [] = [1, 2, 3, 4, 5]   
numbers.forEach(function (number) {
console.log(number);
})

注意: 匿名函数能够根据上下⽂推断出参数类型, 因此参数类型可以省略。

● 箭头函数
匿名函数的语法还可以进⼀步的简化, 只保留参数列表和函数体两个核⼼部分, 两者用=>符号连接。

let numbers: number [] = [1, 2, 3, 4, 5]
numbers.forEach((num) => { console.log(num) })

2.2.5. 类( class)
2.2.5.1. 概述
类( class) 是⾯向对象编程语⾔中的⼀个重要概念。
⾯向对象编程( Object-Oriented Programming, 简称OOP) 是⼀种编程范式, 其核⼼理念在于 将程序中的数据与操作数据的⽅法有机地组织成对象 ,从⽽使程序结构更加模块化和易于理解。通过对象之间的协同合作, 实现更为复杂的程序功能。类( class) 是对象的蓝图或模板, 它定义了对象的属性( 数据) 和⾏为( ⽅法) 。通过类可以创建多个具有相似结构和⾏为的对象 。例如定义⼀个Person类, 其对象可以有 张三 、李四等等。

2.2.5.2. 语法说明
2.2.5.2.1. 类的定义
定义类的语法如下图所示
在这里插入图片描述

代码如下:

class Person {
id: number;
name: string;
age: number = 18;

    constructor(id: number, name: string) {
this.id = id;
this.name = name; 
}
-   introduce(): string {
return `hello,I am ${this.name},and I am ${this.age} years old`
}
}

2.2.5.2.2. 对象创建
● 语法
创建对象的关键字为 new , 具体语法如下

let person = new Person(1, 'zhangsan');

● 对象属性的访问

console.log(person.name); //读 person.name = 'lisi'; //写
console.log(person.name);

● 对象⽅法的调⽤
对象创建后 ,便可通过对象调⽤类中声明的⽅法, 如下

let intro = person.introduce();
console.log(intro);

2.2.5.2.3. 静态成员
Typescript 中的类中可以包含静态成员( 静态属性和静态⽅法), 静态成员⾪属于类本身, ⽽不 属于某个对象实例 。静态成员通⽤⽤于定义⼀些常量, 或者⼯具⽅法。
● 声明静态成员
定义静态成员需要使⽤static关键字。

class Constants{
static count:number=1; 
}
class Utils{
static toLowerCase(str:string){
return str.toLowerCase();
}
}

console.log(Constants.count);
console.log(Utils.toLowerCase( 'Hello World'));

● 使⽤静态成员
静态成员⽆需通过对象实例访问, 直接通过类本身访问即可。

console.log(Constants.count);
console.log(Utils.toLowerCase( 'Hello World'));

2.2.5.3. 继承

继承是⾯向对象编程中的重要机制, 允许⼀个类( ⼦类或派⽣类) 继承另⼀个类( ⽗类或基类) 的属性和⽅法 。⼦类可以直接使⽤⽗类的特性, 并根据需要添加新的特性或覆盖现有的特性 。这 种机制赋予⾯向对象程序良好的扩展性。
下⾯通过⼀个例⼦演示继承的特性

class Student extends Person {
classNumber: string;
    constructor(id: number, name: string, classNumber: string) {
super(id, name);
this.classNumber = classNumber;
}
introduce(): string {
return super.introduce()+`, and I am a student`;
}
}
let student = new Student(1, 'xiaoming', '三年⼆班 '); console.log(student.introduce());

注意:

  • 类的继承需要使⽤关键字extends
  • ⼦类构造器中需使⽤super() 调⽤⽗类构造器对继承⾃⽗类的属性进⾏初始化。
  • 在⼦类中可以使⽤this 关键字访问继承⾃⽗类的属性和⽅法。
  • 在⼦类中可以使⽤super 关键字访问⽗类定义的⽅法。

2.2.5.4. 访问修饰符
访问修饰符(Access Modifiers) ⽤于控制类成员( 属性 、⽅法等) 的可访问性 。TypeScript提 供了三种访问修饰符, 分别是private 、protected和public。

class Person {
private id: number;
protected name: string;
public age: number;
constructor(id: number, name: string, age: number) {
this.id = id;
this.name = name; this.age = age;
}
}
class Student extends Person { }

说明:

  • private 修饰的属性或⽅法是私有的, 只能在声明它的类中的被访问。
  • protected 修饰的属性或⽅法是受保护的, 只能在声明它的类和其⼦类中被访问。
  • public 修饰的属性或⽅法是公有的, 可以在任何地⽅被访问到, 默认所有的属性和⽅法都是 public 的。

2.2.6. 接⼝ ( interface)
2.2.6.1. 概述
接⼝ ( interface) 是⾯向对象编程中的另⼀个重要概念 。接⼝通常会作为⼀种契约或规范让类 (class) 去遵守, 确保类实现某些特定的⾏为或功能。
2.2.6.2. 语法说明
● 接⼝定义
接⼝使⽤interface关键字定义, 通常情况下 ,接⼝中只会包含属性和⽅法的声明, ⽽不包含具体的实现细节, 具体的细节由其实现类完成。

interface Person { 
id: number;
name: string; age: number;

introduce(): void;
}

● 接⼝实现

接⼝的实现需要⽤到implements关键字, 实现类中, 需要包含接⼝属性的赋值逻辑, 以

及接⼝⽅法的实现逻辑。

class Student implements Person {
id: number;
name: string; 
age: number;

    constructor(id: number, name: string, age: number) {
this.id = id;
this.name = name; this.age = age;
}

    introduce(): void {
console.log( 'Hello,I am a student');
}
}

2.2.6.3. 多态
多态是⾯相对象编程中的⼀个重要概念, 它可以使同⼀类型的对象具有不同的⾏为 。下⾯我们通 过⼀个具体的案例来体会多态这⼀概念.
⾸先, 再创建⼀个Person接⼝的实现类Teacher, 如下

class Teacher implements Person {
id: number;
name: string; 
age: number;

constructor(id: number, name: string, age: number) {
this.id = id;
this.name = name; this.age = age;
}
introduce(): void {
console.log( 'Hello,I am a teacher');
}
}

然后分别创建⼀个Student对象和⼀个Teacher对象, 注意两个对象的类型均可以设置Person

let p1: Person = new Student(1, 'zhangsan', 17);
let p2: Person = new Teacher(2, 'lisi', 35);

最后分别调⽤introduce() ⽅法 ,你会发现, 同样是Person类型的两个对象, 调⽤同⼀个introduce() ⽅法时, 表现出了不同的⾏为, 这就是多态。

p1.introduce();//Hello,I am a student
p2.introduce();//Hello,I am a teacher

2.2.6.4. 接⼝的作⽤
在传统的⾯向对象编程的场景中 ,接⼝主要⽤于设计和组织代码 ,使代码更加容易扩展和维护。 下⾯举例说明。
假如现在需要实现⼀个订单⽀付系统 ,按照⾯向对象编程的习惯, ⾸先需要定义⼀个订单类 (Order), 如下

class Order {
totalAmount: number;

    constructor(totalAmount: number) {
this.totalAmount = totalAmount; }
    pay() {
console.log(`AliPay:${this.totalAmount}`);
}
}

很容易预想到, 这个系统将来可能需要⽀持其他的⽀付⽅式, 为了⽅便代码⽀持新的⽀付⽅式, 我们可以对代码进⾏如下改造。
⾸先定义⼀个⽀付策略的接⼝ ,接⼝中声明⼀个
⽅法, ⽤来规范实现类必须实现⽀付逻辑。

interface PaymentStrategy {
pay(amount: number): void;
}

然后在订单类中增加⼀个PaymentStrategy 的属性,并且在订单类中的pay ⽅法中调用PymentStrategy 的pay方法,如下

class Order {
totalAmount: number;
paymentStrategy: PaymentStrategy;

    constructor(totalAmount: number, paymentStrategy: PaymentStrategy) {
this.totalAmount = totalAmount;
this.paymentStrategy = paymentStrategy; 
}

    pay() {
this.paymentStrategy.pay(this.totalAmount);
}
}

这样改造完之后, 就可以很容易的在不改变现有代码的情况下, ⽀持新的⽀付⽅式了。⽐如现在需要⽀持AliPay, 那我们就可以创建AliPay这个类( class) 并实现(implement)PaymentStrategy这个接⼝ , 如下

class AliPay implements PaymentStrategy {
    pay(amount: number): void {
console.log(`AliPay:${amount}`);
}
}

这样⼀来, 之后创建的订单就可以使⽤AliPay这个⽀付⽅式了。

let order = new Order(1000,new AliPay());
order.pay();

2.2.6.5. TS 中的接⼝的特殊性
TypeScript 中的接⼝是⼀个⾮常灵活的概念,写过java的同学都知道(在java叫引用类型), 除了⽤作类的规范之外, 也常⽤于直接描述对象的 类型 ,例如, 现有⼀个变量的定义如下

let person: {name:string, age:number, gender:string} = {name: '张三 ', age:10, gender: '男 '};

可以看到变量的值为⼀个⼀般对象,变量的类型为{name:string, age:number, gender:string} ,此时就可以声明⼀个接⼝来描述该对象的类型,如下

interface Person { 
name: string;  
age: number;
gender: string;
}
let person: Person = {name: '张三 ', age:10, gender: '男 '};

2.2.7. 枚举
2.2.7.1. 概述
枚举( Enumeration) 是编程语⾔中常⻅的⼀种数据类型, 其主要功能是定义⼀组有限的选项, 例如, ⽅向( 上 、下 、左 、右) 或季节( 春 、夏 、秋 、冬) 等概念都可以使⽤枚举类型定义。
2.2.7.2. 语法说明
● 枚举定义
枚举的定义需使⽤ enum 关键字, 如下

enum Season { 
SPRING,
SUMMER, 
AUTUMN, 
WINTER
}

枚举的使⽤记住两个原则即可

  • 枚举值的访问:像访问对象属性⼀样访问枚举值 ,例如Season.SPRING
  • 枚举值的类型:枚举值的类型为enum的名称 ,例Season.SPRINGSeason.SUMMER等值的类型都是Season
let spring:Season = Season.SPRING;

● 使⽤场景
现需要编写⼀个函数 move , 其功能是根据输⼊的⽅向( 上 、下 、左 、右) 进⾏移动 ,此时 就可以先使⽤枚举定义好所有可能的输⼊选项, 如下

enum Direction {
UP,
BOTTOM,
LEFT,
RIGHT
}

move函数的实现如下

function move(direction: Direction) {
if(direction===Direction.UP){ 
console.log( '向上移动 ');
    }else if(direction===Direction.BOTTOM){
console.log( '向下移动 ');
    }else if(direction===Direction.LEFT){
console.log( '向左移动 ');       
}else{
console.log( '向右移动 '); }
}

move(Direction.UP);

2.2.7.3. 赋值
在TypeScript 中 ,枚举实际上是⼀个对象, ⽽每个枚举值都是该对象的⼀个属性, 并且每个属性 都有具体的值, 属性值只⽀持两种类型——数字或字符串。

默认情况下, 每个属性的值都是数字, 并且从开始递增 ,例如上述案例中的Direction枚举中,Direction.UP的值为 0 ,Direction.BOTTOM的值为 1 ,依次类推, 具体如下

console.log(Direction.UP) //0
console.log(Direction.BOTTOM) //1
console.log(Direction.LEFT) //2
console.log(Direction.RIGHT) //3

除了使⽤默认的数字作为属性的值, 我们还能⼿动为每个属性赋值 ,例如

enum Direction
UP = 1,
BOTTOM = 2
LEFT = 3,
RIGHT = 4
}

console.log(Direction.UP) //1
console.log(Direction.BOTTOM) //2
console.log(Direction.LEFT) //3
console.log(Direction.RIGHT) //4

再例如

enum Direction { 
UP = 'up',
BOTTOM = 'bottom'
LEFT = 'left',,
RIGHT = 'right'
}

console.log(Direction.UP) //up
console.log(Direction.BOTTOM) //bottom
console.log(Direction.LEFT) //left
console.log(Direction.RIGHT) //right

通过为枚举属性赋值, 可以赋予枚举属性—些更有意义的信息 ,例如以下枚举

enum Color {
Red = 0xFF0000,
Green = 0x00FF00,
Blue = 0x0000FF
}

enum FontSize {
Small = 12,
Medium = 16,
Large = 20,
ExtraLarge = 24
}

2.2.8. 模块化
2.2.8.1. 概述

模块化是指将复杂的程序拆解为多个独⽴的⽂件单元, 每个⽂件被称为⼀个模块 。在TypeScript 中, 默认情况下, 每个模块都拥有⾃⼰的作⽤域, 这意味着在⼀个模块中声明的任何 内容( 如变量 、函数 、类等) 在该模块外部是不可⻅的 。为了在⼀个模块中使⽤其他模块的内容, 必须对这些内容进⾏导⼊ 、导出。
在这里插入图片描述

2.2.8.2. 语法说明
●导出
导出须使⽤export关键字, 语法如下

export function hello() {
console.log( 'hello module A');
}
export const str = 'hello world' 
const num = 1;;

●导⼊
导⼊须使⽤import关键字, 语法如下

import { hello, str } from './moduleA';

hello();
console.log(str);

2.2.8.3. 避免命名冲突

若多个模块中具有命名相同的变量 、函数等内容, 将这些内容导⼊到同⼀模块下就会出现命名冲 突 。例如 ,在上述案例的基础上, ⼜增加了⼀个 moduleC, 内容如下

export function hello() {
console.log( 'hello module C');
}
export const str = 'module C';

moduleB 同时引⼊ moduleA 和 moduleC 的内容, 如下, 显然就会出命名冲突

import { hello, str } from "./moduleA";
import { hello, str } from "./moduleC";

hello() //?
console.log(str); //?

有多种⽅式可以⽤来解决命名冲突, 下⾯逐⼀介绍
● 导⼊重命名 语法如下

import { hello as helloFromA,str as strFromA } from "./moduleA";
import { hello as helloFromC,str as strFromC } from "./moduleC";

helloFromA();
console.log(strFromA);

helloFromC();
console.log(strFromC);

● 创建模块对象
上述导⼊重命名的⽅式能够很好的解决命名冲突的问题 ,但是当冲突内容较多时, 这种写法 会⽐较冗⻓ 。除了导⼊重命名外, 还可以将某个模块的内容统⼀导⼊到⼀个模块对象上, 这 样就能简洁有效的解决命名冲突的问题了, 具体语法如下

import * as A from "./moduleA";
import * as C from "./moduleC";

A.hello();
console.log(A.str);

C.hello();
console.log(C.str);

2.2.8.4. 默认导⼊导出
除了上述导⼊导出的语法之外, 还有⼀种语法, 叫做默认导⼊导出, 这种语法相对简洁⼀些。
● 默认导出
默认导出允许⼀个模块指定⼀个( 最多⼀个) 默认的导出项, 语法如下

export default function hello(){ 
  console.log( 'moduleA');
}

● 默认导⼊
由于每个模块最多有⼀个默认导出, 因此默认导⼊⽆需关注导⼊项的原始名称, 并且⽆需使{} 。

import helloFromA from"./moduleA";

由于默认导⼊时⽆需关注导⼊项的名称 ,所以默认导出⽀持匿名内容, ⽐如匿名函数, 语法 如下

export default function () { 
console.log( 'moduleB');
}

原文地址:https://blog.csdn.net/m0_46833693/article/details/140527325

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!