Reproduction Steps
The following snippet of code emits a warning:
--!strict
type MyRecord = {[any]: string | boolean}
local x: MyRecord = {
Foo = "Fighters",
}
Warning:
Type Error: (4,1) Type ‘x’ could not be converted into ‘MyRecord’
caused by:
Property ‘Foo’ is not compatible. Type ‘(boolean | string)?’ could not be converted into ‘string’
caused by:
Not all union options are compatible. Type ‘boolean’ could not be converted into ‘string’
However, changing the index type to “string” removes this warning:
--!strict
type MyRecord = {[string]: string | boolean}
local x: MyRecord = {
Foo = "Fighters",
}
This warning causes nearly every piece of code using the Pract Library, as it has a very commonly-used type with an any
index (These keys are converted to a string internally) and a union type for values
Expected Behavior
Luau used to be able to infer types like this, and putting a type annotation on the variable at-declaration used to coerce the initializing value with little friction.
It seems Luau still does this for types that have a string
index type, or a simple value type (i.e. the values are not a union of types)
Actual Behavior
Instead, this causes warnings for otherwise perfectly benign code. This means that any developers using my Pract library will see a bunch of script analysis warnings for what used to be perfectly valid code.
Workaround
The only workaround I’ve found so far is to initialize a table as empty, then add children gradually. In the first example:
--!strict
type MyRecord = {[any]: string | boolean}
local x: MyRecord = {}
x.Foo = "Fighters"
This is not a feasible refactor for Pract code, as it requires converting a simple expression into multiple statements + a variable declaration. Working around this issue requires a very destructive refactor for a developer-facing library.
An alternative workaround is to type all index types as string
, but this will also break existing Pract code, because sometimes it is convenient to create children as follows (using numbers as keys rather than strings):
-- "children" is typed as {[any]: Pract.Element | boolean | nil}
-- "Pract.Element" is typed as {[any]: any}, and is similar to a React element
local children: Pract.ChildrenArgument = {}
for i = 1, 10 do
table.insert(
children,
Pract.create(
"Frame",
{
Position = UDim2.fromScale(0.5, 0.5),
AnchorPoint = Vector2.new(0.5, 0.5),
}
)
)
end
return Pract.create("Frame", {}, children)
Issue Area: Studio
Issue Type: Other
Impact: Very High
Frequency: Constantly
Date First Experienced: 2022-05-15 00:05:00 (-06:00)
Date Last Experienced: 2022-05-15 00:05:00 (-06:00)