2

JS是一门动态类型语言,在定义一个函数时,无法为其进行强类型指定,如:

function hello(name: string, content: string) {
   // 如果name或content不是string类型的话,就抛异常
}

如果没有类型指定的话:

  1. 开发者常常不知道一个函数需要什么数据类型。
  2. 出现奇怪错误时,给debug造成麻烦。

其实业界已经有两种解决办法:

  1. 使用JSDoc对函数进行注释
  2. 使用强类型语言编程,最后编译成JS.

首先说第一种,JSDoc的语法规则可谓麻烦,注释简单类型时还稍微OK,如:

/**
 * @param string name the name of the person
 * @param string content the content to say
 */
function hello(name, content) { //... }

但如果我想对如下的数据结构做注释呢?

javascript{
    name: "jack",
    age: 18,
    address: {
        country: 'china',
        city: 'beijing'
    },
    keywords: ['student', 'programmer', 'ios']
}

基本上没几个人能写的对JSDoc的注释,要对上述结构进行JSDoc,你需要:

  1. 艰难的Google它奇怪的语法。
  2. 写出来还很丑。
  3. 最后其它开发者也看不懂。
  4. 参数传错也没有错误提示。(WebStorm一定程度上可以进行类型推导)。

第二种,嗯,就不说了。

要想基本没有学习成本的进行类型声明和检查,下面进入正题,使用duckie.

安装

对于node/browserify/webpack的用户,直接:

npm install duckie

var t = require('duckie'); // go!

对于浏览器用户,可以直接使用https://github.com/ssnau/duckie/tree/master/build下已经编译好的文件,也可用bower安装。最后可以使用window.duckie

入门

回到篇首,如果想实现function hello(name:string, content:string)该如何实现呢?

function hello(name, content) {
    duckie.string.assert(name);
    duckie.string.assert(content);

    // 如果上面的断言不成立的话,将抛出异常
}

string只是个示例,duckie总共支持如下一些基本类型:

  • boolean/bool
  • number
  • string
  • undefined
  • null
  • array
  • object
  • anything, 表示任意类型

即如下断言都为真:

duckie.boolean.assert(true);
duckie.number.assert(123);
duckie.string.assert('hello');
duckie.undefined.assert(undefined);
duckie.null.assert(null);
duckie.aray.assert([1,2,3]);
duckie.object.assert({name: 'jack'});
duckie.anything.assert('blabla');

如果只是断言简单的类型,那大可不必用duckie,JSDoc就基本能完成这种功效,除了不会抛异常。

duckie真正有效的地方在于,定义复杂的数据结构。

我们一个一个说起。

如果一个变量是枚举类型,如何限定它的枚举值呢?

使用oneOf.

// 只有值为male或female的变量,才能通过认证
duckie.oneOf(['male', 'female']).assert('male') => true
duckie.oneOf(['male', 'female']).assert(1)      => false

如果一个变量的类型,可能是undefined,可能是string,该如何表示?

使用maybe

duckie.maybe(String).assert('hello') => true
duckie.maybe(String).assert(undefined) => true
duckie.maybe(String).assert(123) => false

/*注:String可替换为duckie.string或"string",意义都一样*/

如果一个变量的类型可能是string,可能是number呢?

使用oneOfType

duckie.oneOfType([String, Number]).assert(1) => true
duckie.oneOfType([String, Number]).assert("hello") => true
duckie.oneOfType([String, Number]).assert(true) => false

如果一个变量是一个由数字组成的数组,该如何表示?

使用arrayOf(Number),或[Number].

// 使用arrayOf
duckie.arrayOf(Number).assert([1,2,3]) => true
// 直接使用[/*类型*/]
duckie([Number]).assert([1,2,3]) => true
duckie(['number']).assert(['hello', 'world']) => false

/* 注: 类型声明使用Number,duckie.number 和 'number' 效果是一样的。*/

如果一个变量是由一些key:value组成呢?

使用objectOf,或[].

//例如定义一个Person数据结构,典型的变量如下:
var person = {
    name: 'jack',
    age: 18
};

duckie.objectOf({
    name: String,
    age: Number
}).assert(person)  => true

duckie({
    name: String,
    age: Number
}).assert(person) => true

// 鸭子断言,即只要求被断言对象符合定义的
// 键值类型要求,而不要求精确匹配键数量
duckie({
    name: String
}).assert(person) => true

duckie({
    name: Number
}).assert(person) => false

如果一个变量是个object,里面有些值是数组呢?

以声明变量的方式用duckie声明你的类型。

// 比如篇首这东西
var person = {
    name: "jack",
    age: 18,
    address: {
        country: 'china',
        city: 'beijing'
    },
    keywords: ['student', 'programmer', 'ios']
}

// 使用duckie声明
duckie({
    name: String,
    age: Number,
    address: {
        country: String,
        city: String
    },
    keywords: [String]
}).assert(person)  => true

声明一个类型跟声明一个对象般简单,完全没有学习成本。

总结

使用duckie可以像声明一个变量那样声明你的类型,且可以在运行时进行类型检查。如有什么建议,欢迎提议。


ssnau
1.5k 声望98 粉丝

负能量职业打码师