README.md 13.7 KB
Newer Older
D
DCloud_LXH 已提交
1 2 3 4 5 6 7
## UTS 介绍

**uts 是什么**

uts,全称 uni type script,是一门跨平台的、高性能的、强类型的现代编程语言。

它可以被编译为不同平台的编程语言,如:
W
wanganxp 已提交
8
- web平台/小程序,编译为JavaScript
D
DCloud_LXH 已提交
9 10
- Android平台,编译为Kotlin
- iOS平台,编译Swift
W
wanganxp 已提交
11
- 鸿蒙OS平台,编译为ArkTS(HBuilderX 4.22+)
D
DCloud_LXH 已提交
12 13 14 15 16

uts 采用了与 ts 基本一致的语法规范,支持绝大部分 ES6 API。

但为了跨端,uts进行了一些约束和特定平台的增补。

W
wanganxp 已提交
17 18 19
过去在js引擎下运行支持的语法,大部分在uts的处理下也可以平滑的在kotlin和swift中使用。但有一些无法抹平,需要使用条件编译。

和uni-app的条件编译类似,uts也支持条件编译。写在条件编译里的,可以调用平台特有的扩展语法。
D
DCloud_LXH 已提交
20 21 22 23 24

### 用途和关系

uts是一门语言。也仅是一门语言,不包含ui框架。

W
wanganxp 已提交
25
uvue是DCloud提供的跨平台的、基于uts的、使用vue方式的ui框架。
D
DCloud_LXH 已提交
26

W
wanganxp 已提交
27
uts相当于js,uvue相当于html和css。它们类似于v8和webkit的关系,或者类似于dart和flutter的关系。
D
DCloud_LXH 已提交
28 29 30 31 32 33

uts这门语言,有2个用途:

1. 开发uni-app 和 uni-app x 的原生扩展插件:因为uts可以调用所有原生能力。
2. uts和uvue一起组合,开发原生级的项目,也就是 uni-app x 项目

W
wanganxp 已提交
34
从HBuilderX 3.9起,支持uni-app x项目。详见[uni-app x](../readme.md)
D
DCloud_LXH 已提交
35 36 37 38

也就是说,uts可以在uni-app中使用,也可以在uni-app x中使用。

- 在uni-app中,主编程语言是js。uts可以开发原生插件,包括API插件和组件插件。
W
wanganxp 已提交
39
- 在uni-app x中,主编程语言是uts。不管是应用逻辑还是扩展插件,均使用uts编程。仅在Web平台和iOS的js驱动模式下可以使用js。
D
DCloud_LXH 已提交
40 41 42 43 44 45 46

