Types have a bad reputation for making code harder to read, adding unnecessary ceremony, and in general complicating things. In this blog post I’d like to show that a type system done right can help make code more readable and toolable without constraining the expressiveness of the language.

DOCUMENTATION FOR HUMANS AND MACHINES

First, I want to show how type annotations can be used as documentation for both humans and machines.

Let’s look at this function jQuery.ajax() and pretend that we are not familiar with it. What kind of information can we get from its signature?

    jQuery.ajax(url, settings)

The only thing we can tell for sure is that the function takes two arguments. We can guess the types. Maybe the first one is a string and the second one is a configuration object. But it is just a guess and we might be wrong. We have no idea what options go into the settings object (neither their names nor their types) or what this function returns.

There is no way we can call this function without checking the source code or the documentation. Checking the source code is not a good option – the point of having functions and classes is to be able to use them without knowing how they are implemented. In other words, we should rely on their interfaces, not on their implementation.The only option we have here is to check the documentation. And there is nothing wrong with that. Except that it takes time.

Now, contrast it with a typed version.

ajax(url: string, settings?: JQueryAjaxSettings): JQueryXHR;

interface JQueryAjaxSettings {
async?: boolean;
cache?: boolean;
contentType?: any;
headers?: { [key: string]: any; };
//...
} interface JQueryXHR {
responseJSON?: any;
//...
}

It gives us a lot more information.

  • The first argument of this function is a string.
  • The settings argument is optional. We can see all the options that can be passed into the function, and not only their names, but also their types.
  • The function returns a JQueryXHR object, and we can see its properties and functions.

This bring us to my first point.

Types serve as documentation for the programmer.

In addition, this information enables advanced autocompletion, navigation, and refactoring capabilities. Having such tools is almost a requirement for large projects. Without them programmers are afraid to change the code, which makes large-scale refactorings almost impossible. As Anders Hejlsberg puts it, you can build a large application in a dynamically-typed language, but you cannot maintain it. Without advanced tools a large code base is always in a semi-read-only state.

Types enable advanced tools.

TYPES PROVIDE A CONCEPTUAL FRAMEWORK FOR THE PROGRAMMER

A good design is all about well-defined interfaces. And it is much easier to express the idea of an interface in a language that supports them.

For instance, imagine a book-selling application where a purchase can be made by either a registered user through the UI or by an external system through some sort of an API.

As you can see, both classes play the role of a purchaser. Despite being extremely important for the application, the notion of a purchaser is not clearly expressed in the code. There is no file named purchaser.js. And as a result, it is possible for someone modifying the code to miss the fact that this role even exists.

function processPurchase(purchaser, details){
} class User {
} class ExternalSystem {
}

It is hard, just by looking at the code, tell what objects can play the role of a purchaser, and what methods this role has. We do not know for sure and we will not get much help from our tools. We have to infer this information manually, which is slow and error-prone.

Now, compare it with a version where we explicitly define the Purchaser interface.

interface Purchaser {
id: int;
bankAccount: Account;
} class User implements Purchaser {}
class ExternalSystem implements Purchaser {}

The typed version clearly states that we have the Purchaser interface, and the User and ExternalSystem classes implement it. This brings us to my next point.

Types are useful for defining interfaces/protocols/roles. They provide a conceptual framework for the programmer.

It is important to realize that types do not force us to introduce extra abstractions. The Purchaser abstraction is present in the JavaScript version of the code, but it is not explicitly defined.

I’ve spent most of my career programming in Ruby and JavaScript, and I find these languages extremely powerful and flexible. But after working on sizeable apps written in these languages, I came to the conclusion that the lack of interfaces pushes developers toward building tightly coupled systems.

In a statically typed language boundaries between subsystems are defined using interfaces. Since Ruby and JavaScript lack interfaces, boundaries are not well expressed in code. Not being able to clearly see the boundaries, developers start depending on concrete types instead of abstract interfaces. And it leads to tight coupling. It is possible to build large decoupled systems in these languages, but it requires a lot of discipline.

STATICALLY TYPED LANGUAGES?

It may seem that I am advocating statically typed languages, but I am not. The arguments against a mandatory static type system are still sound.

  1. It complicates the language. Writing a mock library in JavaScript is an exercise that almost everyone can undertake. Doing similar stuff in Java is far more difficult.
  2. It constrains the expressiveness of the language.
  3. It requires type annotations even when they are not desirable (e.g., in a domain specific language).

What we want is something that combines the power of a dynamically typed language with the benefits of having explicit interfaces and type annotations.

OPTIONAL TYPE SYSTEMS

An optional type system does not require using type annotations. Type annotations are used to help you communicate your intent and get better tooling.

Optional type systems are forgiving. You do not have to satisfy the type checker. Quite the opposite, the type checker is there to help you find typos, search, and refactor. You do not completely rewrite your program to make the types work. If you are prototyping something, and duck typing works, just do not use types. Use them only when they add value.

It would not be completely fair to say that optional typing is only good stuff without any drawbacks. It still adds some complexity to the language (nothing compared to a mandatory static type system though).Also, to fully see the benefits of such a system you need more sophisticated tools than a plain text editor. But because of the reasons I outlined in this blog post, I think it is worth paying this price.

