From 6c53c2e108e6262fa44a0669e591d90a409df001 Mon Sep 17 00:00:00 2001 From: osyrisrblx Date: Wed, 31 Jul 2019 11:42:30 -0700 Subject: [PATCH 1/2] update t.literal --- lib/init.lua | 21 ++++++++--- lib/init.spec.lua | 21 +++++++++-- lib/t.d.ts | 94 +++++++++++++++++++++++++++-------------------- lib/ts.lua | 21 ++++++++--- 4 files changed, 104 insertions(+), 53 deletions(-) diff --git a/lib/init.lua b/lib/init.lua index f770b8b..5b571d1 100644 --- a/lib/init.lua +++ b/lib/init.lua @@ -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 diff --git a/lib/init.spec.lua b/lib/init.spec.lua index e91e170..e368afd 100644 --- a/lib/init.spec.lua +++ b/lib/init.spec.lua @@ -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")) diff --git a/lib/t.d.ts b/lib/t.d.ts index 6e09e5b..62114b6 100644 --- a/lib/t.d.ts +++ b/lib/t.d.ts @@ -4,85 +4,99 @@ type check = (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; /** checks to see if `value` is a boolean */ - boolean: (value: unknown) => value is boolean; + boolean: check; /** checks to see if `value` is a thread */ - coroutine: (value: unknown) => value is thread; + coroutine: check; /** checks to see if `value` is a Function */ - callback: (value: unknown) => value is Function; + callback: check; /** checks to see if `value` is undefined */ - none: (value: unknown) => value is undefined; + none: check; /** checks to see if `value` is a number, will _not_ match NaN */ - number: (value: unknown) => value is number; + number: check; /** checks to see if `value` is NaN */ - nan: (value: unknown) => value is number; + nan: check; /** checks to see if `value` is a string */ - string: (value: unknown) => value is string; + string: check; /** checks to see if `value` is an object */ - table: (value: unknown) => value is object; + table: check; /** checks to see if `value` is a userdata */ - userdata: (value: unknown) => value is object; + userdata: check; // roblox types /** checks to see if `value` is an Axes */ - Axes: (value: unknown) => value is Axes; + Axes: check; /** checks to see if `value` is a BrickColor */ - BrickColor: (value: unknown) => value is BrickColor; + BrickColor: check; /** checks to see if `value` is a CFrame */ - CFrame: (value: unknown) => value is CFrame; + CFrame: check; /** checks to see if `value` is a Color3 */ - Color3: (value: unknown) => value is Color3; + Color3: check; /** checks to see if `value` is a ColorSequence */ - ColorSequence: (value: unknown) => value is ColorSequence; + ColorSequence: check; /** checks to see if `value` is a ColorSequenceKeypoint */ - ColorSequenceKeypoint: (value: unknown) => value is ColorSequenceKeypoint; + ColorSequenceKeypoint: check; /** checks to see if `value` is a DockWidgetPluginGuiInfo */ - DockWidgetPluginGuiInfo: (value: unknown) => value is DockWidgetPluginGuiInfo; + DockWidgetPluginGuiInfo: check; /** checks to see if `value` is a Faces */ - Faces: (value: unknown) => value is Faces; + Faces: check; /** checks to see if `value` is an Instance */ - Instance: (value: unknown) => value is Instance; + Instance: check; /** checks to see if `value` is a NumberRange */ - NumberRange: (value: unknown) => value is NumberRange; + NumberRange: check; /** checks to see if `value` is a NumberSequence */ - NumberSequence: (value: unknown) => value is NumberSequence; + NumberSequence: check; /** checks to see if `value` is a NumberSequenceKeypoint */ - NumberSequenceKeypoint: (value: unknown) => value is NumberSequenceKeypoint; + NumberSequenceKeypoint: check; /** checks to see if `value` is a PathWaypoint */ - PathWaypoint: (value: unknown) => value is PathWaypoint; + PathWaypoint: check; /** checks to see if `value` is a PhysicalProperties */ - PhysicalProperties: (value: unknown) => value is PhysicalProperties; + PhysicalProperties: check; /** checks to see if `value` is a Random */ - Random: (value: unknown) => value is Random; + Random: check; /** checks to see if `value` is a Ray */ - Ray: (value: unknown) => value is Ray; + Ray: check; /** checks to see if `value` is a Rect */ - Rect: (value: unknown) => value is Rect; + Rect: check; /** checks to see if `value` is a Region3 */ - Region3: (value: unknown) => value is Region3; + Region3: check; /** checks to see if `value` is a Region3int16 */ - Region3int16: (value: unknown) => value is Region3int16; + Region3int16: check; /** checks to see if `value` is a TweenInfo */ - TweenInfo: (value: unknown) => value is TweenInfo; + TweenInfo: check; /** checks to see if `value` is a UDim */ - UDim: (value: unknown) => value is UDim; + UDim: check; /** checks to see if `value` is a UDim2 */ - UDim2: (value: unknown) => value is UDim2; + UDim2: check; /** checks to see if `value` is a Vector2 */ - Vector2: (value: unknown) => value is Vector2; + Vector2: check; /** checks to see if `value` is a Vector3 */ - Vector3: (value: unknown) => value is Vector3; + Vector3: check; /** checks to see if `value` is a Vector3int16 */ - Vector3int16: (value: unknown) => value is Vector3int16; + Vector3int16: check; /** - * checks to see if `value == literalValue`\ - * If your `literalValue` is not a primitive, use t.exactly instead. + * checks to see if `value == literalValue` */ - literal: (literalValue: T) => (value: unknown) => value is T; - /** checks to see if `value == literalValue` */ - exactly: (literalValue: T) => (value: unknown) => value is T; + literal(this: void, literalValue: T): check; + literal>( + this: void, + ...args: T + ): T extends [infer A] + ? (value: unknown) => value is A + : T extends [infer A, infer B] + ? check + : T extends [infer A, infer B, infer C] + ? check + : T extends [infer A, infer B, infer C, infer D] + ? check + : T extends [infer A, infer B, infer C, infer D, infer E] + ? check + : T extends [infer A, infer B, infer C, infer D, infer E, infer F] + ? check + : never; + literal(this: void, literalValue: T): (value: unknown) => value is T; /** checks to see if `value` is an integer */ integer: (value: unknown) => value is number; diff --git a/lib/ts.lua b/lib/ts.lua index 2c97127..f61fa9b 100644 --- a/lib/ts.lua +++ b/lib/ts.lua @@ -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 From b90d34be0f5059771724a141921e00ecea4b27a5 Mon Sep 17 00:00:00 2001 From: osyrisrblx Date: Wed, 31 Jul 2019 11:44:30 -0700 Subject: [PATCH 2/2] update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7a7d461..ef42b54 100644 --- a/README.md +++ b/README.md @@ -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`