From 686a250c1a8c92b100e84f39c630de0c812f31ef Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 11 May 2026 21:12:57 +0200 Subject: [PATCH 01/33] Create syntax-type-labels.md --- docs/syntax-type-labels.md | 157 +++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 docs/syntax-type-labels.md diff --git a/docs/syntax-type-labels.md b/docs/syntax-type-labels.md new file mode 100644 index 00000000..ec0a248c --- /dev/null +++ b/docs/syntax-type-labels.md @@ -0,0 +1,157 @@ +# Syntax Type Labels + +## Summary + +Syntax type labels intended for generic types, allowing users to attach parameter names to types for use in argument types. +This is to improve IntelliSense and autocomplete, and allows custom callbacks to show you argument names, instead of just the type. + +## Motivation + +Currently, you can only provide argument names in a type by doing the following. + +```luau +type Callback = (x: number, y: number, z: number) -> () + +local cb: Callback = function() + --[[ + IntelliSense shows you cb: (x: number, y: number, z: number) -> (). + Luau Playground just shows cb: (number, number, number) -> () + --]] +end +``` + +But here in this case, a developer would immediately know what each of these type _represents_. In this case ``x``, ``y`` and ``z``. + +Luau and any embedder internally in the implementation, is able to define argument names in some way or another. +But a developer is not able to replicate everything from the implementation itself. + +
+ +Generic packs exist + +```luau +type WrappedSignal = { + FireToFoo: (self: WrappedSignal, targetFoo: Foo, T...) -> (), +} + +type MySignal = WrappedSignal +``` + +But in this case, the result of ``MySignal.FireToFoo`` would show up as: +```luau +(WrappedSignal, Foo, number, string) +-- or +(self: WrappedSignal, targetFoo: Foo, number, string) +``` +without any context or indication on what these provided types ``(number, string)`` are meant to re-present. + +But you can see that ``targetFoo: Foo`` is present, but only because function annotations specifically let you describe argument names, which APIs can pick-up on. + +
+ +Luau already allows you to provide parameter names. + +```luau +(x: number) -> () +``` + +But when generic types are used, this information is no longer available + +```luau +type Callback = (T...) -> () +``` + +``T...`` will only emit over types but not labels. + +And currently, there isn't even syntax to provide a label when using ``Callback`` + + + +Why are we doing this? What use cases does it support? What is the expected outcome? + +## Design + +**Syntax Type Labels**, allowing users to provide semantics onto types, +useful for IntelliSense and autocomplete, even for debug tooling within the internals of the language itself. +_(a bit similar to TypeScript)_ + +Labels are only metadata: +- Labels are NOT enforced in any type checking way +- They don't affect the type itself +- They only improve front-end hints + + +Type Labels are intended to be used while providing types into generics. +```luau +type Callback = (T...) -> () + +function Foo(cb: Callback<[targetBar: Bar]> end +-- cb shows (targetBar: Bar) -> () +``` + +### Syntax: +- Type Label Syntax is wrapped around these brackets ``[]``. +- They can contain a label through ``[label: type]``, but is optional +- ``[number]`` would just be ``number`` +- ``[x: number]`` would just be ``number``, with a label ``"x"`` +- Multiple types can appear in it by separating with ``,`` + - ``[x: number, y: number] + - but this is also fine ``[x: number], [y: number]`` + +Multiple types can only appear if multiple types are even allowed to be provided. +```luau +type Foo = (T...) -> () +type Bar = (T) -> () + +type A = Foo<[a: number, number, label: number]> -- allowed +type B = Foo<[x: number], [y: number]> -- allowed + +type C = Bar<[x: number, y: number]> -- Error: More than one type! +``` + +
+### Usage: + +```luau +type WrappedSignal = { + FireToFoo: (self: WrappedSignal, targetFoo: Foo, T...) -> (), +} + +type MySignal = WrappedSignal<[amount: number, message: string]> + +--[[ + MySignal.FireToFoo would become + (self: WrappedSignal, targetFoo: Foo, amount: number, message: string) -> () +]] +``` + +Nothing changes about the types own identity, it just gets associated with metadata. + +
+ + +In TypeScript you can do +```ts +type Position = [x: number, y: number, z: number] +``` +Luau does NOT support typing tuples in this context, so doing the above in Luau, would error. + + + +## Drawbacks + +- A new syntax has to be introduced. Another question would be whether "labels" will be the only thing, or whether there will be more. +- Whether syntax should be ``[x: number, y: number, z: number]`` or ``[x: number], [y: number], [z: number]`` +- ``[]`` are used by table keys and indexing, or _"arrays"_ in other languages. + +## Alternatives + +Type functions could expose modifying argument names, but that would only work for function annotations, not on a type alone. +There wouldn't be a way to attach a label to a type. + +```luau +type WrappedSignal = { FireToFoo: (self: WrappedSignal, targetFoo: Foo, T...) -> (); } +type MySignal = WrappedSignal<(label1: number, label2: string) -> ()> +``` +And this would also mean that ``WrappedSignal`` needs to implement a type function now, that takes out the argument names and transforms ``.FireToFoo``. +And that sounds too complicated. From 3437c5aa38c84c35a5574ce96e1e10f133713788 Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 11 May 2026 21:16:06 +0200 Subject: [PATCH 02/33] Update syntax-type-labels.md --- docs/syntax-type-labels.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/syntax-type-labels.md b/docs/syntax-type-labels.md index ec0a248c..d5e62811 100644 --- a/docs/syntax-type-labels.md +++ b/docs/syntax-type-labels.md @@ -3,7 +3,7 @@ ## Summary Syntax type labels intended for generic types, allowing users to attach parameter names to types for use in argument types. -This is to improve IntelliSense and autocomplete, and allows custom callbacks to show you argument names, instead of just the type. +This is to improve IntelliSense and autocomplete, and allows custom callbacks to show you argument names instead of just the type. ## Motivation @@ -14,15 +14,17 @@ type Callback = (x: number, y: number, z: number) -> () local cb: Callback = function() --[[ - IntelliSense shows you cb: (x: number, y: number, z: number) -> (). - Luau Playground just shows cb: (number, number, number) -> () + IntelliSense shows you + cb: (x: number, y: number, z: number) -> (). + Luau Playground just shows + cb: (number, number, number) -> () --]] end ``` But here in this case, a developer would immediately know what each of these type _represents_. In this case ``x``, ``y`` and ``z``. -Luau and any embedder internally in the implementation, is able to define argument names in some way or another. +Luau and any embedder internally within the implementation are able to define argument names in some way or another to types _procedurally_. But a developer is not able to replicate everything from the implementation itself.
From 00dcb1df1626ad8334d876ffdae8df3329aebec5 Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 11 May 2026 21:18:32 +0200 Subject: [PATCH 03/33] Update syntax-type-labels.md --- docs/syntax-type-labels.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/syntax-type-labels.md b/docs/syntax-type-labels.md index d5e62811..b140d127 100644 --- a/docs/syntax-type-labels.md +++ b/docs/syntax-type-labels.md @@ -157,3 +157,8 @@ type MySignal = WrappedSignal<(label1: number, label2: string) -> ()> ``` And this would also mean that ``WrappedSignal`` needs to implement a type function now, that takes out the argument names and transforms ``.FireToFoo``. And that sounds too complicated. + +You don't want it to be + +You don't want it to be ``(targetFoo: Foo: Player, (label1: number, label2: string) -> ()) -> ()`` +you want ``(targetFoo: Foo: Player, label1: number, label2: string) -> ()``. From 4db2f21ea552d23d49c09d8db928fb4021d621f8 Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 11 May 2026 21:19:49 +0200 Subject: [PATCH 04/33] Update syntax-type-labels.md --- docs/syntax-type-labels.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/syntax-type-labels.md b/docs/syntax-type-labels.md index b140d127..0c3ef406 100644 --- a/docs/syntax-type-labels.md +++ b/docs/syntax-type-labels.md @@ -112,8 +112,8 @@ type C = Bar<[x: number, y: number]> -- Error: More than one type! ```
-### Usage: +### Usage: ```luau type WrappedSignal = { FireToFoo: (self: WrappedSignal, targetFoo: Foo, T...) -> (), From 56a0de779af879251d2ff063d965490915456f32 Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 11 May 2026 21:21:01 +0200 Subject: [PATCH 05/33] Update syntax-type-labels.md --- docs/syntax-type-labels.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/syntax-type-labels.md b/docs/syntax-type-labels.md index 0c3ef406..6ccfb473 100644 --- a/docs/syntax-type-labels.md +++ b/docs/syntax-type-labels.md @@ -160,5 +160,5 @@ And that sounds too complicated. You don't want it to be -You don't want it to be ``(targetFoo: Foo: Player, (label1: number, label2: string) -> ()) -> ()`` +You don't want it to be ``( targetFoo: Foo: Player, (label1: number, label2: string) -> () ) -> ()`` you want ``(targetFoo: Foo: Player, label1: number, label2: string) -> ()``. From a6a30cc302829e2076026883728acedff6794ef6 Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 11 May 2026 21:26:07 +0200 Subject: [PATCH 06/33] Update syntax-type-labels.md --- docs/syntax-type-labels.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/syntax-type-labels.md b/docs/syntax-type-labels.md index 6ccfb473..fc0f2c31 100644 --- a/docs/syntax-type-labels.md +++ b/docs/syntax-type-labels.md @@ -160,5 +160,5 @@ And that sounds too complicated. You don't want it to be -You don't want it to be ``( targetFoo: Foo: Player, (label1: number, label2: string) -> () ) -> ()`` +You want it to be ``( targetFoo: Foo: Player, (label1: number, label2: string) -> () ) -> ()`` you want ``(targetFoo: Foo: Player, label1: number, label2: string) -> ()``. From bdf60978697d22f0d8b488e4ccce8d1f65ff5d59 Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 11 May 2026 23:22:32 +0200 Subject: [PATCH 07/33] Update and rename syntax-type-labels.md to type-pack-names.md --- ...ntax-type-labels.md => type-pack-names.md} | 56 +++++++++---------- 1 file changed, 25 insertions(+), 31 deletions(-) rename docs/{syntax-type-labels.md => type-pack-names.md} (62%) diff --git a/docs/syntax-type-labels.md b/docs/type-pack-names.md similarity index 62% rename from docs/syntax-type-labels.md rename to docs/type-pack-names.md index fc0f2c31..f25f29e2 100644 --- a/docs/syntax-type-labels.md +++ b/docs/type-pack-names.md @@ -1,9 +1,9 @@ -# Syntax Type Labels +# Names in Type Packs ## Summary -Syntax type labels intended for generic types, allowing users to attach parameter names to types for use in argument types. -This is to improve IntelliSense and autocomplete, and allows custom callbacks to show you argument names instead of just the type. +Allowing users to always provide names within type packs, such as ``(x: number)`` syntax, would allow users to attach parameter names to a within a type pack. +This improves IntelliSense and autocomplete, and allows custom callbacks to show you argument names instead of just the type. ## Motivation @@ -73,42 +73,35 @@ Why are we doing this? What use cases does it support? What is the expected outc ## Design -**Syntax Type Labels**, allowing users to provide semantics onto types, -useful for IntelliSense and autocomplete, even for debug tooling within the internals of the language itself. -_(a bit similar to TypeScript)_ +This syntax here ``(number)`` is a type pack. -Labels are only metadata: -- Labels are NOT enforced in any type checking way +And the idea is to allow to provide names in any type pack syntax. + +e.g. allowing you to do ``(x: number)`` without being exclusively restricted to function annotations anymore. + +Names/Labels are only metadata: +- Names/Labels are NOT enforced in any type checking way - They don't affect the type itself - They only improve front-end hints -Type Labels are intended to be used while providing types into generics. +### Example: + ```luau type Callback = (T...) -> () -function Foo(cb: Callback<[targetBar: Bar]> end +function Foo(cb: Callback<(targetBar: Bar)> end -- cb shows (targetBar: Bar) -> () ``` -### Syntax: -- Type Label Syntax is wrapped around these brackets ``[]``. -- They can contain a label through ``[label: type]``, but is optional -- ``[number]`` would just be ``number`` -- ``[x: number]`` would just be ``number``, with a label ``"x"`` -- Multiple types can appear in it by separating with ``,`` - - ``[x: number, y: number] - - but this is also fine ``[x: number], [y: number]`` - -Multiple types can only appear if multiple types are even allowed to be provided. ```luau type Foo = (T...) -> () type Bar = (T) -> () -type A = Foo<[a: number, number, label: number]> -- allowed -type B = Foo<[x: number], [y: number]> -- allowed +type A = Foo<(a: number, number, label: number)> -- allowed +type B = Foo<(x: number), (y: number)> -- allowed -type C = Bar<[x: number, y: number]> -- Error: More than one type! +type C = Bar<(x: number, y: number)> -- Error: More than one type! ```
@@ -119,7 +112,7 @@ type WrappedSignal = { FireToFoo: (self: WrappedSignal, targetFoo: Foo, T...) -> (), } -type MySignal = WrappedSignal<[amount: number, message: string]> +type MySignal = WrappedSignal<(amount: number, message: string)> --[[ MySignal.FireToFoo would become @@ -132,22 +125,23 @@ Nothing changes about the types own identity, it just gets associated with metad
-In TypeScript you can do -```ts -type Position = [x: number, y: number, z: number] +```luau +type MyNumber = (x: number) +type Func = () -> (x: number, y: number, z: number) ``` -Luau does NOT support typing tuples in this context, so doing the above in Luau, would error. + ## Drawbacks -- A new syntax has to be introduced. Another question would be whether "labels" will be the only thing, or whether there will be more. -- Whether syntax should be ``[x: number, y: number, z: number]`` or ``[x: number], [y: number], [z: number]`` -- ``[]`` are used by table keys and indexing, or _"arrays"_ in other languages. +- Most likely none, other than the implementation. + ## Alternatives +- A new syntax where it would be ``[x: number, y: number, z: number]`` or ``[x: number], [y: number], [z: number]`` + Type functions could expose modifying argument names, but that would only work for function annotations, not on a type alone. There wouldn't be a way to attach a label to a type. From f3cc11d61697b2ef43333848d370c062189bdfbf Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 11 May 2026 23:23:45 +0200 Subject: [PATCH 08/33] Update type-pack-names.md --- docs/type-pack-names.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index f25f29e2..c8a8f98a 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -141,8 +141,9 @@ type Func = () -> (x: number, y: number, z: number) ## Alternatives - A new syntax where it would be ``[x: number, y: number, z: number]`` or ``[x: number], [y: number], [z: number]`` +
-Type functions could expose modifying argument names, but that would only work for function annotations, not on a type alone. +- Type functions could expose modifying argument names, but that would only work for function annotations, not on a type alone. There wouldn't be a way to attach a label to a type. ```luau @@ -152,7 +153,7 @@ type MySignal = WrappedSignal<(label1: number, label2: string) -> ()> And this would also mean that ``WrappedSignal`` needs to implement a type function now, that takes out the argument names and transforms ``.FireToFoo``. And that sounds too complicated. -You don't want it to be -You want it to be ``( targetFoo: Foo: Player, (label1: number, label2: string) -> () ) -> ()`` -you want ``(targetFoo: Foo: Player, label1: number, label2: string) -> ()``. +You don't want it to be ``( targetFoo: Foo: Player, (label1: number, label2: string) -> () ) -> ()`` + +You want ``(targetFoo: Foo: Player, label1: number, label2: string) -> ()``. From b01e5fe4dc3dba42f6cedbd137e42061625edbc4 Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 11 May 2026 23:24:22 +0200 Subject: [PATCH 09/33] Update type-pack-names.md --- docs/type-pack-names.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index c8a8f98a..45a338de 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -63,7 +63,7 @@ But when generic types are used, this information is no longer available type Callback = (T...) -> () ``` -``T...`` will only emit over types but not labels. +``T...`` will only emit over types but not any names/labels. And currently, there isn't even syntax to provide a label when using ``Callback`` From 24c7e4531becea30fc8961629da733ef57f361ce Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 11 May 2026 23:29:29 +0200 Subject: [PATCH 10/33] Update type-pack-names.md --- docs/type-pack-names.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index 45a338de..02999d0c 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -130,6 +130,15 @@ type MyNumber = (x: number) type Func = () -> (x: number, y: number, z: number) ``` +In the event where an annotation already has a name. The name would get overwritten if... +```luau +type Foo = (args: T...) -> () +type Bar = (arg: T) -> () + +type A = Foo<(number, number)> -- nothing changes +type B = Foo<(x: number, y: number)> -- "args" would be gone if something substituted a generic +type C = Foo<(x: number)> -- same here for "arg +``` @@ -137,6 +146,9 @@ type Func = () -> (x: number, y: number, z: number) - Most likely none, other than the implementation. +- We have to ask ourselves what would happen to this + + ## Alternatives From f550335930a620c6f830c7a6cf1a8247a0b5a616 Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 11 May 2026 23:31:10 +0200 Subject: [PATCH 11/33] Update type-pack-names.md --- docs/type-pack-names.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index 02999d0c..90c37432 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -133,11 +133,11 @@ type Func = () -> (x: number, y: number, z: number) In the event where an annotation already has a name. The name would get overwritten if... ```luau type Foo = (args: T...) -> () -type Bar = (arg: T) -> () +type Foo_2 = (arg: T) -> () type A = Foo<(number, number)> -- nothing changes -type B = Foo<(x: number, y: number)> -- "args" would be gone if something substituted a generic -type C = Foo<(x: number)> -- same here for "arg +type A = Foo<(x: number, y: number)> -- "args" would be gone if something substituted a generic +type C = Foo_2<(x: number)> -- same here for "arg" ``` @@ -145,9 +145,7 @@ type C = Foo<(x: number)> -- same here for "arg ## Drawbacks - Most likely none, other than the implementation. - -- We have to ask ourselves what would happen to this - +- Whether argument names ## Alternatives From cf211c37ff815198d6fb291f7f9da04b7d71f2f3 Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 11 May 2026 23:32:35 +0200 Subject: [PATCH 12/33] Update type-pack-names.md --- docs/type-pack-names.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index 90c37432..2533528d 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -135,7 +135,7 @@ In the event where an annotation already has a name. The name would get overwrit type Foo = (args: T...) -> () type Foo_2 = (arg: T) -> () -type A = Foo<(number, number)> -- nothing changes +type A = Foo<(number, number)> -- nothing changes about "args" type A = Foo<(x: number, y: number)> -- "args" would be gone if something substituted a generic type C = Foo_2<(x: number)> -- same here for "arg" ``` From 45ca6ee796957b359734dd4da9c5f5316b447976 Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 11 May 2026 23:38:00 +0200 Subject: [PATCH 13/33] Update type-pack-names.md --- docs/type-pack-names.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index 2533528d..3f964077 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -145,7 +145,7 @@ type C = Foo_2<(x: number)> -- same here for "arg" ## Drawbacks - Most likely none, other than the implementation. -- Whether argument names +- Whether ``(arg: T)`` should have ``"arg"`` replaced or not, if substituted by ``(x: number)``. ## Alternatives From 563c964669ff24eb100450279cc0aafcee6bdb2c Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 11 May 2026 23:38:33 +0200 Subject: [PATCH 14/33] Update type-pack-names.md --- docs/type-pack-names.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index 3f964077..5beff053 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -22,7 +22,7 @@ local cb: Callback = function() end ``` -But here in this case, a developer would immediately know what each of these type _represents_. In this case ``x``, ``y`` and ``z``. +But in the IntelliSense case, a developer would immediately know what each of these type _represents_. In this case ``x``, ``y`` and ``z``. Luau and any embedder internally within the implementation are able to define argument names in some way or another to types _procedurally_. But a developer is not able to replicate everything from the implementation itself. From 55969e99985ece9341f33b7053ba862dfc6ee5c5 Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 11 May 2026 23:42:59 +0200 Subject: [PATCH 15/33] Update type-pack-names.md --- docs/type-pack-names.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index 5beff053..79e69ed9 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -102,6 +102,7 @@ type A = Foo<(a: number, number, label: number)> -- allowed type B = Foo<(x: number), (y: number)> -- allowed type C = Bar<(x: number, y: number)> -- Error: More than one type! +type D = (num: number) -> () -- Already works in Luau, no changes! ```
From e6048bbe1057fb7253cf66197e5911d6500b19f0 Mon Sep 17 00:00:00 2001 From: karl-police Date: Mon, 11 May 2026 23:47:06 +0200 Subject: [PATCH 16/33] Update type-pack-names.md --- docs/type-pack-names.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index 79e69ed9..647d1554 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -85,7 +85,7 @@ Names/Labels are only metadata: - They only improve front-end hints -### Example: +### Usage and Examples: ```luau type Callback = (T...) -> () @@ -107,7 +107,6 @@ type D = (num: number) -> () -- Already works in Luau, no changes!
-### Usage: ```luau type WrappedSignal = { FireToFoo: (self: WrappedSignal, targetFoo: Foo, T...) -> (), @@ -129,6 +128,9 @@ Nothing changes about the types own identity, it just gets associated with metad ```luau type MyNumber = (x: number) type Func = () -> (x: number, y: number, z: number) +function Func2(): (a: number, b: number, c: number) + return 1,2,3 +end ``` In the event where an annotation already has a name. The name would get overwritten if... From 06fc7021538ded8342d88f0e6e62f734c4747f9b Mon Sep 17 00:00:00 2001 From: karl-police Date: Tue, 12 May 2026 00:03:16 +0200 Subject: [PATCH 17/33] Update type-pack-names.md --- docs/type-pack-names.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index 647d1554..25cdb575 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -133,14 +133,13 @@ function Func2(): (a: number, b: number, c: number) end ``` -In the event where an annotation already has a name. The name would get overwritten if... +In the event where an annotation already has a name, we will keep the name if possible. ```luau -type Foo = (args: T...) -> () -type Foo_2 = (arg: T) -> () +type Foo = (arg: T) -> () +type A = Foo<(x: number)> -- "arg" stays. -type A = Foo<(number, number)> -- nothing changes about "args" -type A = Foo<(x: number, y: number)> -- "args" would be gone if something substituted a generic -type C = Foo_2<(x: number)> -- same here for "arg" +type Foo = (T) -> () +type A = Foo<(x: number)> -- "T" had no name, so it gets given one! ``` From 595860bf533c2c5546b776ee044bcbac33115ad7 Mon Sep 17 00:00:00 2001 From: karl-police Date: Tue, 12 May 2026 00:22:47 +0200 Subject: [PATCH 18/33] Update type-pack-names.md --- docs/type-pack-names.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index 25cdb575..cc02532c 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -94,12 +94,15 @@ function Foo(cb: Callback<(targetBar: Bar)> end -- cb shows (targetBar: Bar) -> () ``` + + ```luau type Foo = (T...) -> () type Bar = (T) -> () type A = Foo<(a: number, number, label: number)> -- allowed -type B = Foo<(x: number), (y: number)> -- allowed +type B = Foo<(x: number), (y: number)> -- not valid +type B = Foo<(x: number, y: number)> -- valid type C = Bar<(x: number, y: number)> -- Error: More than one type! type D = (num: number) -> () -- Already works in Luau, no changes! @@ -144,6 +147,7 @@ type A = Foo<(x: number)> -- "T" had no name, so it gets given one! + ## Drawbacks - Most likely none, other than the implementation. From 53399b75cb3edfd8db78c47b59cd0f9c48659b9d Mon Sep 17 00:00:00 2001 From: karl-police Date: Tue, 12 May 2026 00:25:10 +0200 Subject: [PATCH 19/33] Update type-pack-names.md --- docs/type-pack-names.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index cc02532c..762ce904 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -136,14 +136,6 @@ function Func2(): (a: number, b: number, c: number) end ``` -In the event where an annotation already has a name, we will keep the name if possible. -```luau -type Foo = (arg: T) -> () -type A = Foo<(x: number)> -- "arg" stays. - -type Foo = (T) -> () -type A = Foo<(x: number)> -- "T" had no name, so it gets given one! -``` @@ -154,6 +146,13 @@ type A = Foo<(x: number)> -- "T" had no name, so it gets given one! - Whether ``(arg: T)`` should have ``"arg"`` replaced or not, if substituted by ``(x: number)``. +We can't rename ``T`` here +```luau +type Foo = (arg: T) -> () +type A = Foo<(x: number)> -- (x: number), does not count as a type pack +``` + + ## Alternatives - A new syntax where it would be ``[x: number, y: number, z: number]`` or ``[x: number], [y: number], [z: number]`` From b4842681e2dfe346d366fc35e0ccff306eb50678 Mon Sep 17 00:00:00 2001 From: karl-police Date: Tue, 12 May 2026 00:28:48 +0200 Subject: [PATCH 20/33] Update type-pack-names.md --- docs/type-pack-names.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index 762ce904..8b153eb7 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -102,9 +102,8 @@ type Bar = (T) -> () type A = Foo<(a: number, number, label: number)> -- allowed type B = Foo<(x: number), (y: number)> -- not valid -type B = Foo<(x: number, y: number)> -- valid +type C = Foo<(x: number, y: number)> -- valid -type C = Bar<(x: number, y: number)> -- Error: More than one type! type D = (num: number) -> () -- Already works in Luau, no changes! ``` @@ -150,6 +149,10 @@ We can't rename ``T`` here ```luau type Foo = (arg: T) -> () type A = Foo<(x: number)> -- (x: number), does not count as a type pack + +-- Not possible! +type Bar = (T,U) -> () +local e: Bar<(x: number, y: number)> ``` From 5411925f92f54d07b5a1c317896c913d50ff0fae Mon Sep 17 00:00:00 2001 From: karl-police Date: Tue, 12 May 2026 00:38:23 +0200 Subject: [PATCH 21/33] Update type-pack-names.md --- docs/type-pack-names.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index 8b153eb7..0825ec84 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -105,6 +105,7 @@ type B = Foo<(x: number), (y: number)> -- not valid type C = Foo<(x: number, y: number)> -- valid type D = (num: number) -> () -- Already works in Luau, no changes! +type E = Bar<(num: number)> -- not valid because no type pack here! ```
From e6e7db5717e53049cbd89e2c5fd712dbc4d85e3c Mon Sep 17 00:00:00 2001 From: karl-police Date: Tue, 12 May 2026 02:00:30 +0200 Subject: [PATCH 22/33] Update type-pack-names.md --- docs/type-pack-names.md | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index 0825ec84..c201bddb 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -2,7 +2,7 @@ ## Summary -Allowing users to always provide names within type packs, such as ``(x: number)`` syntax, would allow users to attach parameter names to a within a type pack. +Allowing users to always provide names within type packs ``(T...)``, so that parameter names can be attached to types. This improves IntelliSense and autocomplete, and allows custom callbacks to show you argument names instead of just the type. ## Motivation @@ -51,25 +51,20 @@ But you can see that ``targetFoo: Foo`` is present, but only because function an
-Luau already allows you to provide parameter names. - +Luau already allows you to provide parameter names within function annotations. ```luau (x: number) -> () ``` -But when generic types are used, this information is no longer available - +But when generic type packs are used, this information is no longer available. ```luau type Callback = (T...) -> () ``` ``T...`` will only emit over types but not any names/labels. -And currently, there isn't even syntax to provide a label when using ``Callback`` - - +And currently, there isn't a way to provide a name/label when using ``Callback`` -Why are we doing this? What use cases does it support? What is the expected outcome? ## Design From 6ec0004b4529580f9f4c2035622a32fab858b32e Mon Sep 17 00:00:00 2001 From: karl-police Date: Tue, 12 May 2026 02:01:59 +0200 Subject: [PATCH 23/33] Update type-pack-names.md --- docs/type-pack-names.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index c201bddb..0c3c6439 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -68,11 +68,10 @@ And currently, there isn't a way to provide a name/label when using ``Callback`` if ``Type`` without being exclusively restricted to function annotations anymore. Names/Labels are only metadata: - Names/Labels are NOT enforced in any type checking way From 18eb18457956221bfe9076984b70741682cc5e71 Mon Sep 17 00:00:00 2001 From: karl-police Date: Tue, 12 May 2026 02:06:31 +0200 Subject: [PATCH 24/33] Update type-pack-names.md --- docs/type-pack-names.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index 0c3c6439..766cc44a 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -71,14 +71,13 @@ And currently, there isn't a way to provide a name/label when using ``Callback`` if ``Type`` without being exclusively restricted to function annotations anymore. +Allowing you to do ``Type<(x: number)>`` if the base is ``Type`` without being exclusively restricted to function annotations anymore. Names/Labels are only metadata: - Names/Labels are NOT enforced in any type checking way - They don't affect the type itself - They only improve front-end hints - ### Usage and Examples: ```luau @@ -88,18 +87,22 @@ function Foo(cb: Callback<(targetBar: Bar)> end -- cb shows (targetBar: Bar) -> () ``` +```luau +type Bar = (T) -> () +type A = Bar<(num: number)> -- not valid (T) is not a type pack! +type MyNumber = (num: number) -- not valid not a type pack! +``` ```luau type Foo = (T...) -> () -type Bar = (T) -> () type A = Foo<(a: number, number, label: number)> -- allowed type B = Foo<(x: number), (y: number)> -- not valid type C = Foo<(x: number, y: number)> -- valid -type D = (num: number) -> () -- Already works in Luau, no changes! -type E = Bar<(num: number)> -- not valid because no type pack here! +type D = (num: number) -> () -- already works in Luau, no changes! +type E = () -> (num: number) -- valid! ```
@@ -123,7 +126,6 @@ Nothing changes about the types own identity, it just gets associated with metad ```luau -type MyNumber = (x: number) type Func = () -> (x: number, y: number, z: number) function Func2(): (a: number, b: number, c: number) return 1,2,3 From 81ea18f5748e40d635794482ed00c8095cde8c97 Mon Sep 17 00:00:00 2001 From: karl-police Date: Tue, 12 May 2026 02:09:34 +0200 Subject: [PATCH 25/33] Update type-pack-names.md --- docs/type-pack-names.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index 766cc44a..35f33df7 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -105,6 +105,12 @@ type D = (num: number) -> () -- already works in Luau, no changes! type E = () -> (num: number) -- valid! ``` +```luau +type Foo_2 = (A, T...) -> () +type B = Foo_2 -- valid, T... is a type pack, A is not +type B = Foo_2<(text: string), (x: number, y: number)> -- not valid "A", is not a type pack +``` +
```luau From 14680e84504184f64ae2097f1f05101ec105846a Mon Sep 17 00:00:00 2001 From: karl-police Date: Tue, 12 May 2026 02:10:58 +0200 Subject: [PATCH 26/33] Update type-pack-names.md --- docs/type-pack-names.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index 35f33df7..355b70f0 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -45,7 +45,7 @@ But in this case, the result of ``MySignal.FireToFoo`` would show up as: -- or (self: WrappedSignal, targetFoo: Foo, number, string) ``` -without any context or indication on what these provided types ``(number, string)`` are meant to re-present. +without any context or indication on what these provided types ``(number, string)`` are meant to represent. But you can see that ``targetFoo: Foo`` is present, but only because function annotations specifically let you describe argument names, which APIs can pick-up on. From 8fe5ce403d337f919e0476f88bc571501eb0e616 Mon Sep 17 00:00:00 2001 From: karl-police Date: Tue, 12 May 2026 02:18:38 +0200 Subject: [PATCH 27/33] Update type-pack-names.md --- docs/type-pack-names.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index 355b70f0..0705b377 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -145,7 +145,6 @@ end ## Drawbacks - Most likely none, other than the implementation. -- Whether ``(arg: T)`` should have ``"arg"`` replaced or not, if substituted by ``(x: number)``. We can't rename ``T`` here From 533723261c065350b22c85bea72bdbf7f65b8a7e Mon Sep 17 00:00:00 2001 From: karl-police Date: Sat, 16 May 2026 21:13:05 +0200 Subject: [PATCH 28/33] Update type-pack-names.md --- docs/type-pack-names.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index 0705b377..adde7457 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -97,6 +97,7 @@ type MyNumber = (num: number) -- not valid not a type pack! ```luau type Foo = (T...) -> () +-- Names are optional type A = Foo<(a: number, number, label: number)> -- allowed type B = Foo<(x: number), (y: number)> -- not valid type C = Foo<(x: number, y: number)> -- valid From 40e5deb71d630e3d189c79fbed88036756b034b3 Mon Sep 17 00:00:00 2001 From: karl-police Date: Sat, 16 May 2026 21:21:00 +0200 Subject: [PATCH 29/33] Update type-pack-names.md --- docs/type-pack-names.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index adde7457..155d938d 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -77,6 +77,9 @@ Names/Labels are only metadata: - Names/Labels are NOT enforced in any type checking way - They don't affect the type itself - They only improve front-end hints +- Nothing changes about the types own identity, it just gets associated with a name. +- The name is NOT forced. +- Names propagate through type aliases. ### Usage and Examples: @@ -107,9 +110,9 @@ type E = () -> (num: number) -- valid! ``` ```luau -type Foo_2 = (A, T...) -> () -type B = Foo_2 -- valid, T... is a type pack, A is not -type B = Foo_2<(text: string), (x: number, y: number)> -- not valid "A", is not a type pack +type Mixed = (A, T...) -> () +type B = Mixed -- valid, T... is a type pack, A is not +type B = Mixed<(text: string), (x: number, y: number)> -- not valid "A", is not a type pack ```
@@ -127,7 +130,7 @@ type MySignal = WrappedSignal<(amount: number, message: string)> ]] ``` -Nothing changes about the types own identity, it just gets associated with metadata. +
@@ -146,9 +149,10 @@ end ## Drawbacks - Most likely none, other than the implementation. +- Union or intersections may keep a random name. -We can't rename ``T`` here +This RFC doesn't solve that we can't rename ``T`` here. ```luau type Foo = (arg: T) -> () type A = Foo<(x: number)> -- (x: number), does not count as a type pack @@ -161,7 +165,7 @@ local e: Bar<(x: number, y: number)> ## Alternatives -- A new syntax where it would be ``[x: number, y: number, z: number]`` or ``[x: number], [y: number], [z: number]`` +- A new syntax where it would be ``[x: number, y: number, z: number]`` or ``[x: number], [y: number], [z: number]``, that can be applied into types directly, other than within the type pack.
- Type functions could expose modifying argument names, but that would only work for function annotations, not on a type alone. From 1c7bdd9fbdb9234a857b0f34c23260c5edddb5f0 Mon Sep 17 00:00:00 2001 From: karl-police Date: Sat, 16 May 2026 21:22:04 +0200 Subject: [PATCH 30/33] Update type-pack-names.md --- docs/type-pack-names.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index 155d938d..1393d7ca 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -92,7 +92,7 @@ function Foo(cb: Callback<(targetBar: Bar)> end ```luau type Bar = (T) -> () -type A = Bar<(num: number)> -- not valid (T) is not a type pack! +type A = Bar<(num: number)> -- not valid, '(T)' is not a type pack! type MyNumber = (num: number) -- not valid not a type pack! ``` From 10aeebcc89c7463d04d52ef9c3fe38eef5157416 Mon Sep 17 00:00:00 2001 From: karl-police Date: Sat, 16 May 2026 21:23:08 +0200 Subject: [PATCH 31/33] Update type-pack-names.md --- docs/type-pack-names.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index 1393d7ca..93e1f7b7 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -78,7 +78,7 @@ Names/Labels are only metadata: - They don't affect the type itself - They only improve front-end hints - Nothing changes about the types own identity, it just gets associated with a name. -- The name is NOT forced. +- The name is NOT forced and are completely optional. - Names propagate through type aliases. ### Usage and Examples: From a2a3ddeff3a2096e2e052cffab83182c3d9f472b Mon Sep 17 00:00:00 2001 From: karl-police Date: Sat, 16 May 2026 21:25:39 +0200 Subject: [PATCH 32/33] Update type-pack-names.md --- docs/type-pack-names.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index 93e1f7b7..cbf453b3 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -102,11 +102,12 @@ type Foo = (T...) -> () -- Names are optional type A = Foo<(a: number, number, label: number)> -- allowed -type B = Foo<(x: number), (y: number)> -- not valid + +type B = Foo<(x: number), (y: number)> -- not valid, they're not type packs type C = Foo<(x: number, y: number)> -- valid type D = (num: number) -> () -- already works in Luau, no changes! -type E = () -> (num: number) -- valid! +type E = () -> (num: number) -- valid ``` ```luau @@ -123,7 +124,6 @@ type WrappedSignal = { } type MySignal = WrappedSignal<(amount: number, message: string)> - --[[ MySignal.FireToFoo would become (self: WrappedSignal, targetFoo: Foo, amount: number, message: string) -> () From 85c19c5d70ff73c8c6284111af2c0e2eaf7c8fc9 Mon Sep 17 00:00:00 2001 From: karl-police Date: Sun, 17 May 2026 19:16:56 +0200 Subject: [PATCH 33/33] Update type-pack-names.md --- docs/type-pack-names.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/type-pack-names.md b/docs/type-pack-names.md index cbf453b3..9175964d 100644 --- a/docs/type-pack-names.md +++ b/docs/type-pack-names.md @@ -45,7 +45,9 @@ But in this case, the result of ``MySignal.FireToFoo`` would show up as: -- or (self: WrappedSignal, targetFoo: Foo, number, string) ``` -without any context or indication on what these provided types ``(number, string)`` are meant to represent. +There is no context or indication on what these provided types ``(number, string)`` are meant to represent. +You don't want to use a function annotation to fill in ``T...`` because we want ``(self: WrappedSignal, targetFoo: Foo, number, string)`` +and not ``(self: WrappedSignal, targetFoo: Foo, (number, string) -> ())``. But you can see that ``targetFoo: Foo`` is present, but only because function annotations specifically let you describe argument names, which APIs can pick-up on.