TYPED JAVASCRIPT

I wrote the original version of this blog post some time ago, and called it “I Wish Ruby Had Interfaces”. Back then I was a Rails developer. And I was extremely frustrated by working on a very large Rails code base, where some refactorings were taking months to finish. There was no hope Ruby would get an optional type system, so it was just a rant.

This time it is different. The JavaScript community is embracing the idea of optional types. TypeScript has become a robust tool used in production at many companies. AtScript, and Flow are new projects in this area. I am really excited to see what typed JavaScript community will look like in a few years.

WHY JAVASCRIPT NEEDS TYPES的更多相关文章

  1. JavaScript data types and data structures

    JavaScript data types and data structures Programming languages all have built-in data structures, b ...

  2. JavaScript & Error Types

    JavaScript & Error Types JavaScript提供了8个错误对象,这些错误对象会根据错误类型在try / catch表达式中引发: Error EvalError Ra ...

  3. [Javascript] Manage Application State with Immutable.js

    Learn how Immutable.js data structures are different from native iterable Javascript data types and ...

  4. JavaScript 中的数字和日期类型

    本章节介绍如何掌握Javascript里的数字和日期类型 数字EDIT 在 JavaScript 里面,数字都是双精度浮点类型的 double-precision 64-bit binary form ...

  5. JavaScript Transpilers: 为什么需要用它们?Babel的使用介绍。

    英文原文 https://scotch.io/tutorials/javascript-transpilers-what-they-are-why-we-need-them 摘译(文章内的代码有些过期 ...

  6. Javascript——概述 && 继承 && 复用 && 私有成员 && 构造函数

    原文链接:A re-introduction to JavaScript (JS tutorial) Why a re-introduction? Because JavaScript is noto ...

  7. 深入理解 JavaScript中的变量、值、传参

    1. demo 如果你对下面的代码没有任何疑问就能自信的回答出输出的内容,那么本篇文章就不值得你浪费时间了. var var1 = 1 var var2 = true var var3 = [1,2, ...

  8. A re-introduction to JavaScript (JS Tutorial) 转载自:https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript

    A re-introduction to JavaScript (JS Tutorial) Redirected from https://developer.mozilla.org/en-US/do ...

  9. 实现JavaScript继承

    使用TypeScript或者ES2015+标准中的extends关键字是很容易实现继承的,但这不是本文的重点.JS使用了基于原型(prototype-based)的继承方式,extends只是语法糖, ...

随机推荐

  1. 《DSP using MATLAB》 Problem 2.3

    本题主要是显示周期序列的. 1.代码: %% ------------------------------------------------------------------------ %% O ...

  2. 《FDTD electromagnetic field using MATLAB》读书笔记之 Figure 1.14

    背景: 基于公式1.42(Ez分量).1.43(Hy分量)的1D FDTD实现. 计算电场和磁场分量,该分量由z方向的电流片Jz产生,Jz位于两个理想导体极板中间,两个极板平行且向y和z方向无限延伸. ...

  3. python 之 collections

    Python作为一个“内置电池”的编程语言,标准库里面拥有非常多好用的模块.比如今天想给大家 介绍的 collections 就是一个非常好的例子. 基本介绍 我们都知道,Python拥有一些内置的数 ...

  4. 文件和I/O流

    版权声明:本文为[博主](https://zhangkn.github.io)原创文章,未经博主同意不得转载.https://creativecommons.org/licenses/by-nc-sa ...

  5. 深入理解java虚拟机,内存管理部分

    1,对象回收前会调用finalize()方法,尝试自救,只能调用一次 2,上面横向对比c++的析构函数,但是java有良好的内存管理,而且try/catch做得比较好 3,回收一个常量,1,对象的实例 ...

  6. [maven] 实战笔记 - maven 安装配置

    1.下载地址http://maven.apache.org/download.html 2.windows下安装maven(1)下载 apache-maven-3.0-bin.zip 解压到任意目录下 ...

  7. 并发包学习(三)-AbstractQueuedSynchronizer总结

    J.U.C学习的第二篇AQS.AQS在Java并发包中的重要性,毋庸置疑,所以单独拿出来理一理.本文参考总结自<Java并发编程的艺术>第五章第二节队列同步器. 什么是AbstractQu ...

  8. HyberLedger Fabric学习(3)-chaincode学习(开发者)

    参考:http://hyperledger-fabric.readthedocs.io/en/latest/chaincode4ade.html chaincode是由go语言写的,实现了定义的接口. ...

  9. Request模块(八)

    Requests: 让 HTTP 服务人类 虽然Python的标准库中 urllib2 模块已经包含了平常我们使用的大多数功能,但是它的 API 使用起来让人感觉不太好,而 Requests 自称 “ ...

  10. tensorflow 卷积神经网络基本参数()

    目录: 1. tf.placeholder_with_default(tf.constant(1.0),shape=[],name='use_dropout')   # 设置一个占位符 2. tf.c ...