如果插件作者,开发了uts插件,也可以同时在uni-app和uni-app x中使用。比如这2个uts插件:
- 电量:[https://ext.dcloud.net.cn/plugin?id=9295](https://ext.dcloud.net.cn/plugin?id=9295)
- lottie组件:[https://ext.dcloud.net.cn/plugin?id=10674](https://ext.dcloud.net.cn/plugin?id=10674)

这2个uts插件,一个是api插件,一个是组件插件,它们同时兼容uni-app和uni-app x。

W
wanganxp 已提交
47
可以通过表格更清晰的了解uts语言在uni-app和uni-app x下的编译关系。
D
DCloud_LXH 已提交
48

W
wanganxp 已提交
49
<table>
D
DCloud_LXH 已提交
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
  <thead>
    <tr>
      <th></th>
      <th colspan="2">uni-app</th>
      <th colspan="2">uni-app x</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td></td>
      <td>普通页面和脚本</td>
      <td>uts插件</td>
      <td>普通页面和脚本</td>
      <td>uts插件</td>
    </tr>
    <tr>
      <td>Web和小程序</td>
      <td>JS</td>
      <td>JS</td>
      <td>JS</td>
      <td>JS</td>
    </tr>
    <tr>
      <td>Android</td>
      <td>JS</td>
      <td>Kotlin</td>
      <td>Kotlin</td>
      <td>Kotlin</td>
    </tr>
    <tr>
      <td>iOS</td>
      <td>JS</td>
      <td>Swift</td>
      <td>JS(JS驱动时)</td>
      <td>Swift</td>
    </tr>
    <tr>
      <td>HarmonyNext</td>
      <td>JS</td>
      <td>ArkTS</td>
      <td>x</td>
      <td>x</td>
    </tr>
  </tbody>
W
wanganxp 已提交
94 95 96 97 98 99 100 101 102 103 104 105 106
</table>

这里的概念解释是:
- uts插件,指`uni_modules`目录下utssdk目录下的代码
- 除uts插件外,其他都属于 `普通页面和脚本`,包含vue、nvue、uvue等页面及单独的uts文件
- 在uni-app x的iOS平台,目前`普通页面和脚本`是编译为js的,而不是Swift。
	这个策略主要是为了解决windows电脑开发uni-app x的问题。它并不影响性能,uni-app x的iOS通过优化解决了js性能问题。同时未来也会提供js驱动和Swift驱动双选

除了查阅表格,也可以简单的记3个原则:
1. 所有的uts插件,都会编译为原生语言
2. web和小程序上,原生语言就是js
3. App上,目前仅uni-app x的Android平台会编译为原生语言,其他都编译为js

D
DCloud_LXH 已提交
107
本文是 uts 的基本语法介绍。
W
wanganxp 已提交
108 109
- 想了解 uni-app 下如何开发 uts插件,另见文档[https://doc.dcloud.net.cn/uni-app-x/plugin/uts-plugin.html](../plugin/uts-plugin.md)
- 想了解 uni-app x,另见文档[https://doc.dcloud.net.cn/uni-app-x/](../readme.md)
D
DCloud_LXH 已提交
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165


## 类型声明

js是无类型的,TypeScript 的 type 就是类型的意思,给js加上了类型。它的类型定义方式是在变量名后面通过加冒号和类型来进行定义。

uts 中声明变量可以用 let 或 const,详见下。

### 变量定义(let)

声明一个可重新赋值的变量。语法 `let [变量名] : [类型] = 值;`

> 相当于 TypeScript 中的 let、kotlin 中的 var、swift 中的 var。

```ts
let str :string = "hello"; // 声明一个字符串变量
str = "hello world"; // 重新赋值
```

类型除了 string 之外,更多类型见[数据类型](data-type.md)

### 常量定义(const)

声明一个只读常量,只能为其赋值一次。语法 `const [变量名] : [类型] = 值;`

> 相当于 TypeScript 中的 const、kotlin 中的 val、swift 中的 let。

```ts
const str :string = "hello"; // 声明一个字符串常量
str = "hello world"; // 报错,不允许重新赋值
```

注意事项:

- 当前 uts 并未限制使用 `var` 来声明变量,但除非你知道你在做什么,否则不要轻易使用它,因为有不同平台差异:
	* 编译至 JavaScript 平台时,等同于 JavaScript 平台的 var 。存在变量提升现象,具体参考 [var和let的区别](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Grammar_and_types#%E5%A3%B0%E6%98%8E)
	* 编译至 Kotlin 平台时,等同于 Kotlin 平台的 var(允许重新赋值)
- swift 中 let 是定义常量,而 uts 和 ts 中,let 是定义变量。注意勿混淆。
- 类型定义的冒号,左右可以有一个空格,也可以没有空格。`let str:string``let str : string``let str :string``let str: string` 都是合法的。

### 变量命名规则

在 uts 中,使用变量名需要遵守一定的规则。

-   变量名称可以包含数字和字母。
-   除了下划线 \_ 外,不能包含其他特殊字符,包括空格。
-   变量名不能以数字开头。

### 方法参数及返回值类型定义

方法的参数、返回值,也通过冒号定义。

如下示例,方法test,有一个参数score,是number类型,方法返回值类型为boolean类型。

```ts
function test(score: number): boolean {
D
DCloud_LXH 已提交
166
	return (score>=60)
D
DCloud_LXH 已提交
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
}
test(61) // 返回true
```

方法无返回值时,使用`:void`

```ts
function add(x :string, y :string) :void {
    let z :string = x + " " + y
	console.log(z)
	// 不需要return
}
```

函数另有详细文档,详见:[函数](function.md)

### vue data类型定义

vue 选项式开发时,冒号被用于赋值,无法通过let、const和冒号来定义data数据的类型。

此时可以使用[字面量](literal.md)赋值自动推导;也可以使用 `as` 关键字来显式声明类型。

```html
<script lang="uts">
	export default {
		data() {
			const date = new Date()
			return {
				s1 : "abc", // 根据字面量推导为string
				n1 : 0 as number, // 这里其实可以根据字面量自动推导,as number写不写都行
				n2, // 不合法,必须指定类型
				n3 as number, // 不合法,uts不支持undefined,必须通过冒号初始化赋值,哪怕赋值为null,见下
				n4 : null as number | null // 合法。定义为可为null的数字,初始值是null,但在使用n4前必须为其赋值数字。(number | null)是一个或的写法,前后顺序没有关系。uts的联合类型只支持 |null 。
				year: date.getFullYear() as number, // 在data里,目前无法通过变量类型推导data项的类型,需使用 as 显式声明类型为number
			}
		}
	}
</script>
```

W
wanganxp 已提交
207
上述示例仅在 uni-app x 的uvue页面生效。老版uni-app,即js引擎版,不支持在页面里写uts代码,只支持在uts插件里写uts代码。
D
DCloud_LXH 已提交
208 209 210

### 类型自动推导

fxy060608's avatar
fxy060608 已提交
211 212
#### 字面量推导

D
DCloud_LXH 已提交
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
现代语言(ts、kotlin、swift),都具备自动识别[字面量](literal.md),进行类型推导的功能。

即:如果开发者声明变量的同时,进行了初始化赋值。那么编译器可以根据赋值的[字面量](literal.md),自动推导出变量类型,不必开发者显式声明。

在定义变量时如果直接赋值[字面量](literal.md),而不使用冒号声明类型,也可以合法运行。

如下2种写法都是合法的,两个变量都是string类型:

```ts
// 以下每组写法是等价的
let s1 = "hello" // 根据字面量 "hello",自动推导为string类型
let s2 : string = "hello"
let s3 : string
s3 = "hello"

let b1 = true // 根据字面量 true,自动推导为boolean类型
let b2 : boolean = true

// 以上为字符串和布尔的字面量类型自动推导,数字和数组也支持字面量类型推导,但规则比较复杂,需另见文档

```

在HBuilderX 3.9以前, uts 未对字面量赋值类型推导做统一处理,编译到 kotlin 和 swift 时,由这2个语言自行做类型推导。

但 kotlin 和 swift 的自动推导,在某些地方有细节差异。尤其是[数字字面量](data-type.md#autotypefornumber)[数组字面量](data-type.md#autotypeforarray)。在这2个场景下,建议显式声明类型,不使用自动推导。

```ts
// 显式声明数字和数组类型
let n1:number = 1
let n2 = 1 as number
let n3:Int = 1
let a1:Array<string> = ["uni-app", "uniCloud", "HBuilder"]
let a1:Array<number> = [1,2,3,4]
```

HBuilderX 3.9+, uts 统一了字面量自动类型推导。

建议插件作者,除了boolean和string外,其他包括数字和数组在内的类型,尽量不使用字面量自动类型推导,而是显式声明类型。避免 uts 统一自动类型推导时引发的向下兼容问题。

fxy060608's avatar
fxy060608 已提交
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
在 HBuilderX 4.31 以前,对象字面量{}的推导,默认是UTSJSONObject,无论是变量声明,还是传参(除了uni、uniCloud等官方API)等场景,只要没有手动 as,均会推导为 UTSJSONObject 类型。

HBuilderX 4.31+,uts 增强了对象字面量的类型推导,会根据当前上下文,来推断是否是某个type定义的类型(如果type是定义在非当前文件,需要该type对外导出)

```ts
type User = {
	name: string
	age: number
}
function printUser(user: User){
	console.log(user) 
}
printUser({ name: 'zhangsan', age: 12 }) // 从 HBuilderX 4.31+ 起,无需手动 as User

function createUser(name : string, age : number) : User {
    return { name, age } // 从 HBuilderX 4.31+ 起,无需手动 as User
}
printUser(createUser({ name: 'zhangsan', age: 12 }))

```

#### 函数返回值类型推导

在 HBuilderX 4.31 以前,所有的函数如果有 return 语句,均需要主动声明返回值类型。

HBuilderX 4.31+,uts 增强了函数返回值类型的推导,会根据当前上下文,来自动推断补充当前函数的返回值类型

```ts
function test1() { // 自动推导返回值类型为 string
    return "test1"
}
function test2(arg : boolean) { // 自动推导返回值类型为 number | null
    if (arg) {
        return 1
    }
    return null
}
function test3(arg : boolean): any { // 暂不支持多个不同类型的返回值推导,需要主动声明为 any
    if (arg) {
        return 1
    }
    return "test2"
}
```

注意:目前函数返回值仅推导相同类型,或可为空类型,不支持多个类型的推导,比如 test3 函数,可能返回 string | number,此时需要主动声明为 any 类型。

#### 函数参数推导

在 HBuilderX 4.31 以前,函数赋值或作为参数时,当前函数的参数数量必须和目标函数保持一致。

HBuilderX 4.31+,uts 增强了函数参数数量的自动推导

```ts
type TestFn = (a1: string, a2: string) => void
function callTestFn(test: TestFn) {
  test('1', '2')
}
// HBuilderX 4.31 以前仅支持传递两个参数的函数
callTestFn((arg1, arg2) => {})
// HBuilderX 4.31+支持以下调用方式
callTestFn(() => {})
callTestFn((arg1) => {})
```

D
DCloud_LXH 已提交
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
### 类型判断

判断类型,有好几种方案:[typeof](operator.md#typeof)[instanceof](operator.md#instanceof)[isArray](buildin-object-api/array.md#isarray)

使用 typeof 可以判断布尔值、数字、字符串、函数。
```ts
typeof(true) == "boolean"
typeof("abc") == "string"

let n1 : number = 1
typeof(n1) == "number"
```

但如果使用 typeof 验证数组,会发现返回的类型值是"object",这与浏览器是相同的逻辑。

如果想验证数组类型,需要使用如下方法:
```ts
const a1 = ["uni-app", "uniCloud", "HBuilder"]
console.log(Array.isArray(a1)) // 返回true
console.log(a1 instanceof Array) // 返回true
```

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
339
instanceof,除了验证数组,还可以验证类型,但注意它返回的不是具体类型,而是根据入参的一个boolean值。
D
DCloud_LXH 已提交
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386

```ts
let myDate = new Date();
console.log(myDate instanceof Date) // 返回true

uni.request({
	url: 'https://abc',
	success: (data) => {
		if (data.statusCode == 200) {
			const result = data.data as UTSJSONObject
			console.log(result instanceof UTSJSONObject) //返回true
		}
	},
	fail: () => {
		console.log('fail');
	}
});
```

详见:[typeof](operator.md#typeof)[instanceof](operator.md#instanceof)

### 安全调用

js没有类型检查。而uts和ts都有严格的类型检查。

对于可为null的类型,调用时需要加问号,否则编译器会报错。

```ts
const s: string | null = null // s为一个可为null的字符串
console.log(s?.length) //除非前面已经给s赋值,否则调用s的方法和属性必须加?
```

安全调用有很多细节,详见[null类型](data-type.md#null类型)

### 代码语句的分割

uts的多个代码语句,以回车或分号分割。

多行时行尾的分号可以省略。如果写在一行,应以分号分割。

如下的代码都是合法的:

```ts
let a:number = 1 //行尾可以不加分号
let b:boolean = false; //行尾可以加分号
let c:number = 3 ; let d:number = 4 // 同行多语句需要用分号分割
```