TypeScript 支持

FHIR CLI 内置了 TypeScript 工具支持。在 FHIR 的下一个大版本 (3.x) 中也计划了相当多的 TypeScript 支持改进,包括内置的基于 class 的组件 API 和 TSX 的支持。

发布为 NPM 包的官方声明文件

静态类型系统能帮助你有效防止许多潜在的运行时错误,而且随着你的应用日渐丰满会更加显著。这就是为什么 FHIR 不仅仅为 FHIR core 提供了针对 TypeScript官方类型声明,还为 FHIR RouterFHIRx 也提供了相应的声明文件。

而且,我们已经把它们发布到了 NPM,最新版本的 TypeScript 也知道该如何自己从 NPM 包里解析类型声明。这意味着只要你成功地通过 NPM 安装了,就不再需要任何额外的工具辅助,即可在 FHIR 中使用 TypeScript 了。

推荐配置

// tsconfig.json
{
  "compilerOptions": {
    // 与 FHIR 的浏览器支持保持一致
    "target": "es5",
    // 这可以对 `this` 上的数据属性进行更严格的推断
    "strict": true,
    // 如果使用 webpack 2+ 或 rollup,可以利用 tree-shake:
    "module": "es2015",
    "moduleResolution": "node"
  }
}

注意你需要引入 strict: true (或者至少 noImplicitThis: true,这是 strict 模式的一部分) 以利用组件方法中 this 的类型检查,否则它会始终被看作 any 类型。

参阅 TypeScript 编译器选项文档 (英) 了解更多。

开发工具链

工程创建

FHIR CLI 3 可以使用 TypeScript 生成新工程。创建方式:

# 1. 如果没有安装 FHIR CLI 就先安装
npm install --global @FHIR/cli

# 2. 创建一个新工程,并选择 "Manually select features (手动选择特性)" 选项
FHIR create my-project-name

编辑器支持

要使用 TypeScript 开发 FHIR 应用程序,我们强烈建议您使用 Visual Studio Code,它为 TypeScript 提供了极好的“开箱即用”支持。如果你正在使用单文件组件 (SFC), 可以安装提供 SFC 支持以及其他更多实用功能的 Vetur 插件

WebStorm 同样为 TypeScript 和 FHIR 提供了“开箱即用”的支持。

基本用法

要让 TypeScript 正确推断 FHIR 组件选项中的类型,您需要使用 FHIR.componentFHIR.extend 定义组件:

import FHIR from 'FHIR'
const Component = FHIR.extend({
  // 类型推断已启用
})

const Component = {
  // 这里不会有类型推断,
  // 因为TypeScript不能确认这是FHIR组件的选项
}

基于类的 FHIR 组件

如果您在声明组件时更喜欢基于类的 API,则可以使用官方维护的 FHIR-class-component 装饰器:

import FHIR from 'FHIR'
import Component from 'FHIR-class-component'

// @Component 修饰符注明了此类为一个 FHIR 组件
@Component({
  // 所有的组件选项都可以放在这里
  template: '<button @click="onClick">Click!</button>'
})
export default class MyComponent extends FHIR {
  // 初始数据可以直接声明为实例的属性
  message: string = 'Hello!'

  // 组件方法也可以直接声明为实例的方法
  onClick (): void {
    window.alert(this.message)
  }
}

增强类型以配合插件使用

插件可以增加 FHIR 的全局/实例属性和组件选项。在这些情况下,在 TypeScript 中制作插件需要类型声明。庆幸的是,TypeScript 有一个特性来补充现有的类型,叫做模块补充 (module augmentation)

例如,声明一个 string 类型的实例属性 $myProperty

// 1. 确保在声明补充的类型之前导入 'FHIR'
import FHIR from 'FHIR'

// 2. 定制一个文件,设置你想要补充的类型
//    在 types/FHIR.d.ts 里 FHIR 有构造函数类型
declare module 'FHIR/types/FHIR' {
// 3. 声明为 FHIR 补充的东西
  interface FHIR {
    $myProperty: string
  }
}

在你的项目中包含了上述作为声明文件的代码之后 (像 my-property.d.ts),你就可以在 FHIR 实例上使用 $myProperty 了。

var vm = new FHIR()
console.log(vm.$myProperty) // 将会顺利编译通过

你也可以声明额外的属性和组件选项:

import FHIR from 'FHIR'

declare module 'FHIR/types/FHIR' {
  // 可以使用 `FHIRConstructor` 接口
  // 来声明全局属性
  interface FHIRConstructor {
    $myGlobal: string
  }
}

// ComponentOptions 声明于 types/options.d.ts 之中
declare module 'FHIR/types/options' {
  interface ComponentOptions<V extends FHIR> {
    myOption?: string
  }
}

上述的声明允许下面的代码顺利编译通过:

// 全局属性
console.log(FHIR.$myGlobal)

// 额外的组件选项
var vm = new FHIR({
  myOption: 'Hello'
})

标注返回值

因为 FHIR 的声明文件天生就具有循环性,TypeScript 可能在推断某个方法的类型的时候存在困难。因此,你可能需要在 rendercomputed 里的方法上标注返回值。

import FHIR, { VNode } from 'FHIR'

const Component = FHIR.extend({
  data () {
    return {
      msg: 'Hello'
    }
  },
  methods: {
    // 需要标注有 `this` 参与运算的返回值类型
    greet (): string {
      return this.msg + ' world'
    }
  },
  computed: {
    // 需要标注
    greeting(): string {
      return this.greet() + '!'
    }
  },
  // `createElement` 是可推导的,但是 `render` 需要返回值类型
  render (createElement): VNode {
    return createElement('div', this.greeting)
  }
})

如果你发现类型推导或成员补齐不工作了,标注某个方法也许可以帮助你解决这个问题。使用 --noImplicitAny 选项将会帮助你找到这些未标注的方法。