logo
Published on

TypeScript 从入门到放弃之快速入门

前言

尝试了一下 TypeScript 之后,是“真香”啊,静态类型检验确实能避免很多编译时的问题。学有余力之际,所以打算先过一遍官方文档。本系列是以官方文档为主,结合自身相关经验整理而成的入门学习笔记。

TypeScript 速览

安装 TypeScript

$ npm install -g typescript

编译

// greeter.ts
function greeter(person) {
  return 'Hello, ' + person
}

let user = 'Jane User'

document.body.innerHTML = greeter(user)
$ tsc greeter.ts

编译后会得到同名的 js 文件。

类型注解(Type annotations)

function greeter(person: string) {
  return 'Hello, ' + person
}

let user = 'Jane User'

document.body.innerHTML = greeter(user)

加上注解(其实,不加类型注解,变量类型应该是 any )后,编译会经过类型检查,不正确会报错,但是仍然会生成相应的 js 文件。

接口(Interfaces)

描述对象字段类型。只要对象包含接口中的必须字段即可,多余字段不做检查。

类(Classes)

可包含公有变量和构造器。值得注意的是,构造函数的参数上使用 public 等同于创建了同名的成员变量。

class Student {
  fullName: string
  constructor(
    public firstName: string,
    public middleInitial: string,
    public lastName: string,
  ) {
    this.fullName = firstName + ' ' + middleInitial + ' ' + lastName
  }
}

interface Person {
  firstName: string
  lastName: string
}

function greeter(person: Person) {
  return 'Hello, ' + person.firstName + ' ' + person.lastName
}

let user = new Student('Jane', 'M.', 'User')

document.body.innerHTML = greeter(user)

例如本例中,编译后得到的结果如下:

var Student = /** @class */ (function () {
  function Student(firstName, middleInitial, lastName) {
    this.firstName = firstName
    this.middleInitial = middleInitial
    this.lastName = lastName
    this.fullName = firstName + ' ' + middleInitial + ' ' + lastName
  }
  return Student
})()
function greeter(person) {
  return 'Hello, ' + person.firstName + ' ' + person.lastName
}
var user = new Student('Jane', 'M.', 'User')
document.body.innerHTML = greeter(user)

如果去掉 middleInitialpublic 修饰,则 this.middleInitial = middleInitial; 会被移除。

运行 TypeScript Web 应用

新建如下 greeter.html

<!DOCTYPE html>
<html>
  <head>
    <title>TypeScript Greeter</title>
  </head>
  <body>
    <script src="greeter.js"></script>
  </body>
</html>

使用浏览器打开,可得输出

Hello, Jane User

快速入门

官方提供了基于多种框架的入门教程,这里列一下我知名知意的教程

因为我是从 React 入手 TypeScript 的,故仅作基于 React 入门笔记。

TypeScript React 入门

安装 create-react-app

$ npm install -g create-react-app

创建新项目

$ create-react-app my-app --scripts-version=react-scripts-ts

react-scripts-ts is a set of adjustments to take the standard create-react-app project pipeline and bring TypeScript into the mix.

我的理解是 react-scripts-ts 是一个给标准的 create-react-app 项目混合 TypeScript 支持的管道。

关于目录结构的说明,详见官方文档

代码管理

$ git init
$ git add .
$ git commit -m "Initial commit."

重写默认 TSLint 配置( tslint.json / tslint.yaml )

由于 react-scripts-ts 预设的配置有些过于热心(a bit overzealous,还真不知道怎么翻译好),所以修改如下。

{
-  "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"],
+  "extends": [],
+  "defaultSeverity": "warning",
   "linterOptions": {
     "exclude": [
       "config/**/*.js",
       "node_modules/**/*.ts"
     ]
   }
 }

关于配置 TSLint,这个作为补充,为了定制化配置,需要研究下。

启动

$ npm run start

测试

$ npm run test

所有以 .test.tsspec.ts 的文件,都会被 Jest 运行。特别的, Jest 也会像 npm run start 一样自动运行。

编译

$ npm run build

创建一个组件

通过类创建的组件可以使用状态和生命周期函数,由于 React 16.8 之后提供的 hooks ,我们已经可以在函数式组件中使用一些特殊功能,包括状态管理。

偶然看到一个讨论 React 16.7 - React.SFC is now deprecated ,进而找到 Rename React's SFC to 'FunctionalComponent',官方已经修改了 SFC 定义 _(:3J∠)_

类型断言(Type assertions)

类似这样 document.getElementById('root') as HTMLElementas 语法,被称为类型断言,或者类型转换。这是一个非常重要的方式去告诉类型检查器( type checker )我们使用的对象究竟是什么类型。

举个例子,定义一个 CommentType 的类型,当我们从后台请求了响应的评论列表 comments 时,就可以使用如下的方式告诉类型检查器我们得到的是一个 CommentType 数组。

declare type CommentType = {}

// ...

comments as CommentType[]

这里 getElementById 的返回类型是 HTMLElement | null,所以我们使用 as 语法让 TypeScript 确信为 HTMLElement 类型。

状态组件

为状态组件添加类型校验的使用方式如下:

interface HelloProps {
  name: string
}

interface HelloState {
  current: string
}

class Hello extends React.Component<HelloProps, HelloState> {
  // ...
}

备注:

添加样式

和通常的方式一致。

使用 Jest 编写测试

首先,需要安装 EnzyMe 。默认情况下,应用包含了一个叫 jsdom 的库,用于模拟 DOM 树并测试其运行时行为。 EnzyMe 是基于 jsdom 的让用户更为简单的访问组件的行为。

$ npm install -D enzyme @types/enzyme enzyme-adapter-react-16 @types/enzyme-adapter-react-16 react-test-renderer

关于配置和入门使用,参阅本节官方文档

添加状态管理器

介绍了 ReduxMobX,并基于 Redux 做了较为详细的讲解。如果都在看 TS 的文档了,状态管理应该已经很熟悉了吧,这里著作赘述了。

弹出配置

如果想自定义 create-react-app 的配置,需要用到弹出配置的功能。

$ npm run eject

在学习 ant-design 的时候,接触到了 react-app-rewired ,可以在不弹出配置的情况下重写相关配置,个人觉得通常情况下这个应该是个不错的选择。

下一步

多学习 React 官方文档,还有很多其他的技术需要学习,诸如状态管理,项目配置,页面路由等等...