From 6801c65090daeb7f82e5e6d84e25213926b97a9c Mon Sep 17 00:00:00 2001 From: vegorov-rbx <75688451+vegorov-rbx@users.noreply.github.com> Date: Tue, 30 Nov 2021 14:00:23 -0800 Subject: [PATCH] Documentation for type packs (#257) * Documentation for type packs * Update docs/_pages/typecheck.md Co-authored-by: Arseny Kapoulkine * Add a note about the difference between ...T and T... Fix a typo at the start as well. Co-authored-by: Arseny Kapoulkine --- docs/_pages/typecheck.md | 60 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/docs/_pages/typecheck.md b/docs/_pages/typecheck.md index 58e66bb..3580d66 100644 --- a/docs/_pages/typecheck.md +++ b/docs/_pages/typecheck.md @@ -287,6 +287,66 @@ In type annotations, this is written as `...T`: type F = (...number) -> ...string ``` +## Type packs + +Multiple function return values as well as the function variadic parameter use a type pack to represent a list of types. + +When a type alias is defined, generic type pack parameters can be used after the type parameters: + +```lua +type Signal = { f: (T, U...) -> (), data: T } +``` + +> Keep in mind that `...T` is a variadic type pack (many elements of the same type `T`), while `U...` is a generic type pack that can contain zero or more types and they don't have to be the same. + +It is also possible for a generic function to reference a generic type pack from the generics list: + +```lua +local function call(s: Signal, ...: U...) + s.f(s.data, ...) +end +``` + +Generic types with type packs can be instantiated by providing a type pack: + +```lua +local signal: Signal = -- + +call(signal, 1, 2, false) +``` + +There are also other ways to instantiate types with generic type pack parameters: + +```lua +type A = (T) -> U... + +type B = A -- with a variadic type pack +type C = A -- with a generic type pack +type D = A -- with an empty type pack +``` + +Trailing type pack argument can also be provided without parentheses by specifying variadic type arguments: + +```lua +type List = (Head, Rest...) -> () + +type B = List -- Rest... is () +type C = List -- Rest is (string, boolean) + +type Returns = () -> T... + +-- When there are no type parameters, the list can be left empty +type D = Returns<> -- T... is () +``` + +Type pack parameters are not limited to a single one, as many as required can be specified: + +```lua +type Callback = { f: (Args...) -> Rets... } + +type A = Callback<(number, string), ...number> +``` + ## Typing idiomatic OOP One common pattern we see throughout Roblox is this OOP idiom. A downside with this pattern is that it does not automatically create a type binding for an instance of that class, so one has to write `type Account = typeof(Account.new("", 0))`.