Type Inference

2025/12/27

Type
Learning Resource
Format
Glossary Article
Version
General
Subject Tags
Code
Assets
All else
Copyright 2016-2026, GDQuest
Created
2026/02/16
Updated
2025/12/27

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 developers 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 player will be null at runtime (but Godot won't give you an error in the editor).

So, in your head, you should read that player 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 has 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()
Become an Indie Gamedev with GDQuest!

Don't stop here. Step-by-step tutorials are fun but they only take you so far.

Try one of our proven study programs to become an independent Gamedev truly capable of realizing the games you’ve always wanted to make.

Nathan

Founder and teacher at GDQuest
  • Starter Kit
  • Learn Gamedev from Zero
Check out GDSchool

You're welcome in our little community

Get help from peers and pros on GDQuest's Discord server!

20,000 membersJoin Server

Contribute to GDQuest's Free Library

There are multiple ways you can join our effort to create free and open source gamedev resources that are accessible to everyone!