Skip to content

Instantly share code, notes, and snippets.

@eligrey
Created March 19, 2010 03:42
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eligrey/337199 to your computer and use it in GitHub Desktop.
Save eligrey/337199 to your computer and use it in GitHub Desktop.
JavaScript Pseudo-Strict Typing
// assignment in function parameters
function sum1 ({Array: numbers}) {
let total = 0; // let {Number: total} = 0; would also be fine
let i = numbers.length;
while (i--) {
let {Number: n} = numbers[i];
total += n;
}
return total;
}
function sum2 ({any: numbers, length: {int: i}}) {
let total = 0;
while (i--) {
let {Number: n} = numbers[i];
total += n;
}
return total;
}
// assignment in function body
function sum3 (arr) {
let {Array: numbers, length: i} = arr,
total = 0;
while (i--) {
let {Number: n} = numbers[i];
total += n;
}
return total;
}
// generic named variables
function sum4 ({Array, length}) {
let total = 0;
while (length--) {
let {Number} = Array[length];
total += Number;
}
return total;
}
function FakeArray() {
for (let [i, val] in new Iterator(arguments)) {
// Yes, this loop won't include inherited properties
this[i] = val;
}
this.length = arguments.length;
};
// shell session:
js> sum1([2, 3, 4])
9
js> sum1(new FakeArray(2, 3, 4))
TypeError: Expected Array
js> sum2([2, 3, 4])
9
js> sum2(new FakeArray(2, 3, 4))
9
js> var numbers = new FakeArray(2, 3, 4)
js> numbers.length = 3.1
js> sum2(numbers)
TypeError: Expected int
js> sum1([2, "3", 4])
TypeError: Expected Number
// made this example before I knew about JS typed arrays
self.Object.defineTypeCheck("IntArray", function ({Array}) {
try {
return Array.every(function({int}) true);
} catch (ex if ex instanceof TypeError) {
return false;
}
});
js> var {IntArray: ia} = [1, 2, 3, 4];
self.Object.defineTypeCheck("jQuery", function (obj)
obj instanceof self.jQuery.fn.init
);
js> var {jQuery: divs} = $("div");
// $ alias to jQuery
self.Object.defineTypeCheck("$", function ({jQuery}) true);
js> var {$: divs} = $("div");
// # alias to Number
self.Object.defineTypeCheck("#", function ({Number}) true);
js> function square ({"#": n}) n * n;
// deleting types
self.Object.deleteTypeCheck("$");
// byte string type
self.Object.defineTypeCheck("ByteString", function ({String}) {
try {
decodeURIComponent(escape(String));
} catch (ex if ex instanceof URIError) {
return false;
}
return true;
})
var {ByteString: bytes} = "abc\u1234"; // error (U+1234 exceeds one octet)
var {ByteString: bytes} = "abc";
"use strict";
if (typeof self.Object.defineTypeCheck !== "function") {
let
OCtr = self.Object
, ACtr = self.Array
, types = (
"Boolean Date Error Function JSON Math Number Object RegExp String" // Base types
+ "Blob ArrayBuffer DataView Int8Array Int16Array Int32Array Uint8Array Uint16Array Uint32Array Float32Array Float64Array" // Typed array stuff
+ "DOMException Node NodeList DOMTokenList Element Element Attr Text Entity EntityReference Range TreeWalker NodeIterator XPathExpression XPathResult Comment ProcessingInstruction CDATASection CSSStyleSheet Document DocumentType DocumentFragment Event" // some base DOM types
).split(" ")
, i = types.length
, defineTypeCheck = function (type, check)
OCtr.defineTypeCheck(type, check)
;
OCtr.defineTypeCheck = function (type, check) {
this.defineProperty(this.prototype, type, {
get: function () {
if (check(this)) {
return this;
} else {
throw new TypeError("Expected " + type);
}
}
, enumerable: false
, configurable: true
});
};
OCtr.deleteTypeCheck = function (type)
delete this.prototype[type]
;
if (typeof ACtr.isArray === "function") {
defineTypeCheck("Array", function (array)
ACtr.isArray(array)
);
} else {
i = types.push("Array");
}
while (i--) {
let type = types[i];
defineTypeCheck(type, function (object)
OCtr.prototype.toString.call(object) === "[object " + type + "]"
);
}
// Implementable ECMAScript Harmony types:
defineTypeCheck("int", function ({Number})
Number % 1 === 0
);
defineTypeCheck("uint", function ({int})
int >= 0
);
defineTypeCheck("byte", function ({uint})
uint <= 0xFF
);
defineTypeCheck("float", function ({Number})
true
);
defineTypeCheck("boolean", function ({Boolean})
true
);
// "any" type
defineTypeCheck("*", function ()
true
);
// Alias for the "any" type that doesn't require being quoted
defineTypeCheck("any", function ()
true
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment