Skip to content

Commit

Permalink
Merge branch 'master' of https://www.github.com/osyrisrblx/t
Browse files Browse the repository at this point in the history
  • Loading branch information
osyrisrblx committed Jul 31, 2019
2 parents de87a96 + 72c42bc commit c908fcb
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 55 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ The real power of t is in the meta type functions.
**`t.any`**\
Passes if value is non-nil.

**`t.literal(literalValue)`**\
Passes if value matches literalValue exactly.
**`t.literal(...)`**\
Passes if value matches any given value exactly.

**`t.optional(check)`**\
Passes if value is either nil or passes `check`
Expand Down
21 changes: 16 additions & 5 deletions lib/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -385,12 +385,23 @@ t.EnumItem = primitive("EnumItem")
@returns A function that will return true iff the condition is passed
**--]]
function t.literal(literal)
return function(value)
if value ~= literal then
return false, string.format("expected %s, got %s", tostring(literal), tostring(value))
function t.literal(...)
local size = select("#", ...)
if size == 1 then
local literal = ...
return function(value)
if value ~= literal then
return false, string.format("expected %s, got %s", tostring(literal), tostring(value))
end
return true
end
return true
else
local literals = {}
for i = 1, size do
local value = select(i, ...)
literals[i] = t.literal(value)
end
return t.union(unpack(literals))
end
end

Expand Down
21 changes: 18 additions & 3 deletions lib/init.spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,24 @@ return function()
assert(not (numberOrString(nil)))
end)

