diff --git a/Pract/Types.lua b/Pract/Types.lua
index 92c4e97..e9f6fed 100644
--- a/Pract/Types.lua
+++ b/Pract/Types.lua
@@ -4,10 +4,10 @@
-- Util types
export type ChildrenArgument = {[any]: Element | boolean | nil}
-export type PropsArgument = {[any]: any}
+export type PropsArgument = any -- {[any]: any}
export type Symbol = {}
---export type StateUpdate = {[any]: any} | (state: S, props: P) -> {[any]: any}
---export type SetStateCB = (stateUpdate: StateUpdate) -> ()
+--export type StateUpdate
= {[any]: any} | (state: P, props: P) -> {[any]: any} +--export type SetStateCB
= (stateUpdate: StateUpdate
) -> ()
@@ -18,9 +18,12 @@ export type Element = {
export type Component = (props: any) -> Element
export type ComponentTyped = (props: P) -> any
-export type ClassState = {[string]: any}
-export type ClassStateUpdateThunk = (state: ClassState, props: PropsArgument) -> ClassState
-export type ClassStateUpdate = ClassState | ClassStateUpdateThunk
+export type ClassState = any
+export type PartialClassState = {[string]: any}
+export type ClassStateUpdateThunk = (state: ClassState, props: PropsArgument) -> PartialClassState
+export type ClassStateUpdateThunkTyped = (state: P, props: P) -> S
+export type ClassStateUpdate = PartialClassState | ClassStateUpdateThunk
+export type ClassStateUpdateTyped = S | ClassStateUpdateThunkTyped
export type ClassComponentSelf = {
[any]: any,
props: PropsArgument,
@@ -32,6 +35,17 @@ export type ClassComponentSelf = {
subscribeState: (self: ClassComponentSelf, listener: () -> ()) -> (() -> ()),
forceUpdate: (self: ClassComponentSelf) -> (),
}
+export type ClassComponentSelfTyped = {
+ [any]: (self: ClassComponentSelfTyped , ...any) -> ...any,
+ props: P,
+ state: S,
+ setState: (
+ self: ClassComponentSelfTyped ,
+ partialStateUpdate: ClassStateUpdateTyped
+ ) -> (),
+ subscribeState: (self: ClassComponentSelfTyped , listener: () -> ()) -> (() -> ()),
+ forceUpdate: (self: ClassComponentSelfTyped ) -> (),
+}
export type ClassComponentMethods = {
[any]: any,
render: (self: ClassComponentSelf) -> Element,
@@ -46,6 +60,20 @@ export type ClassComponentMethods = {
didUpdate: ((self: ClassComponentSelf) -> ())?,
willUnmount: ((self: ClassComponentSelf) -> ())?,
}
+export type ClassComponentMethodsTyped = {
+ [any]: any,
+ render: (self: ClassComponentSelfTyped ) -> Element,
+ init: ((self: ClassComponentSelfTyped ) -> ())?,
+ didMount: ((self: ClassComponentSelfTyped ) ->())?,
+ shouldUpdate: ((
+ self: ClassComponentSelfTyped ,
+ newProps: P,
+ newState: S
+ ) -> boolean)?,
+ willUpdate: ((self: ClassComponentSelfTyped , newProps: P, newState: S) -> ())?,
+ didUpdate: ((self: ClassComponentSelfTyped ) -> ())?,
+ willUnmount: ((self: ClassComponentSelfTyped ) -> ())?,
+}
export type Lifecycle = {
render: Component,
init: ((props: any) -> ())?,
@@ -55,6 +83,15 @@ export type Lifecycle = {
didUpdate: ((props: any) -> ())?,
willUnmount: ((props: any) -> ())?,
}
+export type LifecycleTyped = {
+ render: Component,
+ init: ((props: P) -> ())?,
+ didMount: ((props: P) ->())?,
+ shouldUpdate: ((newProps: P, oldProps: P) -> boolean)?,
+ willUpdate: ((props: P, oldProps: P) -> ())?,
+ didUpdate: ((props: P) -> ())?,
+ willUnmount: ((props: P) -> ())?,
+}
diff --git a/Pract/init.lua b/Pract/init.lua
index 62d8ae2..dc7c901 100644
--- a/Pract/init.lua
+++ b/Pract/init.lua
@@ -5,7 +5,7 @@
-- https://ambers-careware.github.io/pract/
local Pract = {}
-Pract._VERSION = '0.9.7'
+Pract._VERSION = '0.9.8'
local Types = require(script.Types)
local PractGlobalSystems = require(script.PractGlobalSystems)
@@ -19,8 +19,12 @@ export type Element = Types.Element
export type PropsArgument = Types.PropsArgument
export type ChildrenArgument = Types.ChildrenArgument
export type ClassComponentMethods = Types.ClassComponentMethods
+-- export type ClassComponentMethodsTyped = Types.ClassComponentMethodsTyped
+export type ClassComponentSelf = Types.ClassComponentSelf
+-- export type ClassComponentSelfTyped = Types.ClassComponentSelfTyped
export type ClassState = Types.ClassState
export type Lifecycle = Types.Lifecycle
+-- export type LifecycleTyped = Types.LifecycleTyped
-- Public library values
@@ -46,12 +50,18 @@ Pract.unmount = robloxReconciler.unmountVirtualTree
-- Higher-order component wrapper functions
Pract.withLifecycle = require(script.withLifecycle)
+-- Pract.withLifecycleTyped = (Pract.withLifecycle :: any) :: (
+-- closureCreator: (forceUpdate: () -> ()) -> LifecycleTyped
+-- ) -> ComponentTyped
Pract.withState = require(script.withState)
Pract.withDeferredState = require(script.withDeferredState)
Pract.withSignal = require(script.withSignal)
Pract.withContextProvider = require(script.withContextProvider)
Pract.withContextConsumer = require(script.withContextConsumer)
Pract.classComponent = require(script.classComponent)
+-- Pract.classComponentTyped = (Pract.classComponent :: any) :: (
+-- methods: ClassComponentMethodsTyped
+-- ) -> ComponentTyped
-- Symbols:
diff --git a/docs/advanced/externalstate.md b/docs/advanced/externalstate.md
index 2399f12..40a2281 100644
--- a/docs/advanced/externalstate.md
+++ b/docs/advanced/externalstate.md
@@ -243,7 +243,4 @@ As long as your custom state system has a way to detect changes in state, you ca
Try to avoid repeating yourself, and make your own helper higher-order functions or components to connect your third-party state with Pract. That way, using external state can be just as easy as using a pre-made utlilty with your Pract component!
-#### Up Next: ???
-
-You've reached the end of the Pract documentation.
-Much of this documentation is a first draft, and may be subject to change in the future. Collaborators would be appreciated in improving the documentation and functionality of the Pract library in general!
\ No newline at end of file
+#### Up Next: [Type Safety](./typesafety)
\ No newline at end of file
diff --git a/docs/advanced/typesafety.md b/docs/advanced/typesafety.md
new file mode 100644
index 0000000..d85ae03
--- /dev/null
+++ b/docs/advanced/typesafety.md
@@ -0,0 +1,243 @@
+---
+layout: default
+title: Type Safety
+nav_order: 7
+parent: Advanced Guide
+permalink: advanced/typesafety
+---
+
+# Type Safety
+
+> Note: This section assumes you have a basic understanding of Luau's [type system](https://luau-lang.org/typecheck).
+
+Pract is compatible with Luau's [type system](https://luau-lang.org/typecheck), and provides variants of previously-discussed features for creating typesafe components!
+
+Pract's design puts an emphasis on type system use being _opt-in_, as some people may not wish to use Luau's type system in their code. Pract's default constructs have lenient typings, while offering constructs with stricter typings.
+
+At the time this page is being written, Luau's type system is somewhat underdeveloped, and as such, using Pract with types in strict mode requires a number of conventional tricks to properly assert or annotate types. This article is not completely future-proof, and Pract's type constructs are subject to change. For now, using types with Pract is possible as long as you remember to annotate types where needed.
+
+## Typing component props
+
+Pract exports a type `ComponentTyped