TypeScript(简称 TS)是 JavaScript 的一个超集,由微软开发。简单来说,它就是在 JavaScript 的基础上增加了静态类型检查。那静态类型检查有啥好处呢?举个例子,在 JavaScript 里,我们写代码时可能会不小心把一个变量的类型用错,像这样:
// JavaScript 代码
let num = 10;
num = "hello"; // 这里把数字类型的变量赋值为字符串,运行时可能会出问题
但在 TypeScript 里,我们可以给变量指定类型,一旦类型不匹配,编译器就会报错,帮我们提前发现问题。
// TypeScript 代码
let num: number = 10;
// num = "hello"; // 这里会报错,因为类型不匹配
要使用 TypeScript,首先得安装它。打开终端,输入以下命令:
npm install -g typescript
这里的 -g
表示全局安装,这样你就可以在任何项目里使用 TypeScript 了。
创建一个新的项目文件夹,然后在终端进入这个文件夹,输入以下命令初始化项目:
npm init -y
这个命令会快速创建一个 package.json
文件,记录项目的依赖和配置信息。
在项目根目录下创建一个 tsconfig.json
文件,这是 TypeScript 的配置文件。可以使用以下命令快速生成默认配置:
npx tsc --init
npx
是 npm 自带的工具,用于执行本地安装的包。生成的 tsconfig.json
文件里有很多配置项,我们可以根据需要进行修改。
在 TypeScript 里,数字类型可以表示整数和浮点数。
let age: number = 25;
let price: number = 9.99;
字符串类型用于表示文本。
let name: string = "张三";
let message: string = `你好,${name}`; // 模板字符串
布尔类型只有两个值:true
和 false
。
let isStudent: boolean = true;
有两种方式定义数组类型。
[]
let numbers: number[] = [1, 2, 3];
Array<元素类型>
let names: Array<string> = ["张三", "李四", "王五"];
元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。
let person: [string, number] = ["张三", 25];
这里的 person
元组第一个元素是字符串类型,第二个元素是数字类型。
枚举类型用于定义一组命名常量。
enum Color {
Red,
Green,
Blue
}
let myColor: Color = Color.Green;
默认情况下,枚举成员的值从 0 开始递增。也可以手动指定值:
enum Color {
Red = 1,
Green = 2,
Blue = 3
}
当我们不确定变量的类型时,可以使用 any
类型。
let value: any = 10;
value = "hello";
value = true;
不过要尽量少用 any
类型,因为它会让 TypeScript 的类型检查失去作用。
void
类型通常用于表示函数没有返回值。
function sayHello(): void {
console.log("Hello!");
}
null
和 undefined
是两种特殊的类型。
let n: null = null;
let u: undefined = undefined;
在默认情况下,null
和 undefined
是所有类型的子类型,但在 strictNullChecks
为 true
的情况下,它们只能赋值给 any
和各自的类型。
在 TypeScript 里,我们可以给函数的参数和返回值指定类型。
function add(a: number, b: number): number {
return a + b;
}
let result = add(1, 2);
有时候,函数的某些参数不是必须的,我们可以使用可选参数。在参数名后面加 ?
表示可选参数。
function greet(name: string, message?: string): string {
if (message) {
return `${message}, ${name}`;
} else {
return `Hello, ${name}`;
}
}
let greeting1 = greet("张三");
let greeting2 = greet("李四", "你好");
我们还可以给参数设置默认值。
function multiply(a: number, b: number = 1): number {
return a * b;
}
let product1 = multiply(5); // 相当于 multiply(5, 1)
let product2 = multiply(5, 2);
当函数的参数数量不确定时,可以使用剩余参数。
function sum(...numbers: number[]): number {
let total = 0;
for (let num of numbers) {
total += num;
}
return total;
}
let resultSum = sum(1, 2, 3, 4, 5);
接口用于定义对象的形状,规定对象必须包含哪些属性和方法。
interface Person {
name: string;
age: number;
sayHello(): void;
}
let p: Person = {
name: "张三",
age: 25,
sayHello() {
console.log(`Hello, my name is ${this.name}`);
}
};
接口还可以有可选属性和只读属性。
在属性名后面加 ?
表示可选属性。
interface Person {
name: string;
age?: number; // 可选属性
sayHello(): void;
}
在属性名前面加 readonly
表示只读属性,一旦赋值就不能再修改。
interface Point {
readonly x: number;
readonly y: number;
}
let point: Point = { x: 10, y: 20 };
// point.x = 30; // 这里会报错,因为 x 是只读属性
TypeScript 支持面向对象编程,类是其中的重要概念。
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
sayHello() {
console.log(`Hello, I'm ${this.name}`);
}
}
let cat = new Animal("小猫");
cat.sayHello();
这里的 constructor
是类的构造函数,用于初始化对象的属性。
类可以通过 extends
关键字实现继承。
class Dog extends Animal {
bark() {
console.log("汪汪汪!");
}
}
let dog = new Dog("小狗");
dog.sayHello();
dog.bark();
TypeScript 有三种访问修饰符:public
、private
和 protected
。
public
:公共的,类的内部和外部都可以访问。private
:私有的,只能在类的内部访问。protected
:受保护的,只能在类的内部和子类中访问。class Person {
private age: number;
protected name: string;
public constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
public getAge() {
return this.age;
}
}
class Student extends Person {
public study() {
console.log(`${this.name} is studying.`); // 可以访问 protected 属性
// console.log(this.age); // 不能访问 private 属性
}
}
静态属性和方法属于类本身,而不是类的实例。
class MathUtils {
static PI: number = 3.14;
static calculateCircleArea(radius: number): number {
return MathUtils.PI * radius * radius;
}
}
let area = MathUtils.calculateCircleArea(2);
泛型是一种创建可复用组件的方式,它可以让组件支持多种数据类型。
function identity<T>(arg: T): T {
return arg;
}
let result1 = identity<string>("hello");
let result2 = identity<number>(123);
这里的
是泛型类型参数,它可以在函数调用时指定具体的类型。
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x, y) {
return x + y;
};
有时候,我们需要对泛型类型进行一些约束,确保它满足某些条件。
interface Lengthwise {
length: number;
}
function getLength<T extends Lengthwise>(arg: T): number {
return arg.length;
}
let strLength = getLength("hello");
// let numLength = getLength(123); // 这里会报错,因为数字类型没有 length 属性
通过以上的学习,我们了解了 TypeScript 的基本概念和用法,包括类型系统、函数、接口、类和泛型等。TypeScript 可以帮助我们编写更健壮、更易维护的代码,尤其适合大型项目。希望这篇教程能帮助你快速入门 TypeScript,跟上程序员的脚步!
现在,你可以动手实践一下,用 TypeScript 来开发一些小项目,加深对它的理解和掌握。加油!