Type inference not working correctly, incorrectly assumes a variable is nil

In the code below, if I hover over ‘variable’ in the line where I call the function, it shows: "Type ‘nil’ could not be converted into ‘number’. Despite me setting ‘variable’ to a number, it still thinks that it’s nil since I previously checked if it was nil (or false).

--!strict
local function doSomething(number: number)

end

local variable: number? = 5
if not variable then
	variable = 3

	doSomething(variable)
end

Expected behavior
It should consider ‘variable’ to be a number inside the if statement and not nil after assigning it a number.

A workaround would look something like this

--!strict
local function doSomething(number: number)

end

local variable: number? = 5
if not variable then
	local temporaryVariable: number = 3
	variable = temporaryVariable


	doSomething(temporaryVariable)
end
1 Like

This behavior is currently expected in Luau. You’ve explicitly annotated variable as having the type number? (which is short for number | nil). When you write your condition not variable, you then refine the type of variable to also being either false or nil which gives the type of variable in that scope as nil. The refinement system doesn’t support assignment, only refining types based on checks like not, typeof, and assert. So, the minimal workaround here is probably to insert an assert(variable) after the assignment for now.

If you’re thinking about this in the context of e.g. a function with default values for parameters that come in as nil, I’d suggest the following programming pattern as another approach which is cleaner and doesn’t require an assertion.

local function doSomething(number: number) end

local function myFunctionWithOptionalArgs(variable: number?)
    local variable = variable or 3
    doSomething(variable)
end

The Luau team is working on a new implementation of type inference that includes a feature called typestate which was not possible to implement in the current production type inference engine for Luau. This feature allows the inference system to update the type of variable after the assignment, and thus provide the expected behavior you wanted. We’re working hard to try get a beta of this new type inference system out to users as soon as possible because usability issues like this matter to us quite a bit. Apologies that you’ll have to wait for that to avoid having to add the assertions or contorting your code a bit though.