主页 > 互联网  > 

Arkts和Typescript语法上差别

Arkts和Typescript语法上差别

目录

ArkTs

基础语法介绍

语法差别

具体案例

不支持通过注释类型检查。

对象字面量须标注类型

显示初始化类的属性

不支持‌Structural Typing‌

不支持Symbol()API

禁止使用var声明变量

禁止使用any和unknow约束类型

类型、命名空间的命名必须唯一

允许json中的科学技术法数字格式

应用环境限制

this使用

 具体语法限制

 no-func-apply-call

no-any-unknown

no-call-signature

no-ctor-signatures-type

no-ctor-signatures-iface

no-ctor-signatures-funcs

no-classes-as-obj

no-indexed-signatures

no-mapped-types

 no-in

no-for-in

no-typing-with-this

no-untyped-obj-literals

 no-obj-literals-as-types

no-method-reassignment 

no-polymorphic-unops

no-type-query

no-destruct-assignment

no-spread

no-types-in-catch

limited-throw

limited-stdlib

no-tsdeps 

no-func-props


ArkTs

鸿蒙开发使用的语言,Typescript语言的超集。跟ts一样是静类型态语言,所有数据的类型都必须在编译时确定。文件以ets后缀结尾。在ts的基础上加入了结构体struct的定义以及一些定义好了的UI组件和装饰器。基本语法和ts一致。

基础语法介绍

文档中心

语法差别

文档中心

总体语法和Typescript的基本一致,主要区别在于

1.添加了一些限制去明确类型,例如不支持泛型、常量使用需要标注类型以及this使用等限制。

2.限制了类型、接口的灵活写法,比如接口不能直接定义函数、不能通过[]定义对象属性等,推荐大家使用Typescript中定义好的一些类型函数,例如Record<>等。

3.简化了一些类型定义流程,例如构造函数类型定义去除了new操作符等。

4.限制了操作符等一些灵活的写法,比如禁止使用in、for in、apply、call等操作符和函数。

具体案例

文档中心

不支持通过注释类型检查。

