July 2000 Draft
JavaScript 2.0

Wednesday, February 16, 2000

Predefined Types

The following types are predefined in JavaScript 2.0:

Type Set of Values Coercions
none No values None
void undefined Any value undefined
Null null undefined null
Boolean   true and false undefined false
Integer Double-precision IEEE floating-point numbers that are mathematical integers, including positive and negative zeroes, infinities, and NaN undefined NaN
Number Double-precision IEEE floating-point numbers, including positive and negative zeroes, infinities, and NaN undefined NaN
Character   Single 16-bit unicode characters None
String Immutable strings of unicode characters undefined ""
Function All functions None
Array All arrays undefined []
Type All types undefined any
any All values None

Unlike in JavaScript 1.5, there is no distinction between objects and primitive values. All values can have methods. Some values can be sealed, which disallows addition of ad-hoc properties. User-defined classes can be made to behave like primitives.

The above type names are not reserved words. They are considered to be defined in a scope that encloses a package's global scope, so a package could use these type names as identifiers. However, defining these identifiers for other uses might be confusing because it would shadow the corresponding type names (the types themselves would continue to exist, but they could not be accessed by name).

any is the supertype of all types. none is the subtype of all types. none is useful to describe the return type of a function that cannot return normally because it either falls into an infinite loop or always throws an exception. void is useful to describe the return type of a function that can return but that does not produce a useful value.

A literal number is a member of the type Number; if that literal has an integral value, then it is also a member of type Integer. A literal string is a member of the type String; if that literal has exactly one 16-bit unicode character, then it is also a member of type Character.

Predefined Type Constructors

We can use the following operators to construct more complex types. t is a type expression and u is a value expression in the table below.

Type   Values Coercions
+ t null or any value belonging to type t null null; undefined null (if undefined is not a member of t); any other coercions already defined for t
~ t undefined or any value belonging to type t undefined undefined; any other coercions already defined for t
singleton(u) Only the value u None

The language cannot syntactically distinguish type expressions from value expressions, so a type expression can also use any other value operators such as !, |, and . (member access). Except for parentheses, most of them are not very useful, though. See also the type expression syntax rationale for other possible type constructors.

User-Defined Types

Any class defined using the class declaration is also a type that denotes the set of all of its and its descendants' instances. These include the predefined classes, so Object, Date, etc. are all types. null is not an instance of a user-defined class.

Meaning of Types

Types are generally used to restrict the set of objects that can be held in a variable or passed as a function argument. For example, the declaration

var x:Integer;

restricts the values that can be held in variable x to be integers.

Type declarations use the Pascal-style colon syntax. See the type declaration syntax rationale for an alternative.

A type declaration does not affect the semantics of reading the variable or accessing one of its members. Thus, as long as expression new MyType() returns a value of type MyType, the following two code snippets are equivalent:

var x:MyType = new MyType();
var x = new MyType();

This equivalence always holds, even if these snippets are inside the declaration of class MyType and foo is a private field of that class. As a corollary, adding true type annotations does not change the meaning of a program.

Type Expressions

A type is also a value (whose type is type) and can be used in expressions, assigned to variables, passed to functions, etc. For example, the code

const Z:Type = Integer;
function abs_val(i:Z):Z {
  return i<0 ? -i : i;

is equivalent to:

function abs_val(i:Integer):Integer {
  return i<0 ? -i : i;

As another example, the following method takes a type and returns an instance of that type:

method QueryInterface(T:Type):T { ... }


Coercions can take place in the following situations:

In any of these cases, if v t, then v is passed unchanged. If v t, then if t defines a mapping for value v then that mapped v is used; otherwise an error occurs.

@ Operator

One can explicitly request a coercion in an expression by using the @ operator. This operator has the same precedence as . and coerces its left operand to the right operand, which must be a type. ... v@t ... can be used in an expression and has the same effect as:

function coerce_to_t(a:t):t {return a}   // Declared at the top level

... coerce_to_t(v) ...

assuming that coerce_to_t is an identifier not used anywhere else. The @ operator is useful as a type assertion as in w@Window. It's a postfix operator to simplify cascading expressions:


is equivalent to:



A type cast performs more aggressive transformations than a type coercion. To cast a value to a given type, we use the type as a function, passing it the value as an argument:


For example, Integer(258.1) returns the integer 258, and String(2+2==4) returns the string "true".

If value is already a member of type, the type cast returns value unchanged. If value can be coerced to type, the type cast returns the result of the coercion. Otherwise, the effect of a type cast depends on type.

Need to specify the semantics of type casts. They are intended to mimic the current ToNumber, ToString, etc. methods.

Waldemar Horwat
Last modified Wednesday, February 16, 2000