old_contents: var util = require('../util');
  
  var TYPES = '__types__';
  
  var PARSERS = {
    boolean: util.boolean,
    integer: util.number,
    number:  util.number,
    date:    util.date,
    string:  function(x) { return x == null || x === '' ? null : x + ''; }
  };
  
  var TESTS = {
    boolean: function(x) { return x==='true' || x==='false' || util.isBoolean(x); },
    integer: function(x) { return TESTS.number(x) && (x=+x) === ~~x; },
    number: function(x) { return !isNaN(+x) && !util.isDate(x); },
    date: function(x) { return !isNaN(Date.parse(x)); }
  };
  
  function annotation(data, types) {
    if (!types) return data && data[TYPES] || null;
    data[TYPES] = types;
  }
  
  function type(values, f) {
    values = util.array(values);
    f = util.$(f);
    var v, i, n;
  
    // if data array has type annotations, use them
    if (values[TYPES]) {
      v = f(values[TYPES]);
      if (util.isString(v)) return v;
    }
  
    for (i=0, n=values.length; !util.isValid(v) && i<n; ++i) {
      v = f ? f(values[i]) : values[i];
    }
  
    return util.isDate(v) ? 'date' :
      util.isNumber(v)    ? 'number' :
      util.isBoolean(v)   ? 'boolean' :
      util.isString(v)    ? 'string' : null;
  }
  
  function typeAll(data, fields) {
    if (!data.length) return;
    fields = fields || util.keys(data[0]);
    return fields.reduce(function(types, f) {
      // don't expand embedded periods
      return (types[f] = type(data, '[' + f + ']'), types);
    }, {});
  }
  
  function infer(values, f) {
    values = util.array(values);
    f = util.$(f);
    var i, j, v;
  
    // types to test for, in precedence order
    var types = ['boolean', 'integer', 'number', 'date'];
  
    for (i=0; i<values.length; ++i) {
      // get next value to test
      v = f ? f(values[i]) : values[i];
      // test value against remaining types
      for (j=0; j<types.length; ++j) {
        if (util.isValid(v) && !TESTS[types[j]](v)) {
          types.splice(j, 1);
          j -= 1;
        }
      }
      // if no types left, return 'string'
      if (types.length === 0) return 'string';
    }
  
    return types[0];
  }
  
  function inferAll(data, fields) {
    fields = fields || util.keys(data[0]);
    return fields.reduce(function(types, f) {
      // don't expand embedded periods
      types[f] = infer(data, '[' + f + ']');
      return types;
    }, {});
  }
  
  type.annotation = annotation;
  type.all = typeAll;
  type.infer = infer;
  type.inferAll = inferAll;
  type.parsers = PARSERS;
  module.exports = type;
  
new_contents: var util = require('../util');
  
  var TYPES = '__types__';
  
  var PARSERS = {
    boolean: util.boolean,
    integer: util.number,
    number:  util.number,
    date:    util.date,
    string:  function(x) { return x == null || x === '' ? null : x + ''; }
  };
  
  var TESTS = {
    boolean: function(x) { return x==='true' || x==='false' || util.isBoolean(x); },
    integer: function(x) { return TESTS.number(x) && (x=+x) === ~~x; },
    number: function(x) { return !isNaN(+x) && !util.isDate(x); },
    date: function(x) { return !isNaN(Date.parse(x)); }
  };
  
  function annotation(data, types) {
    if (!types) return data && data[TYPES] || null;
    data[TYPES] = types;
  }
  
  function fieldNames(datum) {
    return util.keys(datum);
  }
  
  function bracket(fieldName) {
    return '[' + fieldName + ']';
  }
  
  function type(values, f) {
    values = util.array(values);
    f = util.$(f);
    var v, i, n;
  
    // if data array has type annotations, use them
    if (values[TYPES]) {
      v = f(values[TYPES]);
      if (util.isString(v)) return v;
    }
  
    for (i=0, n=values.length; !util.isValid(v) && i<n; ++i) {
      v = f ? f(values[i]) : values[i];
    }
  
    return util.isDate(v) ? 'date' :
      util.isNumber(v)    ? 'number' :
      util.isBoolean(v)   ? 'boolean' :
      util.isString(v)    ? 'string' : null;
  }
  
  function typeAll(data, fields) {
    if (!data.length) return;
    var get = fields ? identity : (fields = fieldNames(data[0]), bracket);
    return fields.reduce(function(types, f) {
      return (types[f] = type(data, get(f)), types);
    }, {});
  }
  
  function infer(values, f) {
    values = util.array(values);
    f = util.$(f);
    var i, j, v;
  
    // types to test for, in precedence order
    var types = ['boolean', 'integer', 'number', 'date'];
  
    for (i=0; i<values.length; ++i) {
      // get next value to test
      v = f ? f(values[i]) : values[i];
      // test value against remaining types
      for (j=0; j<types.length; ++j) {
        if (util.isValid(v) && !TESTS[types[j]](v)) {
          types.splice(j, 1);
          j -= 1;
        }
      }
      // if no types left, return 'string'
      if (types.length === 0) return 'string';
    }
  
    return types[0];
  }
  
  function inferAll(data, fields) {
    var get = fields ? identity : (fields = fieldNames(data[0]), bracket);
    return fields.reduce(function(types, f) {
      types[f] = infer(data, get(f));
      return types;
    }, {});
  }
  
  type.annotation = annotation;
  type.all = typeAll;
  type.infer = infer;
  type.inferAll = inferAll;
  type.parsers = PARSERS;
  module.exports = type;
  
subject: Fix PR #80.