ArkTS不支持通过注释的方式绕过严格类型检查。首先将注释(// @ts-nocheck或者// @ts-ignore)删去,再根据报错信息修改其他代码。

对象字面量须标注类型

原因:如果编译器不知道变量point的确切类型,由于对象布局不能确定,编译器无法深度地优化这段代码,造成性能瓶颈。没有类型也会造成属性的类型缺少限制,例如point.x的类型在此时为number,它也可以被赋值成其他类型,造成额外的运行时检查和开销。

注意只有对象字面量需要标注类型,基础变量是不需要的,会隐式的进行类型推断。

let point = { x: 0,y: 0} //编译时报错,需要标注类型 Interface Point { x: number, y: number } let point:Point = { x: 0,y: 0} // 不会报错 let hi = 'hello, world'; //不会报错 显示初始化类的属性

类的属性初始化赋值或者在构造函数里赋值。相当于设置了tsconfig.json中的strictPropertyInitialization为true。

class Person { name: string; // 这里arkts类型检测会报错,需要显性进行赋值。 } new Person()//name为undefined // 正确 class Person1 { name: string=''; } interface I { name:string } class A {} class Test { a: number; b: string; c: boolean; d: I = { name:'abc' }; e: A | null = null; constructor(a:number, b:string, c:boolean) { this.a = a; this.b = b; this.c = c; } } 不支持‌Structural Typing‌

Structural Typing是一种类型系统,它允许根据对象的结构(属性和方法)而不是其类型来处理对象。

注意:规定类型为C,C的子集是可以传入的,C的父集不行。

class C{ s:string = '' } class D{ n:number=0 s:string = '' } function foo(c:C){ console.log(c.s) } foo(new D()) // 在arkts中编译会报错,不允许传入其他类型的变量,即使这个类型的属性满足要求。

原因:foo虽然声明参数类型是C,但也可以传递类型D的变量,这种灵活性可能不符合开发者的意图,容易带来程序行为的正确性问题。另外,由于类型D和类型C布局不同,那么foo中对c.s这个属性访问就不能被优化成根据固定偏移量访问的方式,从而给运行时性能造成瓶颈。

不支持Symbol()API

TypeScript中的Symbol()API用于在运行时生成唯一的属性名称。由于该API的常见使用场景在静态类型语言中没有意义,因此,ArkTS不支持Symbol()API。在ArkTS中,对象布局在编译时就确定了,且不能在运行时被更改。

ArkTS只支持Symbol.iterator。

禁止使用var声明变量 禁止使用any和unknow约束类型 类型、命名空间的命名必须唯一 // 错误 let X: string type X = number[] // 类型的别名与变量同名,报错 允许json中的科学技术法数字格式

标准TS/JS中,JSON的数字格式,小数点后必须跟着数字,如2.e3这类科学计数法不被允许,报出SyntaxError。在方舟运行时中,允许使用这类科学计数法。

应用环境限制 强制使用严格模式(use strict)禁止使用eval()禁止使用with() {}禁止以字符串为代码创建函数 this使用 关键字this只能在类的实例方法中使用(在函数和类的静态方法中无法使用)。 class A { n: number = 0; f1(arg1: this) {} // 编译时错误,不支持this类型 static f2(arg1: number) { this.n = arg1; // 编译时错误,不支持在类的静态方法中使用this,可以直接改为A.n = arg1 } } function foo(arg1: number) { this.n = i; // 编译时错误,不支持在函数中使用this }  具体语法限制  no-func-apply-call

由于this的原因,apply和call方法在arkts中禁止使用。可以通过类的继承去实现。

no-any-unknown

any, unknown不允许在类型中使用。需要改写为具体的类型。可以多使用Record进行简要类型定义。

function foo(str: string) { let tmpStr = JSON.parse(str);//报错,对象字面量需要标注类型。 let tmpStr: Record<string, Object> = JSON.parse(str);//正确 if (tmpStr.add != undefined) { this.v = tmpStr.v as number; this.s = tmpStr.s as string; } } //错误 export default { onCreate() { // ... }, onDestroy() { // ... } } //正确 class Test { onCreate() { // ... } onDestroy() { // ... } } export default new Test() no-call-signature

不使用Interface定义单独的函数类型,使用type定义单独的函数类型。

//错误 interface I { (value: string): void; } //正确 type I = (value: string) => void no-ctor-signatures-type no-ctor-signatures-iface no-ctor-signatures-funcs no-classes-as-obj

在定义函数返回某个类的对象时,使用type或Interface定义都禁止使用new 关键字。

class Controller { value: string = '' constructor(value: string) { this.value = value; } } //错误 type ControllerConstructor = { new (value: string): Controller; } //错误 type ControllerConstructor = new () => Controller // 错误 interface ControllerConstructor { new (value: string): Controller; } //正确 type ControllerConstructor = () => Controller; let a :ControllerConstructor = ()=>new Controller('1') no-indexed-signatures

不允许在[]中使用k:的形式定义属性名类型。

// 错误 interface a { [k:string] :string } // 正确 type b = Record<string,string> no-mapped-types

在type类型定义的对象属性映射[]中不允许使用in。

class C { a: number = 0 b: number = 0 c: number = 0 } type OptionsFlags = { [P in keyof C]: string // 报错 } type OptionsFlags = Record<keyof C, string> // 正确  no-in

不允许使用in操作符(用于判断对象是否存在某属性)。

function test(str: string, obj: Record<string, Object>) { return str in obj; // 报错 } no-for-in

不允许使用for in操作符。

let p: Record<string,string> = { name: 'tom', age: '18' }; for (let t in p) { // 报错 console.log(p[t]); // log: "tom", "18" } no-typing-with-this

在类型约束中禁止使用this,使用类名替代。

//错误 class C { getInstance(): this { return this; } } // 正确 class C { getInstance(): C { return this; } } no-untyped-obj-literals

类的类型约束中,如果该类显式定义了constructor,则只能传该类和该类子类对象。如果未显式定义constructor,则只需要满足对象中刚好只有该类的属性,且属性值的类型和对象中值的类型对应即可。

class C { value: number = 1 constructor(n: number) { if (n < 0) { throw new Error('Negative'); } this.value = n; } } let s: C = new C(-2); let t: C = { value: -2 }; //报错 // 正确 class D { value: number = 1 } let a: D = new D(); let b: D = { value: -2 };  no-obj-literals-as-types

不允许使用type定义对象字面量。

type Person = { name: string, age: number }// 报错 // 正确 interface Person { name: string, age: number } no-method-reassignment 

不允许对类的方法进行重新赋值。

注意:

1.可以定义为类的属性值进行重新赋值。

2.赋值的函数会对其返回值类型进行检查,赋值函数的参数个数可以小于等于原类中属性值函数的参数个数且类型需要对应。

// 错误,对类的方法进行重新赋值 class C { add(left: number, right: number): number { return left + right; } } function sub(left: number, right: number): number { return left - right; } let c1 = new C(); c1.add = sub;//报错 // 正确,对类的属性值进行的重新赋值 class C { add: (left: number, right: number) => number = (left: number, right: number) => { return left + right; } } function sub(right: number): number { return - right; } let c1 = new C(); c1.add = sub; no-polymorphic-unops

一元运算符只允许用于数字,不允许用于字符串。

// 错误 let a = +'5'; let b = -'5'; let c = ~'5'; let d = +'string'; // 正确 let a = Number.parseInt('5'); no-type-query

typeof变量不允许出现在类型约束中。

// module1.ets class C { value: number = 0 } export let c = new C() // module2.ets import { c } from './module1' let t: typeof c = { value: 123 }; // 报错

可以直接导出类名C,用类名C直接作为约束。

no-destruct-assignment

不允许使用解构表达式。

let map = new Map<string, string>([['a', 'a'], ['b', 'b']]); for (let [key, value] of map) { // 解构报错 console.log(key); console.log(value); } let b :Record<string, number> = { 'a':1} let {a:number} = b // 解构报错 no-spread

不允许使用...解构。

let b :Record<string,string> = {'a':'3'} let c:Record<string,string> ={ ...b } no-types-in-catch

在try-catch语句中不允许约束类型。

import { BusinessError } from '@kit.BasicServicesKit' // 错误 try { // ... } catch (e: BusinessError) { // 报错 console.error(e.message, e.code); } // 正确 try { // ... } catch (error) { let e: BusinessError = error as BusinessError; console.error(e.message, e.code); } limited-throw

限制throw的类型必须为Error类型。

import { BusinessError } from '@kit.BasicServicesKit' function ThrowError(error: BusinessError) { throw error; // 报错 throw error as Error; // 正确 } limited-stdlib

不允许是用es2019的Object.fromEntries方法(将数组中的键值对转换为对象中key-value)。

let entries = new Map([ ['foo', 123], ['bar', 456] ]); let obj = Object.fromEntries(entries); // 报错 no-tsdeps 

不允许.ts、.js文件import.ets文件源码。

no-func-props

不允许给函数变量添加属性。可通过类实现。

function foo(value: number): void { console.log(value.toString()); } foo.add = (left: number, right: number) => { // 报错 return left + right; }

建议改法

方式1.将.ts文件的后缀修改成ets,按照ArkTS语法规则适配代码。

方式2.将.ets文件中被.ts文件依赖的代码单独抽取到.ts文件中。

标签:

Arkts和Typescript语法上差别由讯客互联互联网栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“Arkts和Typescript语法上差别