学习 TypeScript:用 Playground 轻松实践
在当今的 Web 开发领域,JavaScript 无疑是核心技术之一。然而,随着项目规模的扩大和复杂度的提升,JavaScript 的动态类型特性有时也会带来一些挑战,例如运行时错误难以预测、代码重构困难、团队协作效率降低等。为了解决这些问题,TypeScript 应运而生。
TypeScript 是 JavaScript 的一个超集,它在 JavaScript 的基础上增加了静态类型系统、类、接口等特性。通过在开发阶段捕获潜在的类型错误,TypeScript 大大提高了代码的可维护性、可读性和健壮性,尤其适用于大型企业级项目。许多流行的前端框架(如 Angular、Vue 3)和后端框架(如 NestJS)都强烈推荐或默认使用 TypeScript。
对于初学者或者想快速了解和实践 TypeScript 特性的开发者来说,如何开始往往是第一个问题。本地环境的搭建(安装 Node.js、npm/yarn、TypeScript 编译器 tsc
、配置 tsconfig.json
、集成到构建工具)可能会显得有些繁琐。有没有一种更简便的方式,能够让我们立刻上手,编写 TypeScript 代码,并实时看到它的编译结果和潜在的错误呢?
答案是肯定的,这就是 TypeScript Playground。
什么是 TypeScript Playground?
TypeScript Playground 是一个由 Microsoft 官方提供的在线交互式环境。它允许你在浏览器中直接编写 TypeScript 代码,并实时进行编译,显示编译后的 JavaScript 代码、任何类型检查错误以及运行时输出(尽管运行时输出通常不如错误检查重要)。
你可以通过访问以下链接打开 TypeScript Playground:https://www.typescriptlang.org/play
Playground 提供了一个无需任何本地安装或配置的沙箱环境,是学习、实验、分享 TypeScript 代码 snippet 的绝佳工具。无论你是在尝试一个新的类型特性,验证某个复杂的类型定义,还是仅仅想看看一段 TypeScript 代码会被编译成什么样的 JavaScript,Playground 都能为你提供即时反馈。
初识 Playground 界面
打开 Playground 页面后,你会看到一个被分成几个主要区域的界面:
- Editor(编辑器): 这是你编写 TypeScript 代码的主要区域。它提供了语法高亮、智能感知(在你输入时会显示可能的属性、方法等)、错误提示等功能,体验类似于一个轻量级的 IDE。
- JS Output(JS 输出): 这个区域实时显示你的 TypeScript 代码被编译成的 JavaScript 代码。通过观察这里的输出,你可以了解 TypeScript 是如何将类型信息移除或转换为对应的 JavaScript 结构的。
- Errors(错误): 这个区域显示 TypeScript 编译器在进行类型检查时发现的所有错误。这些错误通常是类型不匹配、属性不存在、参数数量不正确等问题。Playground 的强大之处在于,它会在你输入代码时就即时显示这些错误,帮助你快速定位和修复问题。
- Logs(日志): 这个区域可以显示
console.log
等语句的输出。虽然在学习 TypeScript 类型系统时不如 Errors 面板重要,但在编写包含运行时逻辑的代码时,它可以帮助你验证程序的实际行为。 - Options(选项): 界面顶部或侧边通常会有一个选项面板或按钮(有时是一个齿轮图标),点击它可以展开或显示编译选项。这里你可以调整 TypeScript 编译器的各种设置,例如目标 JavaScript 版本 (
target
)、模块系统 (module
)、严格模式 (strict
) 等。修改这些选项会立即影响 JS Output 和 Errors 面板的结果。
理解这几个区域的功能,你就掌握了使用 Playground 的基本方法。你的主要工作流程将是在 Editor 中编写代码,观察 Errors 面板看是否有类型错误,以及查看 JS Output 了解编译结果。
使用 Playground 实践 TypeScript 基础概念
现在,让我们通过 Playground 来实践一些 TypeScript 的核心概念。在 Editor 中输入以下代码,并观察其他面板的变化。
1. 基本类型 (Basic Types)
TypeScript 为 JavaScript 的基本类型提供了明确的类型注解。
“`typescript
// 在 Editor 中输入以下代码
let isDone: boolean = false; // 布尔类型
let age: number = 25; // 数字类型 (整数或浮点数)
let firstName: string = “Alice”; // 字符串类型
let list: number[] = [1, 2, 3]; // 数字数组
let anotherList: Array
// 元组 Tuple:表示已知元素数量和类型的数组,各元素的类型不必相同
let x: [string, number];
x = [“hello”, 10]; // 正确
// x = [10, “hello”]; // 错误:类型不匹配,在 Errors 面板会看到错误
// 枚举 Enum:定义一组命名的常量
enum Color {Red, Green, Blue};
let c: Color = Color.Green; // 默认从 0 开始编号
console.log(c); // 输出 1
enum Direction {
Up = 1,
Down, // 自动编号为 2
Left, // 自动编号为 3
Right // 自动编号为 4
}
let d: Direction = Direction.Up;
console.log(d); // 输出 1
// Any 类型:可以表示任何类型,通常在不确定类型或需要兼容旧 JS 代码时使用
let notSure: any = 4;
notSure = “maybe a string instead”;
notSure = false; // 也可以是 boolean
// Unknown 类型:与 Any 类似,但更安全。在使用 unknown 类型的变量前,必须进行类型检查或断言
let unknownValue: unknown = “hello”;
// let str2: string = unknownValue; // 错误:unknown 类型不能直接赋值给其他类型
if (typeof unknownValue === ‘string’) {
let str2: string = unknownValue; // 正确:经过类型检查后可以使用
}
// Void 类型:表示没有任何返回值的函数
function warnUser(): void {
console.log(“This is a warning message”);
}
// let unusable: void = undefined; // 在 strictNullChecks: false 时允许
// let unusable2: void = null; // 在 strictNullChecks: false 时允许
// Null 和 Undefined 类型:默认情况下,它们是所有其他类型的子类型,可以赋值给其他类型(取决于 strictNullChecks 选项)
let u: undefined = undefined;
let n: null = null;
// let num: number = undefined; // 在 strictNullChecks: true 时错误
// Never 类型:表示永远不会有返回值的函数(例如抛出错误或无限循环)
function error(message: string): never {
throw new Error(message);
}
function infiniteLoop(): never {
while (true) {}
}
“`
在 Editor 中输入以上代码后:
- 观察 Errors 面板:你会看到上面注释中标记为“错误”的地方会显示对应的类型错误提示。例如,尝试将
[10, "hello"]
赋值给[string, number]
类型的x
时,错误信息会清晰地指出类型不匹配。 - 观察 JS Output 面板:你会发现大多数类型注解 (
: boolean
,: number
,: string
,: number[]
,: Array<string>
,: [string, number]
,: any
,: unknown
,: void
,: never
) 都被移除了。枚举 (enum
) 会被编译成对应的 JavaScript 对象或 IIFE (立即执行函数表达式),具体取决于你的编译选项和枚举类型。这是一个关键点:TypeScript 的类型信息只在编译阶段用于类型检查,运行时并不存在(被称为“类型擦除”)。
通过这些简单的例子,你可以直观地理解不同基本类型的用法以及 TypeScript 如何在编译时进行类型检查。
2. 类型推断 (Type Inference)
即使你不显式地添加类型注解,TypeScript 也能根据变量的初始值推断出其类型。
“`typescript
// 在 Editor 中输入以下代码
let greeting = “Hello, world!”; // TypeScript 推断为 string 类型
// greeting = 123; // 错误:不能将 number 类型赋值给 string 类型
let count = 0; // TypeScript 推断为 number 类型
// count = “ten”; // 错误:不能将 string 类型赋值给 number 类型
let numbers = [1, 2, 3]; // TypeScript 推断为 number[] 类型
// numbers.push(“four”); // 错误:不能将 string 类型添加到 number 数组中
let obj = { name: “Bob”, age: 30 }; // TypeScript 推断为 { name: string, age: number } 类型
// obj.age = “thirty”; // 错误:不能将 string 类型赋值给 number 类型
// obj.address = “unknown”; // 错误:类型 ‘{ name: string; age: number; }’ 上不存在属性 ‘address’
“`
在 Editor 中输入这些代码,尝试取消注释那些错误行。你会看到 Errors 面板立即显示错误,即使你没有显式写出类型。这展示了 TypeScript 强大的类型推断能力,它减少了你需要手动编写的类型注解数量,同时仍然提供了类型安全。
3. 函数 (Functions)
TypeScript 可以为函数的参数和返回值添加类型注解。
“`typescript
// 在 Editor 中输入以下代码
// 带类型注解的函数
function add(x: number, y: number): number {
return x + y;
}
let result = add(5, 3); // 正确
// let errorResult = add(“hello”, 3); // 错误:参数类型不匹配
// 函数表达式
let myAdd: (x: number, y: number) => number =
function(x: number, y: number): number { return x + y; };
// 可选参数
function buildName(firstName: string, lastName?: string): string {
if (lastName)
return firstName + ” ” + lastName;
else
return firstName;
}
let name1 = buildName(“Bob”); // 正确
let name2 = buildName(“Bob”, “Adams”); // 正确
// let name3 = buildName(“Bob”, “Adams”, “Sr.”); // 错误:参数过多
// 默认参数值
function buildNameWithDefault(firstName: string, lastName: string = “Smith”): string {
return firstName + ” ” + lastName;
}
let nameWithDefault1 = buildNameWithDefault(“Bob”); // 相当于 buildNameWithDefault(“Bob”, “Smith”)
let nameWithDefault2 = buildNameWithDefault(“Bob”, “Adams”); // 覆盖默认值
// 剩余参数 (Rest Parameters)
function sumArray(firstArg: number, …restOfArgs: number[]): number {
let total = firstArg;
for (let i = 0; i < restOfArgs.length; i++) {
total += restOfArgs[i];
}
return total;
}
let totalSum = sumArray(1, 2, 3, 4, 5); // 正确
// 函数重载 (Overloads) – 允许你定义多种函数签名
function display(x: string): void; // 重载签名 1
function display(x: number): void; // 重载签名 2
function display(x: string | number): void { // 实现签名 (不能被外部调用)
console.log(x);
}
display(“hello”); // 正确,匹配签名 1
display(123); // 正确,匹配签名 2
// display(true); // 错误:没有匹配的签名
“`
在 Playground 中尝试这些函数示例。你会看到 TypeScript 在你调用函数时,会检查传递的参数数量和类型是否与函数签名匹配。可选参数和默认参数提供了灵活的函数定义方式,而剩余参数则允许你处理不确定数量的参数。函数重载则是在同一函数名下提供多种调用方式的强大工具。观察 JS Output,你会发现这些类型注解和重载签名都不会出现在最终的 JavaScript 代码中。
4. 接口 (Interfaces)
接口是 TypeScript 中非常核心的概念,用于定义对象的结构(形状)。
“`typescript
// 在 Editor 中输入以下代码
// 定义一个接口
interface Person {
firstName: string;
lastName: string;
age?: number; // 可选属性
readonly id: number; // 只读属性
}
// 创建一个对象,必须符合 Person 接口的结构
let user: Person = {
firstName: “John”,
lastName: “Doe”,
age: 30,
id: 12345 // 初始化时必须赋值
};
// user.id = 67890; // 错误:id 是只读属性,不能修改
// 如果缺少必需属性,会报错
// let user2: Person = {
// firstName: “Jane”,
// id: 54321
// }; // 错误:缺少属性 ‘lastName’
// 如果多了未定义的属性(取决于是否开启了 excess property checks)
// let user3: Person = {
// firstName: “Pete”,
// lastName: “Smith”,
// id: 98765,
// city: “New York” // 错误:对象字面量不能指定未知的属性
// };
// 接口也可以描述函数类型
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(src: string, sub: string): boolean {
let result = src.search(sub);
return result > -1;
};
// mySearch = function(src: number, sub: number): boolean { // 错误:参数类型不匹配 SearchFunc 接口
// return true;
// };
// 接口描述数组类型
interface StringArray {
[index: number]: string; // 定义索引签名:所有数字索引都必须是字符串
}
let myArray: StringArray;
myArray = [“Bob”, “Fred”];
// let myItem: string = myArray[0]; // 正确
// myArray[2] = 123; // 错误:索引 2 必须是字符串
“`
在 Playground 中,你会看到接口本身不会被编译到 JavaScript 中,它们仅用于类型检查。通过接口,你可以清晰地定义数据结构或函数类型,并在使用时强制遵循这些结构,从而提高代码的规范性和可维护性。尝试故意创建不符合接口的对象或函数,观察 Errors 面板给出的详细错误信息。
5. 类 (Classes)
TypeScript 增强了 JavaScript 的类,提供了更严格的类型检查和一些额外的特性(如访问修饰符)。
“`typescript
// 在 Editor 中输入以下代码
class Greeter {
greeting: string; // 属性默认是 public
constructor(message: string) {
this.greeting = message;
}
greet(): string {
return “Hello, ” + this.greeting;
}
}
let greeter = new Greeter(“world”); // 正确创建实例
// let greeter2 = new Greeter(123); // 错误:构造函数参数类型不匹配
console.log(greeter.greet()); // 调用方法
// 继承
class Animal {
name: string;
constructor(theName: string) { this.name = theName; }
move(distanceInMeters: number = 0) {
console.log(${this.name} moved ${distanceInMeters}m.
);
}
}
class Dog extends Animal {
bark() {
console.log(‘Woof! Woof!’);
}
// 覆盖父类方法
move(distanceInMeters = 5) {
console.log(‘Wagging tail…’);
super.move(distanceInMeters); // 调用父类的 move 方法
}
}
let dog = new Dog(“Buddy”);
dog.bark();
dog.move(10);
// 访问修饰符 (public, private, protected)
class PersonWithAccessModifiers {
public name: string; // 默认就是 public
private age: number; // 只能在类内部访问
protected city: string; // 只能在类内部和子类中访问
constructor(name: string, age: number, city: string) {
this.name = name;
this.age = age;
this.city = city;
}
private getAge(): number { // private 方法
return this.age;
}
protected getCity(): string { // protected 方法
return this.city;
}
}
class Employee extends PersonWithAccessModifiers {
private department: string;
constructor(name: string, age: number, city: string, department: string) {
super(name, age, city);
this.department = department;
}
public getElevatorPitch() {
// console.log(Hello, my name is ${this.name} and I am ${this.age} years old.
); // 错误:age 是 private
console.log(Hello, my name is ${this.name} and I work in ${this.department}. I live in ${this.getCity()}.
); // 正确:name 是 public, department 是当前类属性, getCity() 是 protected 方法
}
}
let howard = new Employee(“Howard”, 35, “Seattle”, “Sales”);
console.log(howard.name); // 正确:public 属性可访问
// console.log(howard.age); // 错误:private 属性不可访问
// console.log(howard.city); // 错误:protected 属性在外部不可访问
howard.getElevatorPitch(); // 正确调用 public 方法
“`
在 Playground 中,你可以看到类结构(属性、方法、构造函数)会被保留在 JS Output 中,但 TypeScript 独有的访问修饰符 (private
, protected
) 会被移除,因为 JavaScript 原生不支持这些修饰符(尽管 ES 提案中有了 #
语法表示私有)。TypeScript 的类特性主要是在编译阶段进行类型检查和访问控制。尝试从外部访问 private
或 protected
成员,你会立即在 Errors 面板看到错误。
6. 联合类型 (Union Types) 和交叉类型 (Intersection Types)
联合类型允许一个变量可以是几种类型之一,而交叉类型则将多个类型合并成一个类型。
“`typescript
// 在 Editor 中输入以下代码
// 联合类型:可以是 string 或 number 或 boolean
let myVariable: string | number | boolean;
myVariable = “hello”; // 正确
myVariable = 123; // 正确
myVariable = true; // 正确
// myVariable = [1, 2]; // 错误:不能是数组
// 函数参数可以是联合类型
function printId(id: number | string) {
// 在联合类型上,只能访问所有类型共有的属性/方法
console.log(“Your ID is: ” + id); // number 和 string 都可以与字符串相加
// console.log(id.toUpperCase()); // 错误:number 类型没有 toUpperCase 方法
// 需要使用类型收窄 (Type Narrowing) 来访问特定类型的方法
if (typeof id === “string”) {
console.log(id.toUpperCase()); // 正确:在 if 块内,id 被收窄为 string 类型
} else {
console.log(id.toFixed(2)); // 正确:在 else 块内,id 被收窄为 number 类型
}
}
printId(100.1234);
printId(“abc”);
// 交叉类型:合并多个类型为一个新类型,新类型拥有所有被合并类型的成员
interface Name {
firstName: string;
lastName: string;
}
interface Age {
age: number;
}
// PersonInfo 既有 Name 的属性,也有 Age 的属性
type PersonInfo = Name & Age;
let person: PersonInfo = {
firstName: “Peter”,
lastName: “Jones”,
age: 40
};
// let incompletePerson: PersonInfo = { firstName: “Peter”, lastName: “Jones” }; // 错误:缺少 age 属性
“`
联合类型是处理多种可能类型输入的强大工具,而交叉类型则用于构建更复杂的类型。在 Playground 中,你会看到这些类型定义本身不会出现在 JS Output 中,但 TypeScript 会根据这些定义在 Editor 中进行严格的类型检查。尝试在未使用类型收窄的情况下访问联合类型特有的属性,你会看到错误提示。
7. 泛型 (Generics)
泛型允许你编写可以处理多种类型的可重用代码,同时保持类型安全。
“`typescript
// 在 Editor 中输入以下代码
// 泛型函数:identity 函数接受一个任何类型的参数,并原样返回它
function identity
return arg;
}
// 使用时指定类型
let output1 = identity
let output2 = identity
// 使用时让 TypeScript 推断类型 (更常见)
let output3 = identity(“myString”); // TypeScript 推断 T 为 string
let output4 = identity(123); // TypeScript 推断 T 为 number
// 泛型接口
interface GenericIdentityFn
(arg: T): T;
}
let myIdentity: GenericIdentityFn
// 泛型类
class GenericNumber
zeroValue: T;
add: (x: T, y: T) => T; // add 方法必须接受两个 T 类型参数,返回 T 类型
constructor(zeroValue: T, addFunc: (x: T, y: T) => T) {
this.zeroValue = zeroValue;
this.add = addFunc;
}
}
let myGenericNumber = new GenericNumber
console.log(myGenericNumber.add(5, 10)); // 输出 15
let myGenericString = new GenericNumber
console.log(myGenericString.add(“Hello, “, “World!”)); // 输出 “Hello, World!”
// myGenericNumber = myGenericString; // 错误:类型不兼容 GenericNumber
“`
泛型是 TypeScript 中比较高级但非常重要的概念。它使得你的代码更加灵活和通用。在 Playground 中,你可以看到泛型类型参数(<T>
)在 JS Output 中会消失,因为它们只在编译时用于类型检查。尝试将一个 GenericNumber<number>
类型的变量赋值给 GenericNumber<string>
类型的变量,你会看到 TypeScript 如何阻止这种不安全的赋值。
利用 Playground 的 Options 面板
Playground 的 Options 面板提供了许多编译器设置,它们会影响 TypeScript 的编译行为和严格程度。探索这些选项是深入理解 TypeScript 的一个重要环节。
点击 Playground 界面上的 “Options” 或齿轮图标,你会看到一个面板展开,其中包含大量的复选框和下拉菜单。一些常用的重要选项包括:
- Target: 设置编译成的 JavaScript 版本(如 ES5, ES2015, ESNext)。改变这个选项会显著影响 JS Output 中的代码。例如,如果你使用
async/await
或类语法,选择 ES5 会看到更多的polyfill或不同的编译结果。 - Module: 设置模块系统(如 CommonJS, ESNext)。这会影响
import
/export
语句的编译方式。 - Strict: 这是一个总开关,启用一系列严格的类型检查选项。强烈建议在实际项目中开启
strict
模式,它能捕获更多的潜在错误。- 开启
strict
会同时开启noImplicitAny
,strictNullChecks
,strictFunctionTypes
,strictBindCallApply
,strictPropertyInitialization
,noImplicitThis
,useUnknownInCatchVariables
等多个子选项。
- 开启
- noImplicitAny: 如果 TypeScript 无法推断出变量的类型,并且你没有为其指定
any
类型,则会报错。这有助于避免意外使用any
,提高代码的类型安全性。 - strictNullChecks: 在这个模式下,
null
和undefined
不再是所有类型的子类型。这意味着你不能将null
或undefined
赋值给一个期望具体类型(如string
,number
)的变量,除非该类型显式地包含null
或undefined
(例如使用联合类型string | null
)。这是 TypeScript 中一个非常重要的严格选项,可以帮助避免很多运行时错误。 - noUnusedLocals: 如果你定义了一个局部变量但从未被使用,会报错。有助于清理死代码。
- noUnusedParameters: 如果你定义了一个函数参数但从未在函数体中使用,会报错。有助于清理无用参数。
实践建议:
- 尝试将
Target
从 ESNext 改为 ES5,观察 JS Output 的变化,理解不同 JS 版本下的编译差异。 - 开启
strict
选项,然后回到之前的代码示例,看看是否会突然出现新的错误。例如,如果一个函数参数没有类型注解,在noImplicitAny
开启时就会报错。如果一个变量可能为null
或undefined
但你直接使用了它的方法,在strictNullChecks
开启时会报错。这会让你更深入地理解这些严格模式的好处。 - 尝试修改其他选项,观察它们对 Errors 和 JS Output 的影响。
通过 Playground 的 Options 面板,你可以直观地学习到 TypeScript 编译器的行为以及不同的配置如何影响类型检查和代码输出。
Playground 的其他有用功能
- Sharing (分享): Playground 右上角通常有一个 “Share” 或类似图标。点击它可以生成一个包含当前代码和选项的唯一 URL。你可以将这个 URL 分发给其他人,他们打开链接后会看到和你完全相同的 Playground 状态。这是询问 TypeScript 问题、演示 Bug、或分享代码示例的极好方式。
- Download (下载): 有时你可能想将 Playground 中的代码保存到本地。有些 Playground 版本提供下载功能,或者你可以直接复制粘贴 Editor 中的代码。
- Plugins / Transformers: 高级用户可以探索 Plugins 或 Custom Transformers 选项,这允许你在编译过程中插入自定义逻辑,用于代码转换或更复杂的类型检查。这对于学习如何扩展 TypeScript 编译器很有帮助,但对于初学者来说不是必需的。
什么时候应该从 Playground 转向本地开发环境?
Playground 是一个非常棒的学习和实验工具,但它毕竟是一个单文件、在线的环境。当你需要处理以下情况时,就应该考虑搭建本地的 TypeScript 开发环境了:
- 多文件项目: 实际项目通常包含多个相互依赖的 TypeScript 文件。Playground 只能处理一个文件。
- 模块化开发: 需要使用
import
/export
来组织代码,并在文件之间共享类型或值。 - 集成构建工具: 将 TypeScript 编译集成到 Webpack, Parcel, Vite 等构建流程中。
- 使用第三方库: 需要安装和使用通过 npm 管理的 TypeScript 库(
.d.ts
类型声明文件)。 - IDE 的完整功能: 利用 VS Code 等 IDE 提供的更强大、更深入的智能感知、重构工具、调试功能。
- 项目配置管理: 通过
tsconfig.json
文件来统一管理复杂的编译器选项。
搭建本地环境也很简单,通常只需要安装 Node.js 和 npm/yarn,然后通过 npm 安装 TypeScript (npm install -g typescript
或作为项目依赖 npm install typescript --save-dev
),创建一个 tsconfig.json
文件,就可以开始使用 tsc
命令行工具或集成到构建流程中进行编译了。
使用 Playground 学习 TypeScript 的技巧总结
- 从小处着手: 不要试图在一个文件中实现所有东西。每次关注一个特定的 TypeScript 特性,编写简短的代码片段来演示它。
- 积极观察 Errors 面板: TypeScript 的错误信息通常非常详细和有用。仔细阅读它们,理解为什么会出错,这是学习类型系统的关键。
- 查看 JS Output: 了解 TypeScript 如何编译成 JavaScript,这有助于你理解类型擦除和运行时行为。
- 探索 Options 面板: 尝试不同的编译器选项,尤其是
strict
相关的选项,理解它们如何影响类型检查的严格性。 - 利用 Sharing 功能: 当遇到问题时,生成 Playground 链接并在社区(如 Stack Overflow、GitHub Discussions)提问,这能让别人更容易帮助你。
- 不要怕犯错: 在 Playground 中,你可以随意尝试,不用担心破坏任何东西。这是学习新事物的最佳方式。
结论
TypeScript 是一个强大的工具,它可以显著提升 JavaScript 项目的开发体验和代码质量。而 TypeScript Playground 则是入门和精进 TypeScript 的最简便、最直观的平台之一。
通过 Playground,你可以零成本、零配置地立即开始编写 TypeScript 代码,实时看到类型检查的结果和编译后的 JavaScript。它是你理解 TypeScript 基础概念(如基本类型、类型推断、函数、接口、类、联合/交叉类型、泛型)的最佳伙伴。同时,通过探索编译选项,你还能深入了解 TypeScript 编译器的行为和如何配置你的项目。
无论你是完全的新手,还是想尝试 TypeScript 的某个特定特性,亦或是需要快速验证一段类型复杂的代码片段,TypeScript Playground 都能为你提供一个便捷、高效的实践环境。
现在,就打开 TypeScript Playground,开始你的 TypeScript 探索之旅吧!动手实践是掌握任何新技术的最好方法,而 Playground 让实践变得前所未有的简单。祝你在 TypeScript 的学习道路上一切顺利!