it("should support exact types", function()
local checkSingle = t.exactly("foo")
local checkUnion = t.union(t.exactly("foo"), t.exactly("bar"), t.exactly("oof"))
it("should support literal types", function()
local checkSingle = t.literal("foo")
local checkUnion = t.union(t.literal("foo"), t.literal("bar"), t.literal("oof"))

assert(checkSingle("foo"))
assert(checkUnion("foo"))
assert(checkUnion("bar"))
assert(checkUnion("oof"))

assert(not (checkSingle("FOO")))
assert(not (checkUnion("FOO")))
assert(not (checkUnion("BAR")))
assert(not (checkUnion("OOF")))
end)

it("should support multiple literal types", function()
local checkSingle = t.literal("foo")
local checkUnion = t.literal("foo", "bar", "oof")

assert(checkSingle("foo"))
assert(checkUnion("foo"))
Expand Down
94 changes: 54 additions & 40 deletions lib/t.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,85 +4,99 @@ type check<T> = (value: unknown) => value is T;
interface t {
// lua types
/** checks to see if `value` is an any */
any: (value: unknown) => value is any;
any: check<any>;
/** checks to see if `value` is a boolean */
boolean: (value: unknown) => value is boolean;
boolean: check<boolean>;
/** checks to see if `value` is a thread */
coroutine: (value: unknown) => value is thread;
coroutine: check<thread>;
/** checks to see if `value` is a Function */
callback: (value: unknown) => value is Function;
callback: check<Function>;
/** checks to see if `value` is undefined */
none: (value: unknown) => value is undefined;
none: check<undefined>;
/** checks to see if `value` is a number, will _not_ match NaN */
number: (value: unknown) => value is number;
number: check<number>;
/** checks to see if `value` is NaN */
nan: (value: unknown) => value is number;
nan: check<number>;
/** checks to see if `value` is a string */
string: (value: unknown) => value is string;
string: check<string>;
/** checks to see if `value` is an object */
table: (value: unknown) => value is object;
table: check<object>;
/** checks to see if `value` is a userdata */
userdata: (value: unknown) => value is object;
userdata: check<object>;

// roblox types
/** checks to see if `value` is an Axes */
Axes: (value: unknown) => value is Axes;
Axes: check<Axes>;
/** checks to see if `value` is a BrickColor */
BrickColor: (value: unknown) => value is BrickColor;
BrickColor: check<BrickColor>;
/** checks to see if `value` is a CFrame */
CFrame: (value: unknown) => value is CFrame;
CFrame: check<CFrame>;
/** checks to see if `value` is a Color3 */
Color3: (value: unknown) => value is Color3;
Color3: check<Color3>;
/** checks to see if `value` is a ColorSequence */
ColorSequence: (value: unknown) => value is ColorSequence;
ColorSequence: check<ColorSequence>;
/** checks to see if `value` is a ColorSequenceKeypoint */
ColorSequenceKeypoint: (value: unknown) => value is ColorSequenceKeypoint;
ColorSequenceKeypoint: check<ColorSequenceKeypoint>;
/** checks to see if `value` is a DockWidgetPluginGuiInfo */
DockWidgetPluginGuiInfo: (value: unknown) => value is DockWidgetPluginGuiInfo;
DockWidgetPluginGuiInfo: check<DockWidgetPluginGuiInfo>;
/** checks to see if `value` is a Faces */
Faces: (value: unknown) => value is Faces;
Faces: check<Faces>;
/** checks to see if `value` is an Instance */
Instance: (value: unknown) => value is Instance;
Instance: check<Instance>;
/** checks to see if `value` is a NumberRange */
NumberRange: (value: unknown) => value is NumberRange;
NumberRange: check<NumberRange>;
/** checks to see if `value` is a NumberSequence */
NumberSequence: (value: unknown) => value is NumberSequence;
NumberSequence: check<NumberSequence>;
/** checks to see if `value` is a NumberSequenceKeypoint */
NumberSequenceKeypoint: (value: unknown) => value is NumberSequenceKeypoint;
NumberSequenceKeypoint: check<NumberSequenceKeypoint>;
/** checks to see if `value` is a PathWaypoint */
PathWaypoint: (value: unknown) => value is PathWaypoint;
PathWaypoint: check<PathWaypoint>;
/** checks to see if `value` is a PhysicalProperties */
PhysicalProperties: (value: unknown) => value is PhysicalProperties;
PhysicalProperties: check<PhysicalProperties>;
/** checks to see if `value` is a Random */
Random: (value: unknown) => value is Random;
Random: check<Random>;
/** checks to see if `value` is a Ray */
Ray: (value: unknown) => value is Ray;
Ray: check<Ray>;
/** checks to see if `value` is a Rect */
Rect: (value: unknown) => value is Rect;
Rect: check<Rect>;
/** checks to see if `value` is a Region3 */
Region3: (value: unknown) => value is Region3;
Region3: check<Region3>;
/** checks to see if `value` is a Region3int16 */
Region3int16: (value: unknown) => value is Region3int16;
Region3int16: check<Region3int16>;
/** checks to see if `value` is a TweenInfo */
TweenInfo: (value: unknown) => value is TweenInfo;
TweenInfo: check<TweenInfo>;
/** checks to see if `value` is a UDim */
UDim: (value: unknown) => value is UDim;
UDim: check<UDim>;
/** checks to see if `value` is a UDim2 */
UDim2: (value: unknown) => value is UDim2;
UDim2: check<UDim2>;
/** checks to see if `value` is a Vector2 */
Vector2: (value: unknown) => value is Vector2;
Vector2: check<Vector2>;
/** checks to see if `value` is a Vector3 */
Vector3: (value: unknown) => value is Vector3;
Vector3: check<Vector3>;
/** checks to see if `value` is a Vector3int16 */
Vector3int16: (value: unknown) => value is Vector3int16;
Vector3int16: check<Vector3int16>;

/**
* checks to see if `value == literalValue`\
* If your `literalValue` is not a primitive, use t.exactly instead.
* checks to see if `value == literalValue`
*/
literal: <T extends string | number | boolean | undefined>(literalValue: T) => (value: unknown) => value is T;
/** checks to see if `value == literalValue` */
exactly: <T>(literalValue: T) => (value: unknown) => value is T;
literal<T extends string | number | boolean | undefined>(this: void, literalValue: T): check<T>;
literal<T extends Array<any>>(
this: void,
...args: T
): T extends [infer A]
? (value: unknown) => value is A
: T extends [infer A, infer B]
? check<A | B>
: T extends [infer A, infer B, infer C]
? check<A | B | C>
: T extends [infer A, infer B, infer C, infer D]
? check<A | B | C | D>
: T extends [infer A, infer B, infer C, infer D, infer E]
? check<A | B | C | D | E>
: T extends [infer A, infer B, infer C, infer D, infer E, infer F]
? check<A | B | C | D | E | F>
: never;
literal<T>(this: void, literalValue: T): (value: unknown) => value is T;

/** checks to see if `value` is an integer */
integer: (value: unknown) => value is number;
Expand Down
21 changes: 16 additions & 5 deletions lib/ts.lua
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,23 @@ t.Vector3int16 = primitive("Vector3int16")
t.Enum = primitive("Enum")
t.EnumItem = primitive("EnumItem")

function t.literal(literal)
return function(value)
if value ~= literal then
return false
function t.literal(...)
local size = select("#", ...)
if size == 1 then
local literal = ...
return function(value)
if value ~= literal then
return false
end
return true
end
return true
else
local literals = {}
for i = 1, size do
local value = select(i, ...)
literals[i] = t.literal(value)
end
return t.union(unpack(literals))
end
end

Expand Down

0 comments on commit c908fcb

Please sign in to comment.