Hello!
Ok, this is just a quick doubt:
Can someone explain me why luau type cheking says that this is bad.
WeldC.Parent = hit
and this is bad:
WeldC.Parent = hit::Instance
But this is not:
WeldC.Parent = (hit::BasePart)::Instance
This is almost certainly a bug. However, I was unable to reproduce this on my own. Can you try to recreate the error with as little code as possible?
This is an TYPE assertion in luau.
In this case, hit is directly assigned to WeldC.Parent. If hit is inferred or already known to be of a compatible type (e.g., Instance), this assignment is straightforward and type-safe.
WeldC.Parent = hit::Instance
This means that you are saying that hit is an Instance. However, if the type checker had earlier inferred hit as an even more specific kind such as BasePart, then it would be deemed redundant by the type checker to assert it again as an instance.
WeldC.Parent = (hit::BasePart)::Instance
This statement performs a nested type assertion
First, it asserts that hit is of type BasePart.
Then, it asserts that the resulting BasePart is of type Instance.
im a sleepy head
Same as @OptimisticSide, I cannot reproduce this.
If you are using Roblox LSP, Luau LSP, or some other similar in nature, I’ve found that it does not fully match the behavior of Roblox’s built-in script analysis.
I think im not getting you:
it says that hit::Instance
is wrong becaues “types are unrelated” (and hit type is BasePart
). So I don’t understand casting a BasePart as Instance is not Ok, but casting a BasePart as a BasePart and then to a Instance is Ok.
Is it weird, im not able to recreate it:
All I know is that this is bad:
local HookTouched = Hook.Touched:Connect(function(hit)
if CanNotTouch[hit.Name] then return end
CanNotTouch[hit.Name] = true
if hit.Parent == GameFolder.Fountain.ToRemove then
LeafsToRemove-=1
hit.Anchored = false
hit.CanCollide = false
hit.CanTouch = false
local WeldC = Instance.new("WeldConstraint")
WeldC.Parent = hit
WeldC.Part0 = hit
WeldC.Part1 = Hook
table.insert(HookedParts, hit)
UpdateLeafsAmount()
SoundFolder.LeafCollect.PitchShiftSoundEffect.Octave = math.random(90,110)/10
SoundFolder.LeafCollect:Play()
local Part:BasePart&{ParticleEmitter:ParticleEmitter}
if InstantiatedParticleParts[1] then
Part = InstantiatedParticleParts[1]
table.remove(InstantiatedParticleParts,1)
else
Part = script.ParticlesPart:Clone()
end
Part.Parent = workspace
Part.CFrame = hit.CFrame
Part.ParticleEmitter:Emit(10)
wait(1.5)
Part.Parent = script
table.insert(InstantiatedParticleParts, Part)
end
end)
And this is not:
--!strict
local Part:BasePart = script.Parent
local a:{BasePart} = {}
local HookTouched = Part.Touched:Connect(function(hit)
if hit.Parent ~= workspace then
hit.Anchored = false
hit.CanCollide = false
hit.CanTouch = false
local WeldC = Instance.new("WeldConstraint")
WeldC.Parent = hit
WeldC.Part0 = hit
WeldC.Part1 = Part
table.insert(a, hit)
end
end)
(Both scripts have the “
--!strict
” at top.)
Let me rephrase, you did not state it you were in strict mode at the start of your post.
So since you clarified that you did use !strict in your code it makes sense.
When in !strict It enforces strict checking to identify possible type errors.
First Example Uses ‘DIRECT’ method
BasePart belongs to the subclass of Instance. However, the type checker doesn’t support direct type assertion from a specific subtype like BasePart to a supertype like Instance.
This limitation exists to prevent unsafe type conversions that could violate important type constraints.
Second One Uses ‘Subtype Casting Directly’ method
Similar to the first case, the type checker prevents direct casting of a BasePart
to an Instance
because it considers this as an unsafe type conversion.
This ensures that you explicitly handle such conversions.
And the third one uses ‘Nested’ method
By first asserting hit
as BasePart
and then as Instance
, you are explicitly stating the type conversion path. This process makes it so that each type conversion is valid and safe.
The type checker recognizes this explicit conversion path and allows it.
Simple reason why this occurs in !strict
-
Directly asserting
BasePart
asInstance
could hide bugs or type mismatches.
The nested assertion makes the conversion process clear, making sure each step is checked. -
The type checker needs to be certain that each type conversion is safe.
By breaking it down into smaller steps
you ensure that each conversion is checked for correctness. -
This would potentially make your code more readable & maintainable
by clearly stating each type conversion.
The behavior difference is because the type checker requires clear and safe type conversions.
Direct assertions or casts from BasePart
to Instance
are not allowed to prevent errors.
Nested assertions provide a clear and safe conversion path.
Which meet the type checker’s requirements
Ok, thanks I got it now.
(Is there any doc category about unsafe conversions?)
You can go here
Or use the devforum topics
Hope this helps you in someway.
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.