上一篇我们学习了Harmony开发入门,接下来我们简单学习一下ArkTS
一、ArkTS起源
在TS基础上扩展了申明式UI和状态管理等相应的能力
二、TS语法基础
1、类型
any | 任意类型(动态类型) let a: any = 5; a = "str" | |
number | let num: number = 5; num = 10.0 | 包装类:Number |
string | let str: string = 'name', str = "age", str = `age ${a}` | 包装类:String |
boolean | let b: boolean = false | 包装类:Boolean |
数组 | let: arr1: number[] = [1,2]; let arr2: Array<number> = [3,4]/new Array(3,4) | 包装类:Array |
元组 | 已知元素数量和类型,类型可以不相同,对应位置的类型需要相同 let x: [string, number]; x = ['str', 1] | |
enum | enum Color{Red,Green,Blue}; let c:Color=Color.Blue; | |
void | 用于标识方法返回值的类型,表示该方法没有返回值。 function hello():void{ alert("Hello"); } | |
null | 表示对象值缺失 let num: number = null | |
undefined | 用于初始化变量为一个未定义的值 let num: number console.log(num) ----> 输出undefined | |
联合类型 | let t: Type1|Type2|Type3... | |
类型别名 | type float = number; let time: float = 10; // time就是number类型 type userObj = {name:string} // 对象 type numOrObj = float | userOjb // 联合类型 |
2、变量申明
let/var[变量名]:[类型]=值;
let/var[变量名] = 值 // 类型推断
let/var[变量名]:[类型] // 不赋值,默认是undefined
let与var的区别:
1、let 不能重复声明,但var可以; // var a = 1; var a = 2;
2、let会产生块级作用域,且只在自己的作用域内生效,但var不受限制
{ let a = 1; var b = 2;} console.log(a); //报错 console.log(b);//2
3、let不存在变量提升
console.log(a); //undefined var a = 1; console.log(b); //报错 let b = 1;
3、条件语句if
if(boolean_expression){
# 在布尔表达式 boolean_expression 为 true 执行
}
当boolean_expression 结果不是布尔值时会自动转换为boolean
如:if(0)、 if("") 、if('') 、if(null)、 if(undefined) 均为等价if(false)
4、函数
function function_name(param1 [:datatype], ...) [:return_type] { // 语句 return value; };
function function_name(param1? :datatype){} // 可选参数
function function_name(param1 :datatype = default_value){} // 默认参数
function function_name(...param1 :datatype[]){} // 剩余参数,不确定参数个数,数组接受
匿名函数:var res = function( [arguments] ) { ... }
构造函数申明:var res = new Function ([arg1[, arg2[, ...argN]],] functionBody) // 例如 var myFunction = new Function("a", "b", "return a * b");
Lambda函数(箭头函数) ([arguments] ) => statement;
注意:普通函数中的this指向调用该函数的对象,但是箭头函数中的this指向定义它时,它所处的对象
5、接口
interface interface_name {
[变量]:[类型]
...
}
实现: var res: interface_name = {...}
继承:interface interface_name extends inteface_name1, inteface_name2 { }
6、类
class class_name {
static [变量]:[类型]; // 静态变量
static static_fun_name()[:return_type] {} // 静态变量
[变量]:[类型]; // 字段
constructor([arguments]) {} // 构造函数
function_name()[:return_type] { } // 方法
}
实例化:var object_name = new class_name([ arguments ])
继承:class child_class_name extends parent_class_name // 单继承,支持多重继承(A 继承 B,B 继承 C)
实现接口:class child_class_name implements interface_name1, interface_name2, ...
instanceof运算符: 用于判断对象是否是指定的类型, // person_obj instanceof Person 返回true
7、对象
类实例化:var object_name = new class_name([ arguments ])
对象字面量var object_name = { [key]: [value] // 标量、函数、数组、对象等 }
object_name.key = value // 赋值更新
8、泛型
泛型函数: function combine<T>(arg: T):T{
return arg;
}
泛型接口:interface interface_name<T, U> { first: T; second: U; }
泛型类:class class_name<T> {
private value: T;
constructor(value: T) { this.value = value; }
}
泛型默认值:function defaultValue<T=string>(arg: T):T {return arg;}
9、命名空间
解决重名问题、聚合相关联的类和接口
namespace SomeNameSpaceName {
export interface ISomeInterfaceName { }
export class SomeClassName { }
}
使用:SomeNameSpaceName.SomeClassName;
10、模块
模块是一个独立的文件或代码块,它封装了一组相关的数据和函数,并提供了对外的接口,暴露给外部的接口,必须使用exprot命令声明;如果一个文件要使用模块的接口,需要用import命令导入
导出 | 导入 | |
单独导出 | export let/var/const xxx1 = v1 export function fn() {} | import { xxx1, fn } from 'xxxfile' |
正常导出 | export {xxx1, xxx2, ... } | import { xxx1, xxx2, ... } from 'xxxfile' import * as xx from 'xxxfile' // xx.xxx1 |
默认导出 (每个模块有且只有一个) | export default xxxn | import xxxn from 'xxxfile' |
重命名导出/导入 | export {xxx1 as 1xxx, xxx2, ... } | import { 1xxx, xxx2 as 2xxx, ... } from 'xxxfile' |
复合导入 | export {xxx1, xxx2, ... } export default xxxn | import xxxn, { xxx1, xxx2, ... } from 'xxxfile' |
导入导出:export命令和import命令结合在一起写成一行,变量实质没有被导入当前模块,相当于对外转发接口,当前模块无法直接使用其导入变量
默认导入导出 | export { default } from "xxxfile" |
整体导入导出 | export * from "xxxfile" |
按需导入导出 | export { age, name, sex } from "xxxfile" |
改名导入导出 | export { name as newName } from "xxxfile" |
具名改默认导入导出 | export { name as default } from "xxxfile" |
默认改具名导入导出 | export { default as name } from "xxxfile" |
11、声明文件
直接引用的三方 JavaScript 库,是无法使用TypeScript 诸如类型检查等特性功能,将库里的函数方法体去掉只保留导出类型声明,产生一个描述 JavaScript 库和模块信息的声明文件,声明文件以.d.ts为后缀
声明文件语法格式:declare module Module_Name{ }
三、常见的TypeScript语法规则到ArkTS的适配
1、ArkTS不支持var,请使用let声明变量
2、ArkTS不支持any和unknown类型。显式指定具体类型
3、禁止在运行时变更对象布局
class Point {
public x: number = 0
public y: number = 0
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
- 向对象中添加新的属性或方法。
let p2 = new Point(2.0, 2.0);
p2.z = 'Label';
- 从对象中删除已有的属性或方法。
let p1 = new Point(1.0, 1.0);
delete p1.x;
- 将任意类型的值赋值给对象属性。
let p4 = new Point(4.0, 4.0);
p4.x = 'Hello!';
4、对象的属性名不能为数字或字符串
var x = { 'name': 'x', 2: '3' };
5、不支持使用#符号开头声明的私有字段。改用private关键字
class C {
// #foo: number = 42
private foo: number = 42
}
6、类型、命名空间的命名必须唯一
let X: string
type X = number[] // 类型的别名与变量同名
7、ArkTS不允许类中有多个静态代码块,如果存在多个静态代码块语句,请合并到一个静态块中
class C {
static s: string
static {
C.s = 'aa'
}
}
8、使用点操作符访问字段,例如(obj.field),不支持索引访问(obj[field])
9、需要显式标注对象字面量的类型
错误:let o1 = {n: 42, s: 'foo'}; // 需要显示申明n和s的类型
正确-先声明类型:class C1 {
n: number = 0
s: string = ''
}
let o1: C1 = {n: 42, s: 'foo'};
10、ArkTS不支持使用对象字面量声明类型,可以使用类或者接口声明类型。
错误:let o: {x: number} = { x: 2 }
正确-先声明类型:class O { x: number = 0}
let o: O = {x: 2};
11、ArkTS不支持函数表达式,使用箭头函数。
错误:let f = function (s: string) { console.log(s)}
正确:let f = (s: string) => { console.log(s)}
12、在ArkTS中,as关键字是类型转换的唯一语法
let c3 = square obj as Shape;
13、一元运算符+、-和~仅适用于数值类型
14、不支持delete运算符
15、ArkTS不支持解构赋值。可使用其他替代方法,例如,使用临时变量。
let one, two;
[one, two] = [1, 2];
16、ArkTS不支持解构变量声明
class Point {
x: number = 0.0
y: number = 0.0
}
错误:let {x, y} = new Point();
正确:let x = zp.x; let y = zp.y;
17、不支持在catch语句标注类型
try {
// ...
} catch (a) { // a不标注类型
// 处理异常
}
18、限制省略函数返回类型标注(尽量标注函数返回值类型)
19、ArkTS不支持在函数内声明函数,可以用lambda函数
20、不支持在函数和类的静态方法中使用this
21、接口不能继承具有相同方法的两个接口
22、不支持import default as ...
不支持:import { default as d } from 'mod'
import d from 'mod'
23、不允许通过注释关闭类型检查,不支持使用@ts-ignore和@ts-nocheck。