SimplyTyped
Yet another typing library.
This differs by aiming to be less experimental than others, driven by industry use cases.
Many of the exposed types are a very thin layer above built in functionality.
The goal is to provide all of the building blocks necessary to make concise, yet complex types.
Additionally packaged with this lib is a JSON-schema validator that will act as a type-guard for appropriately typed object.
Using this will mean run-time checking of user/network/external data, with compile time checking of logic flow.
The primary purpose of packaging the JSON-schema validator is as an example of complexity of types this library is able to specify.
In particular, this shows the library's solution to the conditional mapped types problem without overloading the global namespace.
npm install --save-dev simplytyped
Conditionals
If - And - Or - Not - Xor - Nand
Predicates
IsAny - IsArray - IsBoolean - IsFunction - IsNever - IsNumber - IsObject - IsType
Objects
Keys - ObjectType - CombineObjects - Intersect - SharedKeys - DiffKeys - AllKeys - Omit - Merge - Overwrite - DeepPartial - DeepReadonly - Optional - GetKey
Tuples
Tuple - UnionizeTuple - Length
Strings
Diff - StringEqual - DropString
Numbers
IsZero - IsOne - NumberToString - Next - Prev - Add - Sub - NumberEqual
Functions
Predicate - ConstructorFunction
Schema Validation
Conditionals
Some (somewhat common) implementations of conditional type logic
If
type x = If<True, string, number>
type y = If<False, string, number>
And
type x = If<And<True, True>, string, number>
type y = If<And<True, False>, string, number>
...
Or
type x = If<Or<True, False>, string, number>
type y = If<Or<False, False>, string, number>
...
Not
type x = Not<True>
type y = Not<False>
Xor
type x = Xor<True, False>
type y = Xor<True, True>
...
Nand
type x = Nand<True, True>
type y = Nand<False, True>
Predicates
IsAny
type x = IsAny<any>
type y = IsAny<'hey'>
IsArray
type x = IsArray<any[]>
type y = IsArray<number>
IsBoolean
type x = IsBoolean<false>
type y = IsBoolean<3>
IsFunction
type x = IsFunction<(() => string)>
type y = IsFunction<'not a function'>
IsNever
Returns true if type is never
, otherwise returns false.
type x = IsNever<'hi'>
type y = IsNever<never>
IsNumber
type x = IsNumber<3>
type y = IsNumber<false>
IsObject
type x = IsObject<{a: number, b: string}>
type y = IsObject<string>
IsType
Given a base type and a value, check to see if value matches the base type.
Useful for checking if something is an instance of a class.
class Thing { x: string };
type x = IsType<Thing, { x: string }>
type y = IsType<Thing, { y: number }>
Objects
type obj1 = { w: string, x: string, y: number }
type obj2 = { y: string, z: number }
Keys
No different than keyof
, but can look a bit nicer when nesting many types deep
type x = keyof obj1
type y = Keys<obj1>
ObjectType
On its own, not that interesting.
Takes an object and makes it an object type.
Is useful when combined with &
intersection types (as seen next).
type x = ObjectType<obj1>
CombineObjects
Takes the intersection between two objects, and flattens them.
This can make extremely complex types look much nicer.
type x = obj1 & obj2
type y = CombineObjects<obj1, obj2>
Intersect
Returns only the shared properties between two objects.
All shared properties must be the same type.
type x = Intersect<obj1, { x: string }>
SharedKeys
Gets all of the keys that are shared between two objects (as in keys in common).
type x = SharedKeys<obj1, obj2>
DiffKeys
Gets all of the keys that are different from obj1 to obj2.
type x = DiffKeys<obj1, obj2>
type y = DiffKeys<obj2, obj1>
AllKeys
Gets all keys between two objects.
type x = AllKeys<obj1, obj2>
Omit
Gives back an object with listed keys removed.
type x = Omit<obj1, 'w' | 'x'>
Merge
Much like _.merge
in javascript, this returns an object with all keys present between both objects, but conflicts resolved by rightmost object.
type x = Merge<obj1, obj2>
Overwrite
Can change the types of properties on an object.
This is similar to Merge
, except that it will not add previously non-existent properties to the object.
type a = Overwrite<obj1, obj2>
type b = Overwrite<obj2, obj1>
DeepPartial
Uses Partial
to make every parameter of an object optional (| undefined
).
type x = DeepPartial<obj1>
DeepReadonly
Uses Readonly
to make every parameter of an object readonly
type x = DeepReadonly<obj1>
Optional
Makes certain properties on an object optional.
type x = Optional<obj1, 'w' | 'x'>
GetKey
Gets the value of specified property on any object without compile time error (Property 'b' does not exist on type '{ a: string; }'.
) and the like.
Returns never
if the key is not on the object.
I suggest using If<HasKey...
first to handle validity of the object first.
type x = GetKey<{ a: string }, 'a'>
type y = GetKey<{ a: string }, 'b'>
Tuples
A tuple can be defined in two ways: [number, string]
which as of Typescript 2.7 has an enforced length type parameter: [number, string]['length'] === 2
or using this library's Tuple<any>
which can be extended with any length of tuple: function doStuff<T extends Tuple<any>>(x: T) {}
.
Tuple
function doStuff<T extends Tuple<any>>(x: T) {}
doStuff(['hi', 'there']);
UnionizeTuple
Returns elements within a tuple as a union.
type x = UnionizeTuple<[number, string]>
Length
Gets the length of either a built-in tuple, or a Vector.
This will only work after Typescript 2.7 is released.
type x = Length<['hey', 'there']>
Strings
Diff
Get the differences between two unions of strings.
type x = Diff<'hi' | 'there', 'hi' | 'friend'>
StringEqual
Returns true if all elements in two unions of strings are equal.
type x = StringEqual<'hi' | 'there', 'hi'>
type y = StringEqual<'hi' | 'there', 'there' | 'hi'>
DropString
Can remove a string from a union of strings
type x = DropString<'hi' | 'there', 'hi'>
Numbers
Supports numbers from [0, 63]. More slows down the compiler to a crawl right now.
IsZero
Returns true if the number is equal to zero.
type x = IsZero<1>
type y = IsZero<0>
IsOne
Returns true if the number is equal to one.
type x = IsOne<0>
type y = IsOne<1>
NumberToString
Returns the string type for a given number
type x = NumberToString<0>
type y = NumberToString<1>
Next
Returns the number + 1.
type x = Next<0>
type y = Next<22>
Prev
Returns the number - 1.
type x = Prev<0>
type y = Prev<23>
Add
Adds two numbers together.
type x = Add<22, 8>
Sub
Subtracts the second from the first.
type x = Sub<22, 8>
NumberEqual
Returns True
if the numbers are equivalent
type x = NumberEqual<0, 0>
type y = NumberEqual<22, 21>
Functions
Predicate
This is a function that takes some args and returns a boolean
type x = Predicate
const isThing: Predicate = (x: Thing) => x instanceof Thing;
ConstructorFunction
This represents the constructor for a particular object.
class Thing { constructor(public x: string) {}}
type x = ConstructorFunction<Thing>
declare const construct: x;
const y = new construct();
Schema Validation
One of the easiest points of failure with the typescript type system is outside data.
It is difficult to confirm that outside data matches the contract we have set within our typings.
Using the common JSON-schema specification, we can check the validity of our runtime objects, while still having compile checking of logic validity.
If we define our schemas as so:
const schema = {
type: 'object' as 'object',
properties: {
prop: {
type: 'string' as 'string'
}
}
}
then pass in data:
const runtimeData: any = {
prop: 'hello world'
};
then schemaIsValid(data, schema)
will give both compile time and run time checking of types.
if (schemaIsValid(data, schema)) {
type x = typeof data;
} else {
throw new Error('Uh-oh, you gave me ill-formatted data!!');
}