← 返回首页

FIELD NOTE / 2026-08-20

godot

TypeScript 开发者快速上手 GDScript 语法

本文基于 Godot 4.5,重点介绍 GDScript 与 TypeScript 之间的语法差异。

TypeScript 开发者快速上手 GDScript 语法 封面

本文基于 Godot 4.5,重点介绍 GDScript 与 TypeScript 之间的语法差异。

GDScript 是一门支持渐进式静态类型的语言,可以将它理解为:

Python 风格语法 + 可选静态类型 + Godot API

1. 基础语法对照

TypeScriptGDScript
let value = 1var value = 1
const MAX = 10const MAX: int = 10
numberint / float
stringString
booleanbool
T[]Array[T]
Map<K, V>Dictionary[K, V]
null / undefinednull
functionfunc
switchmatch
condition ? a : ba if condition else b
async/Promiseawait + Signal
instanceofis
importclass_name / preload()

GDScript 使用缩进表示代码块,不需要花括号和分号。

func greet(name: String) -> String:
   if name.is_empty():
      return "Hello"

   return "Hello, %s" % name

2. 变量与常量

动态类型变量

var value = 10
value = "text"

使用 = 且不声明类型时,变量按动态类型处理,类似 TypeScript 中的 any

显式静态类型

var count: int = 10
var speed: float = 120.0
var title: String = "Godot"
var enabled: bool = true

静态类型变量不能被赋予其他类型:

var count: int = 10

# 编译错误
count = "ten"

类型推导

使用 := 让编译器推导静态类型:

var count := 10
var speed := 120.0
var title := "Godot"
var position := Vector2.ZERO

下面的代码会产生类型错误:

var count := 10

# count 已被推导为 int
count = "ten"

常量

const MAX_COUNT: int = 100
const DEFAULT_NAME: String = "Guest"
const DEFAULT_POSITION := Vector2.ZERO

常量通常使用 UPPER_SNAKE_CASE 命名。

3. 基础类型

var integer_value: int = 10
var float_value: float = 10.5
var text_value: String = "Hello"
var boolean_value: bool = true
var vector_value: Vector2 = Vector2(10.0, 20.0)
var color_value: Color = Color.WHITE
var node_path: NodePath = ^"Root/Child"
var identifier: StringName = &"player"

TypeScript 的 number 在 GDScript 中分为:

  • int:整数
  • float:浮点数

注意整数除法:

var result_a := 5 / 2
var result_b := 5.0 / 2

print(result_a) # 2
print(result_b) # 2.5

4. 字符串

字符串声明

var single_line := "Hello, Godot"
var another_line := 'Hello, Godot'

多行字符串

var content := """
第一行
第二行
第三行
"""

字符串格式化

GDScript 没有 JavaScript 模板字符串,通常使用 %

var name := "Alice"
var score := 100

var message := "%s 的分数是 %d" % [name, score]

常用格式:

格式含义
%s字符串
%d整数
%f浮点数
%.2f保留两位小数

示例:

var price := 12.3456
var text := "价格:%.2f" % price

5. 数组

声明数组

var values: Array[int] = [1, 2, 3]
var names: Array[String] = ["Alice", "Bob"]

添加和删除元素

var values: Array[int] = []

values.append(1)
values.push_back(2)
values.push_front(0)

values.erase(1)
values.remove_at(0)
values.clear()

访问元素

var values: Array[int] = [10, 20, 30]

print(values[0])
print(values[-1])
print(values.size())
print(values.is_empty())

负数索引表示从数组末尾开始访问。

遍历数组

var values: Array[int] = [10, 20, 30]

for value in values:
   print(value)

获取索引:

for index in range(values.size()):
   print(index, values[index])

数组复制

Array 是引用类型:

var source: Array[int] = [1, 2, 3]
var target := source

target.append(4)

print(source) # [1, 2, 3, 4]

复制数组:

var copied := source.duplicate()

深复制:

var copied := source.duplicate(true)

6. Dictionary

Dictionary 类似 TypeScript 的 Map 或普通对象。

声明 Dictionary

var scores: Dictionary[String, int] = {
   "Alice": 100,
   "Bob": 80,
}

读取和修改

scores["Alice"] = 120

var alice_score: int = scores["Alice"]

判断键是否存在

if scores.has("Alice"):
   print(scores["Alice"])

安全读取

var score: int = scores.get("Charlie", 0)

遍历 Dictionary

for key in scores:
   var value: int = scores[key]
   print(key, value)

也可以分别获取键和值:

for key in scores.keys():
   print(key)

for value in scores.values():
   print(value)

Dictionary 同样是引用类型,需要复制时使用:

var copied := scores.duplicate()

7. 运算符

算术运算符

var add := 10 + 5
var subtract := 10 - 5
var multiply := 10 * 5
var divide := 10.0 / 5.0
var remainder := 10 % 3
var power := 2 ** 3

比较运算符

a == b
a != b
a > b
a >= b
a < b
a <= b

GDScript 没有 TypeScript 中的 ===!==

逻辑运算符

推荐使用:

condition_a and condition_b
condition_a or condition_b
not condition_a

也支持:

condition_a && condition_b
condition_a || condition_b
!condition_a

三元表达式

TypeScript:

const result = condition ? "yes" : "no";

GDScript:

var result := "yes" if condition else "no"

成员判断

var values: Array[int] = [1, 2, 3]

if 2 in values:
   print("存在")

Dictionary:

if "Alice" in scores:
   print("存在")

8. 条件语句

var score := 85

if score >= 90:
   print("A")
elif score >= 80:
   print("B")
else:
   print("C")

GDScript 使用 elif,而不是 TypeScript 的 else if

9. Match

match 类似 TypeScript 的 switch

var state := 1

match state:
   0:
      print("Idle")

   1:
      print("Running")

   2, 3:
      print("Other")

   _:
      print("Unknown")

_ 表示默认分支。

match 不需要 break,并且不会发生分支穿透。

10. 循环

For 循环

for index in range(5):
   print(index)

输出范围为 04

指定起点和终点:

for index in range(2, 5):
   print(index)

指定步长:

for index in range(0, 10, 2):
   print(index)

While 循环

var count := 0

while count < 5:
   print(count)
   count += 1

Continue 和 Break

for value in range(10):
   if value == 2:
      continue

   if value == 8:
      break

   print(value)

11. 函数

普通函数

func add(a: int, b: int) -> int:
   return a + b

无返回值函数

func print_message(message: String) -> void:
   print(message)

默认参数

func greet(name: String = "Guest") -> String:
   return "Hello, %s" % name

静态函数

class_name MathHelper
extends RefCounted

static func clamp_percentage(value: float) -> float:
   return clampf(value, 0.0, 1.0)

调用:

var result := MathHelper.clamp_percentage(1.5)

GDScript 不支持函数重载。

下面的写法无效:

# 不允许声明两个同名函数

func calculate(value: int) -> int:
   return value

func calculate(value: String) -> String:
   return value

通常通过不同函数名、默认参数或更通用的参数类型解决。

12. Lambda 与 Callable

GDScript 使用 Callable 表示可调用对象。

var double: Callable = func(value: int) -> int:
   return value * 2

var result: int = double.call(10)
print(result)

将普通函数作为 Callable:

func print_value(value: int) -> void:
   print(value)

var callback := Callable(self, "print_value")
callback.call(10)

也可以直接引用函数:

var callback: Callable = print_value
callback.call(10)

13. 枚举

匿名枚举

enum {
   IDLE,
   RUNNING,
   STOPPED,
}

命名枚举

enum State {
   IDLE,
   RUNNING,
   STOPPED,
}

使用枚举:

var state: State = State.IDLE

if state == State.RUNNING:
   print("Running")

枚举值底层是整数。

可以显式指定数值:

