# 类型兼容性

由于 UTS 语言最终会转换为 kotlin、swift 等语言，UTS 语言中的接口也更接近 kotlin 中的接口或 swift 中的协议，在类型兼容性判断时与 TS 语言的结构类型系统有着明显的区别：

- TS：如果两个类型的内部结构相似（具有相同的属性和方法），那么它们被认为是兼容的，即使它们的名称不同。
- UTS：依赖于类型的显式声明，必需是同一个类型或者存在显式的继承/实现关系。

```ts
interface IPerson {
    name: string
    printName(): void
}

class Person implements IPerson {
    constructor(public name: string) {}
    printName(): void {
        console.log(this.name)
    }
}

class Person1 {
    constructor(public name: string) {}
    printName(): void {
        console.log(this.name)
    }
}

type PersonObject = {
    name: string
    printName(): void
}

class Person2 extends Person {}

const person: IPerson = new Person('Tom') // 正确，Person 实现自 IPerson

const person1: Person = new Person1('Tom') // 错误，Person 与 Person1 无关只是结构相同

const person2: Person = new Person2('Tom') // 正确，Person2 继承自 Person

const person3: IPerson = {
    name: 'Tom',
    printName: function () {
        console.log(this.name)
    }
} as PersonObject // 错误，PersonObject 类型与 IPerson 无关只是结构相同
```

### 运行时类型保留

不同于ts编译后完全抹除类型，uts在运行时保留了部分类型信息。通常是定义type后，创建此type对应的实例时，会保留此实例的类型信息。

例如：

```ts
type Obj = {
  a: number
}
const obj = {
  a: 1
} as Obj 
// 此时obj的类型为Obj，运行时可以使用 obj instanceof Obj
console.log(obj instanceof Obj) // true

const result = JSON.parse<Obj>(`{"a": 1}`) // 此时返回的对象类型为Obj
console.log(result instanceof Obj) // true
```

**注意**

- 目前 web端`uni.request`传入泛型时不会创建对应类型的实例，会直接抹除类型信息，后续可能会调整为创建泛型类型对应的实例，请勿利用此特性。
- web端仅项目内定义的类型可以被实例化，uni-app-x内部定义的类型无法被实例化，例如`const options = { url: 'xxx' } as RequestOptions`，并不会将此对象转化为RequestOptions的实例，运行时也没有`RequestOptions`对应的类型信息。

### any类型

> 4.18版本起，uts在编译到js时，any类型会包含null类型。

不同于ts，uts中any类型不包含null类型。

例如定义可选参数时应使用下面的写法：

```ts
function test(anything?: any | null) { // 注意带上问号
  console.log(anything)
}
```

### 可选属性

如果属性在类型中是可选值需要使用下面的写法，不要省略问号和`| null`

```ts
type Options = {
  num?: number | null
}
```

### void/undefined类型

为保证多端统一应尽量避免使用undefined、void类型，可以使用null代替。如果需要判断是否为null建议使用两个等号，不要使用三个等号（此处使用了js的特性`undefined == null`结果为true）。

### String、Number、Boolean类型

ts内string、number、boolean类型与String、Number、Boolean类型并不相同。

```ts
let str1: String = '1'
let str2: string = '2'

str1 = str2 // 不报错
str2 = str1 // 报错 Type 'String' is not assignable to type 'string'
```

尽量使用string、number、boolean类型替代String、Number、Boolean类型。

### import type@import-type

由于uts会为as为某些类型的对象字面量创建这个类型对应的实例，所以经常会存在一些类型引入后是作为值使用而不是作为类型使用。应尽量不要使用`import type`用法，避免编译结果出错。

```ts
import type { TypeA } from './type' // 避免使用
import { TypeA } from './type' // 推荐用法
```
