It is possible to chain Instance:FindFirstChild calls. However, that is not how the function is meant to be used. The function is used to access children of an instance that you’re unsure exists, or are named after a property/function of the parent instance. Because it has the capacity to return nil, it is unsafe to chain this function. A better term to describe what you want is called optional chaining, and there are languages with direct support for this. One of these languages is TypeScript, and there exists a transpiler to Luau with support for the Roblox Studio API:
const child = npc.FindFirstChild("Visuals")?.FindFirstChild("Particle");
You can implement this as a monad in Luau:
local function Maybe(value)
local monad = {}
local result = value
function monad.advance(transform, ...)
if result then
result = transform(result, ...)
end
return monad
end
function monad.result()
return result
end
return monad
end
local particles = Maybe(npc).advance(npc.FindFirstChild, "Visuals")
.advance(npc.FindFirstChild, "Particle")
.result()
But this specific utilization is taking advantage of language properties that are not commonly abused, and therefore may be difficult to understand.
If you know no second descendant of the NPC could have the name “Particles”, then you could use the recursive mode of FindFirstChild:
local particles = npc:FindFirstChild("Particles", true)
-- See API reference on second argument
If your main concern is code readability, you can reduce indentation using techniques from the never-nesting principle, which include extraction, and what’s most useful in your case, inversion. Inversion inverts conditionals and sets points of early exits:
local visuals = npc:FindFirstChild("Visuals")
if visuals then
local particles = npc:FindFirstChild("Particles")
if particles then
-- ...
end
end
Is converted to:
local visuals = npc:FindFirstChild("Visuals")
if not visuals then
return
end
local particles = npc:FindFirstChild("Particles")
if not particles then
return
end
-- ...
Since you’ll need to hold onto the return results of the previous calls, you can use another language feature called short-circuiting to remove the leading if-statements altogether. This was demonstrated by @DasKairo in this reply