使用 TypeScript

上次修改时间:2021-07-02 10:46:78

TypeScript 是 Javascript 的超集,它相对于 Javascript,增加了许多实用的新特性:

  • 类型批注和编译时类型检查
  • 类型推断
  • 类型擦除
  • 接口
  • 枚举
  • Mixin
  • 泛型编程
  • 名字空间
  • 元组
  • Await

使用 TypeScript 对 IDE 会更加友好,如果你是用 vscode 开发的,那么你的开发体验将会显著提升。基于 umi 的特性,我们可以很容易的在 Pro 中使用。 Pro 中自带了 TypeScript 所需的配置文件.

  • tsconfig.js
  • tslint.json

tsconfig 会声明这是一个 TypeScript 的项目,其中会进行一些配置,详细内容可以看这里。 tslint 类似 eslint 将会检查你的代码,为了提升体验,可以一并安装 vscode 的 tslint 插件。接下来我们只要直接新建 tsx 文件,就可以开始 TypeScript 开发了。

常见问题

在 css-module 中使用

由于 Pro 使用了 css-module,你可能需要

import style from './index.style.less';

这时候 typescript 会报错,你可以 使用

const style = require('./index.less');

避开这个问题。社区有很多相关讨论,暂时没有最好的办法,只有相对完美的 typings-for-css-modules-loader,同理导入图片,css,svg 也可以通过这种方式避开类型检查。

Form.create()

在 TypeScript 中使用 Form.create() 可能会抛出类似下面的错误:

error TS2339: Property 'loading' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Compone
nt<{}, ComponentState>> & Readonly<{ childr...'.

这是因为 props 的类型没有通过检查,以下是正确的方式

import { FormComponentProps } from "antd/lib/form/Form";

interface IFormComponentProps extends FormComponentProps {
  test: string;
}

class FormComponent extends React.Component<IFormComponentProps> {
  constructor(props: IFormComponentProps) {
    super(props);
    ....
  }
  render() {
    const { getFieldDecorator } = this.props.form;
    return ....;
  }
}

没有描述文件的仓库

在实际使用有些库并没有相关的 d.ts,这个时候我们可以直接在使用的文件中定义,以高德地图为例。

import React from 'react';

// 定义 Map 的 类型
declare class GaoDeAMap {
  constructor(container: HTMLElement, option: { center: [number, number]; zoom: number });
  public destroy(): void;
}

// 定义全局的 AMap
declare const AMap: {
  Map: typeof GaoDeAMap;
};

// tslint:disable-next-line:max-classes-per-file
class MapComponent extends React.Component {
  public mapDom: HTMLDivElement;
  public map: GaoDeAMap;
  public componentDidMount() {
    const map = new AMap.Map(this.mapDom, {
      center: [117.000923, 36.675807],
      zoom: 11,
    });
    this.map = map;
  }
  public componentWillUnmount() {
    this.map.destroy();
  }
  public render() {
    return <div ref={(ref) => (this.mapDom = ref)} />;
  }
}

export default MapComponent;

如果要多次使用,可以建立一个 namespace,

declare namespace AMap {
  class Map {
    constructor(
      container: HTMLElement,
      option: { center: [number, number]; zoom: number }
    )
    public destroy(): void
  }
}

export = AMap
export as namespace

然后在项目中直接引入就可以了。

import AMapInterface from './AMap';

declare const AMap: typeof AMapInterface;