笔者注:typescript在轻量级游戏开发中相当重要,cocos creator,laya,egret的主要开发语言都是typescript。unity 也可用typescript开发(用工具转lua),所以写这个专题复盘和游戏开发相关的ts基础知识,更多的是给自己记录便于查找。
在 TypeScript 里,作用域对变量、函数、类等标识符的可见性与生命周期起着关键的决定作用。
全局作用域是最外围的作用域,其中定义的标识符在整个应用程序里都能被访问到。像在文件顶层声明的变量、函数或者类,都会处于全局作用域。
// 全局变量
const globalVar = 'global';
function globalFunction() {
console.log('This is a global function');
}
class GlobalClass {}
在函数内部声明的变量具有函数作用域,这意味着这些变量只能在该函数内部被访问,函数外部无法访问。TypeScript 中的var
关键字声明的变量就属于函数作用域。
function example() {
var functionScoped = 'I am function scoped';
console.log(functionScoped); // 正常输出
}
example();
console.log(functionScoped); // 错误:找不到变量functionScoped
块级作用域由花括号{}
界定,像if
语句、for
循环、while
循环等内部的代码块都属于块级作用域。使用let
和const
关键字声明的变量就具有块级作用域。
if (true) {
let blockScopedLet = 'I am block scoped with let';
const blockScopedConst = 'I am block scoped with const';
console.log(blockScopedLet); // 正常输出
}
console.log(blockScopedLet); // 错误:找不到变量blockScopedLet
console.log(blockScopedConst); // 错误:找不到变量blockScopedConst
类作用域涵盖了类的属性和方法,这些属性和方法可以通过类的实例或者类本身(静态成员)来访问。
class MyClass {
public publicProp = 'public'; // 公共属性,任何地方都能访问
private privateProp = 'private'; // 私有属性,只能在类内部访问
protected protectedProp = 'protected'; // 受保护属性,能在类内部和子类中访问
public publicMethod() {
console.log(this.privateProp); // 正常访问
}
}
const instance = new MyClass();
console.log(instance.publicProp); // 正常访问
console.log(instance.privateProp); // 错误:私有属性只能在类内部访问
console.log(instance.protectedProp); // 错误:受保护属性只能在类内部或子类中访问
在 TypeScript 中,每个文件都可以看作一个独立的模块。模块内部定义的标识符默认是私有的,若想在模块外部访问,需要使用export
关键字进行导出。
// module.ts
const privateToModule = 'private to module';
export const publicToModule = 'public to module';
// main.ts
import { publicToModule } from './module';
console.log(publicToModule); // 正常访问
console.log(privateToModule); // 错误:找不到变量privateToModule
闭包是指有权访问另一个函数作用域中变量的函数。即便该函数已经执行完毕,其作用域内的变量也会被闭包所保留。
function outer() {
const outerVar = 'I am from outer function';
return function inner() {
console.log(outerVar); // 闭包访问外部函数的变量
};
}
const closure = outer();
closure(); // 输出:I am from outer function
TypeScript 中的作用域规则和 JavaScript 基本一致,不过 TypeScript 增加了一些特性,像类型检查、访问修饰符(private
、protected
)以及模块系统等,让作用域的管理变得更加严谨和安全。
TypeScript 是 JavaScript 的超集,它为 JavaScript 添加了静态类型系统,最终需要编译成纯 JavaScript 代码才能在浏览器或 Node.js 等环境中运行。
TypeScript 的编译过程主要分为三个核心阶段:
TypeScript 源代码 → 解析器 → AST → 类型检查器 → 转换 → JavaScript 代码
解析阶段将 TypeScript 源代码转换为抽象语法树(AST),主要分为两个步骤:
const x: number = 10;
会被分解为 const
、x
、:
、number
、=
、10
、;
等 Tokens。示例 AST 结构:
VariableDeclaration
├─ kind: const
├─ declarations
│ └─ VariableDeclarator
│ ├─ name: Identifier(x)
│ ├─ type: Identifier(number)
│ └─ initializer: NumericLiteral(10)
└─ flags: None
TypeScript 的核心特性是静态类型系统,类型检查器通过以下方式工作:
const x = 10; // 推断为 number 类型
const y: string = "hello";
const z: number = "world"; // 类型错误:string 不能赋值给 number
类型检查完成后,编译器将 AST 转换为 JavaScript 代码,主要工作包括:
// TypeScript
const add = (a: number, b: number): number => a + b;
// JavaScript
const add = (a, b) => a + b;
// TypeScript (ES6)
class Person {
constructor(public name: string) {}
}
// JavaScript (ES5)
var Person = (function () {
function Person(name) {
this.name = name;
}
return Person;
})();
// TypeScript 枚举
enum Color { Red, Green, Blue }
// JavaScript 等价实现
var Color;
(function (Color) {
Color[Color["Red"] = 0] = "Red";
Color[Color["Green"] = 1] = "Green";
Color[Color["Blue"] = 2] = "Blue";
})(Color || (Color = {}));
tsconfig.json
是 TypeScript 的核心配置文件,控制编译行为:
{
"compilerOptions": {
"target": "ES6", // 目标 JavaScript 版本
"module": "commonjs", // 模块系统
"strict": true, // 启用所有严格类型检查
"esModuleInterop": true, // 支持 ES6 模块与 CommonJS 互操作
"skipLibCheck": true, // 跳过类型声明文件检查
"forceConsistentCasingInFileNames": true // 强制文件名大小写一致
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules"]
}
tsconfig.json
中的 incremental: true
缓存编译结果,加快后续编译速度。// lodash.d.ts
declare function debounce(func: Function, wait: number): Function;
// 装饰器
@log
class MyClass {}
// 编译后
var MyClass = (function () {
function MyClass() {}
MyClass = __decorate([log], MyClass);
return MyClass;
})();
@babel/preset-typescript
编译 TypeScript(仅移除类型信息,不进行类型检查)。ts-loader
或 awesome-typescript-loader
集成到构建流程中。TypeScript 编译的核心目标是在保留 JavaScript 动态特性的同时,通过静态类型检查提供早期错误捕获。整个过程通过解析、类型检查和代码生成三个阶段,将带有类型信息的 TypeScript 代码转换为纯 JavaScript 代码,同时确保类型安全。理解编译原理有助于更好地利用 TypeScript 的特性,并在遇到编译错误时快速定位问题。