Skip to content

Commit

Permalink
Improve type checking for state objects
Browse files Browse the repository at this point in the history
  • Loading branch information
dphfox committed Apr 15, 2024
1 parent c37eb70 commit df1c67a
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 12 deletions.
4 changes: 2 additions & 2 deletions src/InternalTypes.luau
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ export type StateObject<T> = Types.StateObject<T> & {
]]

-- A state object whose value can be set at any time by the user.
export type Value<T> = Types.Value<T> & {
_value: T
export type Value<T, S = T> = Types.Value<T, S> & {
_value: S
}

-- A state object whose value is derived from other objects using a callback.
Expand Down
10 changes: 5 additions & 5 deletions src/State/Value.luau
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function class:set(
newValue: unknown,
force: boolean?
)
local self = self :: InternalTypes.Value<unknown>
local self = self :: InternalTypes.Value<unknown, unknown>
local oldValue = self._value
if force or not isSimilar(oldValue, newValue) then
self._value = newValue
Expand All @@ -47,7 +47,7 @@ end
Returns the interior value of this state object.
]]
function class:_peek(): unknown
local self = self :: InternalTypes.Value<unknown>
local self = self :: InternalTypes.Value<unknown, unknown>
return self._value
end

Expand All @@ -56,7 +56,7 @@ function class:get()
end

function class:destroy()
local self = self :: InternalTypes.Value<unknown>
local self = self :: InternalTypes.Value<unknown, unknown>
if self.scope == nil then
logError("destroyedTwice", nil, "Value")
end
Expand All @@ -66,7 +66,7 @@ end
local function Value<T>(
scope: Types.Scope<unknown>,
initialValue: T
): Types.Value<T>
): Types.Value<T, any>
if initialValue == nil and (typeof(scope) ~= "table" or (scope[1] == nil and next(scope) ~= nil)) then
logError("scopeMissing", nil, "Value", "myScope:Value(initialValue)")
end
Expand All @@ -76,7 +76,7 @@ local function Value<T>(
dependentSet = {},
_value = initialValue
}, CLASS_METATABLE)
local self = (self :: any) :: InternalTypes.Value<T>
local self = (self :: any) :: InternalTypes.Value<T, any>

table.insert(scope, self)

Expand Down
9 changes: 5 additions & 4 deletions src/Types.luau
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export type Dependent = ScopedObject & {
export type StateObject<T> = Dependency & {
type: "State",
kind: string,
[{}]: T -- unindexable phantom data so StateObject actually contains a T
____phantom_peekType: (never) -> T -- phantom data so this contains a T
}

-- Either a constant value of type T, or a state object containing type T.
Expand All @@ -101,14 +101,15 @@ export type Use = <T>(target: CanBeState<T>) -> T
]]

-- A state object whose value can be set at any time by the user.
export type Value<T> = StateObject<T> & {
export type Value<T, S = T> = StateObject<T> & {
kind: "State",
set: (Value<T>, newValue: T, force: boolean?) -> ()
set: (Value<T, S>, newValue: S, force: boolean?) -> (),
____phantom_setType: (never) -> S -- phantom data so this contains a T
}
export type ValueConstructor = <T>(
scope: Scope<unknown>,
initialValue: T
) -> Value<T>
) -> Value<T, any>

-- A state object whose value is derived from other objects using a callback.
export type Computed<T> = StateObject<T> & Dependent & {
Expand Down
2 changes: 1 addition & 1 deletion src/init.luau
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export type StateObject<T> = Types.StateObject<T>
export type Task = Types.Task
export type Tween<T> = Types.Tween<T>
export type Use = Types.Use
export type Value<T> = Types.Value<T>
export type Value<T, S = T> = Types.Value<T, S>
export type Version = Types.Version

-- Down the line, this will be conditional based on whether Fusion is being
Expand Down

0 comments on commit df1c67a

Please sign in to comment.