See all glossary terms

Type Inference

GDScript is an optionally typed language.
That means we can write code like this:
var name: String = "Godot"
var score: int = 100
var is_active: bool = true
var health: float = 100.0
var position: Vector2 = Vector2(100, 100)
This is good, because it reduces errors and documents our code.
However, this is a bit noisy. We already know "Godot" is a string, 100 is an integer, and so on; we can see that. And GDScript knows it too.
So, the GDScript developpers gave us a nice shortcut; we can write this:
var name := "Godot"
var score := 100
var is_active := true
var health := 100.0
var position := Vector2(100, 100)
GDScript will guess the type of all those variables. This is called "type inference".
How does GDScript differentiate a float from an integer?
Through convention, writing a plain number, like 0, 15, 300, etc., is interpreted as an integer ( int). Writing a number with a decimal point, like 0.0, 15.0, 300.0, etc., is interpreted as a float ( float).
Is there a difference between typing out a type or letting Godot infer it?
To answer an often asked question, writing:
var amount: int = 10
is strictly equivalent to:
var amount := 10
If Godot can infer the type, it will be the same as if you had written it explicitly. As long as Godot does not give you an error, the inference works exactly the same.

Inference chain

Sometimes, you use an existing variable to let GDScript infer another variable. For example:
var my_variable_b := my_variable_a
In this example, my_variable_b is inferred to be the same type as my_variable_a. But if my_variable_a is not typed, then my_variable_b cannot be inferred, and you will get an error.
This is also true of expressions. The following code will result in an error:
var position := Vector2(100, 100)
var offset = Vector2(100, 100)
var final_position := position + offset
# Error: Cannot infer the type of "final_position" variable because the value doesn't have a set type.
Did you notice it?
You're right, offset isn't typed. We can fix this by adding the : after the variable name:
var position := Vector2(100, 100)
var offset := Vector2(100, 100)
var final_position := position + offset
Now it all works out.
Inference is for you, not the engine
When we talk of "type inference" and how GDScript guesses your types, it applies to the static code in the editor. It serves to write less text and get good autocompletion and errors.
For the engine, there is no difference between writing types explicitly or not.

Limitations of Inference

sometimes, Godot cannot guess the type of a variable. In those cases, we need to specify it ourselves.
For example, when nodes are in the scene, if you write:
var player := $MyCharacterBody2D
All Godot can infer is that it is a node of type Node. It cannot know what type of node it is. So, we add a type hint to help Godot:
var player: CharacterBody2D = $MyCharacterBody2D
Another limitation is that some types are "nullable". That is, they can be null. If in the example above, $MyCharacterBody2D doesn't exist, then node will be null at runtime (but Godot won't give you an error in the editor).
So, in your head, you should read that node type as " CharacterBody2D or null".
Any type can be null?
No. Not all types are nullable. Built-in Godot primitives are not nullable: float, int, Vector2, Vector2i, Vector3, Vector3i, Color, String, bool, and so on.
A last limitation is that some built-in methods do not specify their return type. For example, the round() function can use either floats, ints, Vector2s, or Vector3s. As a result, GDScript cannot know the return type of round().
This line will give an error:
var rounded_vector := round(Vector2(22.84, 10.67))
# Error: The variable type is being inferred from a Variant value, so it will be typed as Variant.
(The Variant type is a type that means "we don't know")
Instead, we have to explicitly type:
var rounded_vector: Vector2 = round(Vector2(22.84, 10.67))

The as keyword

You can use as to cast a variable to a different type. For example:
var the_node := $MyCharacterBody2D as CharacterBody2D
This almost the same result as:
var the_node: CharacterBody2D = $MyCharacterBody2D
So why would you use as?
For example, to get good typing on some more generic variables:
func _on_body_entered(body: PhysicsBody2D) -> void:
	if body is Player:
		var player := body as Player
		player.take_damage()
Yes, we could instead write var player: Player = body, but using as documents that we're converting a value from an unknown one to a known one.
as also silently returns null if a value cannot be converted, so it can be used as a guard:
func _on_body_entered(body: PhysicsBody2D) -> void:
	var player := body as Player
	# if `body` is not a `Player` type, the variable `player` will be `null`:
	if player != null:
		player.take_damage()
We can also use this for casting elements that we do not want to put inside variables.
For example, instead of
func _ready() -> void:
  var timer: Timer = $MyTimerNode
  timer.start()
You could just write:
func _ready() -> void:
  ($MyTimerNode as Timer).start()

See Also

Related terms in the Glossary