Hello.
I wish to begin using strict type checking as default in my future scripts.
I am having difficult with a particular nuance of strict type checking mode.
Consider the following:
--!strict
local function target(turret: Model, target: Vector3?)
local base = turret.base
local baseHinge = base.hinge
local barrelsHinge = turret.barrels.hinge
if target then
local offsetCFrame = CFrame.new(base.Position, players[target].Character.HumanoidRootPart.Position).LookVector
I am receiving an error on on line 3 and 6 of this particular script when attempting to reference child instances ābaseā and ābarrelsā, with the error message āKey āBase/Barrelsā not found in class āModelāā.
Whilst Iām aware that :FindFirstChild() is better practice, my understanding is that there is performance overhead associated with the function and itās a lot less concise, so I donāt use it. But, in order to fix this issue, I tried to use it.
--!strict
local function target(turret: Model, target: Vector3?)
local base = turret:FindFirstChild("base")
local baseHinge = base:FindFirstChild("hinge")
local barrelsHinge = turret:FindFirstChild("barrels"):FindFirstChild("hinge")
if target then
local offsetCFrame = CFrame.new(base.Position, players[target].Character.HumanoidRootPart.Position).LookVector
However, in this case the last line gives an error stating āKey āPositionā not found in class āModelāā.
I also tried to force the type of base to be BasePart but this throws an error as well, stating that āType āInstanceā could not be converted into āBasePartāā.
I would greatly appreciate if someone could help diagnose this issue and point out what Iām doing wrong.
Thanks.
Iām aware the last line has another error associated with it, but Iām going to fix that soon, after this code works.
This is one of the problems that can be a bit hard to get around with strict mode.
The reason this problem happens is that the type Model
and the type Model
with children are technically 2 different types and original type Model
you use doesnāt account for children.
There are 2 ways you can get around this problem:
- Use intersection types to get typechecker recognize children like this:
type TurretModel = Model & {base: BasePart & {hinge: HingeConstraint}, barrels: BasePart & {hinge: HingeConstraint}}
local function target(turret: TurretModel, target: Vector3?)
local base = turret.base
local baseHinge = base.hinge
local barrelsHinge = turret.barrels.hinge
if target then
local offsetCFrame = CFrame.new(base.Position, players[target].Character.HumanoidRootPart.Position).LookVector
- Call
typeof
on the turret template when declaring the type of the turret
parameter and use union types with type Model
to bypass the linter errors then redeclare turret
as a local inside function with typeof
turret model and type assertation operator (::
) like this:
--!strict
local TurretModel = script.Model
type TurretModel = typeof(TurretModel)
local function target(turret: TurretModel | Model, target: Vector3?)
local turret: TurretModel = turret :: TurretModel
local base = turret.base
local baseHinge = base.hinge
local barrelsHinge = turret.barrels.hinge
if target then
local offsetCFrame = CFrame.new(base.Position, players[target].Character.HumanoidRootPart.Position).LookVector
5 Likes
Thanks.
Iāve just decided to stay on non strict for the time being until Roblox makes the system more robust and approachable.
Yeah honestly, this wouldāve been a lot more easier if generic functions and default type parameters were a thing right now combined with autocomplete as you only would have to do this:
--!strict
local TurretModel = script.Model
type TurretModel = typeof(TurretModel)
local function target<Turret = TurretModel>(turret: Turret, target: Vector3?)
local base = turret.base
local baseHinge = base.hinge
local barrelsHinge = turret.barrels.hinge
if target then
local offsetCFrame = CFrame.new(base.Position, players[target].Character.HumanoidRootPart.Position).LookVector
--...
target<typeof(turret)>(turret, Vector.new(0, 1, 0)) --For example.