JSig is language to express the types of a JavaScript program.
To be able to talk about how JavaScript values and JSig types are related we will introduce some concepts.
A JavaScript value v is of a JSig type T.
To check whether v is of type T we first infer the
Jsig type expression S for v. Then if S is a subtype
of T we know that v is of type T
A Jsig type expression S can be a subtype of a JSig type
expression T
TODO: define subtype semantics
A JSig file contains a series of statements.
You can also use a statement in a comment in a piece of code.
someIdentifier : {{TypeExpression}}
An assignment statement is an identifier and a type expression
seperated by a : symbol.
An identifier is a reference to some concrete value in JavaScript.
There are multiple ways that identifiers can be resolved to a value in JavaScript, these will be defined later.
The concrete value v that the identifier references to must
satisfy the {{TypeExpression}}
Examples:
add : (Number, Number) => voidmyApp : { state: T, render: (T) => DOMElement }HttpServer : { listen: (Number) => void }
type SomeCustomTypeName : {{TypeExpression}}
A type declaration statement is the type keyword, followed
by a custom type name followed by the : symbol and
followed by a type expression
The custom type name can then be used in the rest of the file
to reference to the {{TypeExpression}}
It is also valid for another file to import the
SomeCustomTypeName type literal into their file. i.e. all
custom types are exported by default.
Example:
type Coord : Numbertype Pos : { x: Number, y: Number }type HttpRequest : { url: String, method: String }
TODO
import { A, B, ... } from "./other-file.jsig"
An import statement is an import keyword followed by a comma
seperated list of type names in curly braces, followed by
a from keyword and a file name.
An import statement allows you to import one or more custom types defined in another file.
For the import to be valid the other file should have defined
A and B as custom types.
Example:
import { AThing } from "./other-file.jsig"import { Callback, EventEmitter } from "types-node.jsig"import { AThing, BThing } from "./other-file.jsig"import { AThing as BThing } from "./other-file.jsig"
A type expression is one of the following
- A builtin type
- A type literal
- An object literal
- A function expression
- A tuple literal
- A union expression
- A compound expression
- A string literal
- A null literal
- A undefined literal
- A numeric literal
- A boolean literal
There are a set of builtin types.
StringNumberBooleanObjectvoidAnyArrayErrorFunction
Every builtin type is a valid type expression.
Any JavaScript String value is of type String.
i.e. A value v is of type String if typeof v === 'string'.
Examples:
"foo"is of typeString.new String("foo")is not of typeString
Any JavaScript Number value is of type Number
i.e. A value v is of type Number if typeof v === 'number'
Examples:
42is of typeNumberInfinity,-Infinityis of typeNumberNaNis of typeNumbernew Number(0)is not of typeNumber
TODO
Any Javascript object is of type Object
i.e. A value v is of type Object if
typeof v === 'object' && v !== null
Examples:
{ foo: 'bar' }is of typeObject[1, 2, 3]is of typeObjectnew Object()is of typeObjectnullis not of typeObject
myThing : Object<String, T>
TODO
If something has no value then it is of type void.
In JavaScript the undefined value is of type void
i.e. A value v is of type void if v === void 0
Examples:
void 0is of typevoidundefinedis of typevoid(function () { /* no return statement */ }())is of typevoidnullis not of typevoid
Everything is of type Any
i.e. A value v is of type Any if true
Examples
undefinedis of typeAny"foo"is of typeAnynullis of typeAny{ foo: 50 }is of typeAny
Any javascript Array object is of type Array
i.e. A value v is of type Array if Array.isArray(v)
Examples:
[1, 2, 3]is of typeArraynew Array(10)is of typeArray{ length: 1, 1: 10 }is not of typeArray{ __proto__: Array.prototype }is not of typeArray
myThing : Array<T>
TODO
Any javascript Error object is of type Error
i.e. A value v is of type Error if
{}.toString.call(v) === '[object Error]'
Examples:
new Error("foo")is of typeErrorError("foo")is of typeError{ message: "foo" }is not of typeError
Any javascript function is of type Function
i.e. A value v is of type Function if typeof v === 'function'
Examples:
Object.prototype.toStringis of typeFunctionfunction () {}is of typeFunctionnew Function("return 42")is of typeFunction{ call: function () {} }is not of typeFunction
myThing : Function<Promise>
TODO
TODO
myThing : "foo"
TODO
myThing : null
TODO
myThing : undefined
TODO
myThing : 13
TODO
myThing : true
TODO
A type literal is a type name. All builtin types are type literals.
Any type literal that is not builtin in is a custom type.
Examples:
myThing : MyCustomType
It is expected that a custom type is either defined inside the file using a type declaration statement or is imported into the file using an import statement.
myThing : MyCustomType<T>
TODO
myThing : { foo: Number, bar: String }
TODO
myThing : (someStr: String) => Boolean
TODO
myThing : [Number, Number]
TODO
myThing : null | Object
TODO
myThing : { foo: String } & () => Boolean
TODO