Newtype is a programming language for type level programming in typescript.
Typescript has a powerful typesystem, so powerful that it's turing complete1. One is fully capable of writing a JSON parser 2 using only the type system, ignoring the question of if this is a good idea or not. In spite of this power, typescript's type system grammar is packed full of impicit rules 34, and becomes quite unweildy with any significant length.
git clone https://github.com/dkendal/newtype
cd newtype
stack build
stack install
Newtype borrows a good deal of syntax and ideas from Haskell and Idris. Statements are only allowed at the top of the document, not unlike typescript.
Primitive types are the same as in Typescript.
any
unknown
object
string
number
bigint
boolean
null
undefined
never
import "./foo-bar" (Foo, Bar)
Members are exported separately from their definition.
provide (Foo, Bar)
type True = true
interface ArrayBufferTypes where
ArrayBuffer : ArrayBuffer
Angle brackets and commas, and parens are omitted in newtype. Expressions may be parenthesized to disambiguate.
type Foo = Pick Bar "a" | "b"
type Foo = Pick<Bar, "a" | "b">
Mapped types5 use set builder notation6.
{ Value : Key <- Type }
?
replaces the infer
keyword.
?Type
Newtypes makes it much easier to write conditional types7
All expressions below compile to an equivalent typescript A extends B ? Then : Else
expression.
Newtype introduces a number of binary operators for type comparison.
A <: B
is equivalent toA extends B
, read as extends-left.A :> B
is equivalent toB extends A
, read as extends-right.A == B
A != B
It also introduces a single prefix operator to negate a condition
not A <: B
if A <: B
then C
else D
If the else
branch is omitted, it is assumed to be never
.
Expressions can be combined using and
, and or
.
if A <: B then if C <: D then E
Can be rewritten as:
type T =
if A <: B and C <: D
then E
Which is equivalent to:
type T = A extends B ? (C extends D ? E : never) : never;
type T =
case A of
string -> 1
object -> 2
_ -> never
Which is equivalent to:
type T = A extends string ? 1 : A extends object ? 2 : never;
Footnotes
-
https://github.com/jamiebuilds/json-parser-in-typescript-very-bad-idea-please-dont-use ↩
-
https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types ↩
-
Basically any question answered by the infamous and prolific jcalz has answered on Stackoverlow: https://stackoverflow.com/users/2887218/jcalz ↩
-
https://www.typescriptlang.org/docs/handbook/2/mapped-types.html ↩
-
https://en.wikipedia.org/wiki/Set-builder_notation#In_programming_languages ↩
-
https://www.typescriptlang.org/docs/handbook/2/conditional-types.html ↩