enum StatusCode {
   SUCCESS = 200,
   NOT_FOUND = 404,
   ERROR = 500,
}

14. 类与继承

一个 .gd 文件通常对应一个类。

class_name Counter
extends RefCounted

var value: int = 0

func increment() -> void:
   value += 1

使用:

var counter := Counter.new()
counter.increment()

构造函数

GDScript 使用 _init() 作为构造函数:

class_name Counter
extends RefCounted

var value: int

func _init(initial_value: int = 0) -> void:
   value = initial_value

创建对象:

var counter := Counter.new(10)

继承

class_name BaseService
extends RefCounted

func execute() -> void:
   print("Base")

子类:

class_name CustomService
extends BaseService

func execute() -> void:
   print("Custom")

调用父类同名方法:

func execute() -> void:
   super()
   print("Custom")

GDScript 只支持单继承。

访问修饰符

GDScript 没有:

  • public
  • private
  • protected

通常使用下划线表示内部成员:

var _internal_value: int = 0

func _calculate_result() -> int:
   return _internal_value * 2

这只是命名约定,不会真正限制访问。

15. Getter 与 Setter

var _score: int = 0

var score: int:
   get:
      return _score

   set(value):
      _score = maxi(value, 0)

使用方式和普通变量相同:

score = -10
print(score) # 0

也可以直接使用属性自身作为后备存储:

var score: int = 0:
   set(value):
      score = maxi(value, 0)

   get:
      return score

16. 类型判断与类型转换

is

is 类似 TypeScript 的 instanceof

if value is Node:
   print("value 是 Node")

as

var node := value as Node

if node != null:
   print(node.name)

对象转换失败时,as 可能返回 null

更安全的写法:

if value is Node:
   var node: Node = value
   print(node.name)

基础类型转换

var integer_value := int("10")
var float_value := float("10.5")
var string_value := str(100)

17. Null

GDScript 没有 undefined,只有 null

var target: Node = null

if target == null:
   print("没有目标")

对象类型可以保存 null

以下值类型不能使用 null

var count: int = 0
var speed: float = 0.0
var position: Vector2 = Vector2.ZERO

GDScript 没有 TypeScript 的可选链:

object?.method();

需要显式判断:

if object != null:
   object.method()

GDScript也没有 ?? 空值合并运算符,可以使用三元表达式:

var result := value if value != null else default_value

18. Signal

Signal 类似类型化的事件。

定义 Signal

signal value_changed(value: int)
signal completed

发出 Signal

value_changed.emit(100)
completed.emit()

连接 Signal

func _ready() -> void:
   value_changed.connect(_on_value_changed)

func _on_value_changed(value: int) -> void:
   print(value)

也可以连接 Lambda:

value_changed.connect(
   func(value: int) -> void:
      print(value)
)

断开 Signal

if value_changed.is_connected(_on_value_changed):
   value_changed.disconnect(_on_value_changed)

19. Await

GDScript 使用 await 等待 Signal。

func wait_one_second() -> void:
   await get_tree().create_timer(1.0).timeout
   print("完成")

等待自定义 Signal:

signal completed

func run() -> void:
   await completed
   print("收到 completed")

GDScript 没有 JavaScript 的 Promise,也没有 Promise.all()

异步流程通常围绕 Signal 组织。

20. 注解

@export

将属性暴露到 Godot Inspector:

@export var speed: float = 100.0
@export var display_name: String = ""

限制数字范围:

@export_range(0, 100) var percentage: int = 50

限制步长:

@export_range(0.0, 1.0, 0.1) var opacity: float = 1.0

枚举选项:

@export_enum("Small", "Medium", "Large")
var size_type: int = 0

资源类型:

@export var texture: Texture2D
@export var scene: PackedScene

@onready

等待当前 Node 进入场景树后初始化:

@onready var label: Label = $Label
@onready var button: Button = %Button

它常用于获取子节点,因为脚本初始化时子节点可能尚未准备完成。

21. Preload 与 Load

preload

编译时预加载:

const ICON := preload("res://assets/icon.png")
const HELPER := preload("res://scripts/helper.gd")

preload() 的路径必须是常量字符串。

load

运行时动态加载:

var path := "res://assets/icon.png"
var resource := load(path)

建议为结果添加类型:

var texture := load(path) as Texture2D

if texture == null:
   push_error("资源加载失败")

22. 错误处理

GDScript 没有 try/catch

Godot API 通常通过以下方式表示错误:

  • 返回 Error
  • 返回 null
  • 返回 false
  • 输出错误日志

常用调试函数:

print("普通日志")
print_debug("调试日志")
push_warning("警告信息")
push_error("错误信息")

断言:

assert(value >= 0, "value 不能小于 0")

assert() 主要用于开发阶段,不应该代替正常的业务错误处理。

23. 值类型与引用类型

常见值类型包括:

  • int
  • float
  • bool
  • String
  • Vector2
  • Vector3
  • Color

复制值类型会得到独立副本:

var first := Vector2(10.0, 20.0)
var second := first

second.x = 100.0

print(first.x) # 10

常见引用类型包括:

  • Array
  • Dictionary
  • Object
  • Node
  • Resource
  • RefCounted

复制引用类型变量通常只是复制引用。

24. TypeScript 开发者需要注意的差异

GDScript 没有这些 TypeScript 特性

  • undefined
  • 可选链 ?.
  • 空值合并 ??
  • 接口 interface
  • 联合类型
  • 交叉类型
  • 用户自定义泛型
  • 函数重载
  • 访问修饰符
  • 装饰器系统
  • ES Module
  • 异常捕获 try/catch
  • Promise
  • 对象解构
  • 数组展开语法

对应替代方式

TypeScript 特性GDScript 替代方式
interface基类、Resource、鸭子类型
importclass_namepreload()
PromiseSignal + await
try/catch返回值、Error、null 检查
private下划线命名约定
T | null对象类型直接允许 null
Array<T>Array[T]
Map<K, V>Dictionary[K, V]
instanceofis
类型断言as
switchmatch

25. 命名规范

Godot 官方风格通常使用:

class_name ExampleService

const MAX_RETRY_COUNT: int = 3

@export var request_timeout: float = 10.0

var current_retry_count: int = 0
var _internal_state: int = 0

func start_request() -> void:
   pass

func _calculate_delay() -> float:
   return 1.0

命名约定:

内容风格
类名PascalCase
函数snake_case
变量snake_case
常量UPPER_SNAKE_CASE
内部成员_snake_case
文件名snake_case.gd
Signalsnake_case,通常使用过去式

Signal 示例:

signal value_changed(value: int)
signal request_completed
signal connection_failed

26. 完整语法示例

class_name Counter
extends RefCounted

signal value_changed(value: int)
signal limit_reached

const DEFAULT_LIMIT: int = 100

var _value: int = 0

var limit: int = DEFAULT_LIMIT:
   set(new_value):
      limit = maxi(new_value, 0)
      _value = mini(_value, limit)

var value: int:
   get:
      return _value

func _init(initial_value: int = 0) -> void:
   _value = clampi(initial_value, 0, limit)

func increment(amount: int = 1) -> void:
   if amount <= 0:
      push_warning("amount 必须大于 0")
      return

   _value = mini(_value + amount, limit)
   value_changed.emit(_value)

   if _value == limit:
      limit_reached.emit()

func reset() -> void:
   _value = 0
   value_changed.emit(_value)

func is_at_limit() -> bool:
   return _value >= limit

static func create_default() -> Counter:
   return Counter.new()

使用:

var counter := Counter.new(10)

counter.value_changed.connect(
   func(value: int) -> void:
      print("当前值:", value)
)

counter.limit_reached.connect(
   func() -> void:
      print("达到上限")
)

counter.increment(5)
counter.reset()

参考资料