TypeScript语法(类型注解:、类型断言as、联合类型|、类型守卫typeof、交叉类型、类型别名type、类型保护is)
文章目录
- 引言
- TypeScript的核心优势
- 1. **静态类型检查**:在编译时捕获类型错误,减少运行时错误
- 2. **更好的开发体验**:提供更完善的代码提示和自动补全
- 3. **面向对象特性**:支持类、接口、继承等面向对象编程特性
- 4. **向后兼容**:所有JavaScript代码都是有效的TypeScript代码
- 5. **与现代工具链无缝集成**:支持主流编辑器和构建工具
- 基础语法详解
- 1. 类型注解
- 2. 变量声明
- 3. 基本数据类型
- - `string`:字符串
- - `number`:数值
- - `boolean`:布尔值
- - `null`:空值
- - `undefined`:未定义
- - `any`:任意类型(不推荐在大型项目中使用)
- - `void`:无返回值
- - `never`:永远不返回的函数类型
- - `object`:对象类型
- 代码示例
- 4. 接口(Interfaces)
- 5. 枚举(Enums)
- 6. 泛型(Generics)
- 7. 类型断言
- 8. 类(Classes)
- 9. 函数
- 10. 数组与元组
- 11. 类型推断
- 高级语法特性
- 1. 联合类型(Union Types)
- 2. 交叉类型(Intersection Types)
- 3. 类型别名(Type Aliases)
- 4. 类型保护(Type Guards)
- 5. 模块系统
- 实用技巧与最佳实践
- 1. **使用类型推断**:尽可能让TypeScript推断类型,减少冗余代码
- 2. **避免使用any**:在大型项目中,使用any会破坏TypeScript的类型检查优势
- 3. **使用严格模式**:在tsconfig.json中启用"strict": true,启用所有严格的类型检查
- 4. **使用接口定义结构**:而不是使用类型别名定义对象结构
- 5. **合理使用泛型**:在需要类型安全的通用代码中使用泛型
- 6. **使用类型守卫**:在处理联合类型时,使用类型守卫来缩小类型范围
- 7. **利用TypeScript Playground**:在编写和测试TypeScript代码时使用在线Playground
- 总结
引言
TypeScript是微软开发的一种开源编程语言,它是JavaScript的超集,添加了可选的静态类型系统和基于类的面向对象编程特性。TypeScript的设计目标是让开发大型应用程序更加容易,同时保持与JavaScript的兼容性。通过引入静态类型检查,TypeScript能够在编译阶段捕获潜在错误,显著提高代码质量和可维护性。
TypeScript的核心优势
1. 静态类型检查:在编译时捕获类型错误,减少运行时错误
2. 更好的开发体验:提供更完善的代码提示和自动补全
3. 面向对象特性:支持类、接口、继承等面向对象编程特性
4. 向后兼容:所有JavaScript代码都是有效的TypeScript代码
5. 与现代工具链无缝集成:支持主流编辑器和构建工具
基础语法详解
1. 类型注解
TypeScript最核心的特性是类型系统。在变量、函数参数和返回值上可以显式指定类型。
// 基本类型注解
let name: string = "Alice";
let age: number = 30;
let isStudent: boolean = true;
let count: number = 100;
2. 变量声明
TypeScript支持多种变量声明方式,与JavaScript类似,但增加了类型安全。
// 使用let声明变量
let firstName: string = "John";
let lastName: string;
lastName = "Doe";// 使用const声明常量
const PI: number = 3.14159;
const MAX_USERS: number = 1000;// 类型推断
let message = "Hello, TypeScript!"; // 类型推断为string
message = "Updated message"; // 正确
// message = 42; // 错误:类型不匹配
3. 基本数据类型
TypeScript支持以下基本数据类型:
- string
:字符串
- number
:数值
- boolean
:布尔值
- null
:空值
- undefined
:未定义
- any
:任意类型(不推荐在大型项目中使用)
- void
:无返回值
- never
:永远不返回的函数类型
- object
:对象类型
代码示例
// 字符串
let greeting: string = "Hello";
let firstName: string = "John";
let lastName: string = "Doe";// 数值
let age: number = 30;
let price: number = 19.99;
let decimal: number = 6.022e23;// 布尔值
let isMember: boolean = true;
let isPublished: boolean = false;// 空值和未定义
let nullValue: null = null;
let undefinedValue: undefined = undefined;// 任意类型(谨慎使用)
let data: any = "Hello";
data = 42;
data = true;// 无返回值(注意:void 函数 - 会正常返回 undefined)
function logMessage(message: string): void {console.log(message);
}// 永远不返回的函数
function error(message: string): never {throw new Error(message);
}
4. 接口(Interfaces)
接口用于定义对象的结构,确保对象符合预期的形状。
注意:TS接口是一种类型定义,如:
interface Person {name: string; // 属性age: number; // 属性sayHello(): void; // 方法签名
interface GenericIdentityFn<T> {(arg: T): T;
}
// 定义接口
interface User {id: number;name: string;email: string;isActive?: boolean; // 可选属性roles: string[];
}// 使用接口
const user1: User = {id: 1,name: "John Doe",email: "john@example.com",isActive: true,roles: ["admin", "user"]
};// 可选属性
const user2: User = {id: 2,name: "Jane Smith",email: "jane@example.com",roles: ["user"]
};// 只读属性
interface ReadonlyUser {readonly id: number;name: string;
}const readOnlyUser: ReadonlyUser = {id: 3,name: "ReadOnly User"
};// readOnlyUser.id = 4; // 错误:只读属性不能修改
5. 枚举(Enums)
枚举用于定义一组命名常量,提高代码可读性。
// 数字枚举
enum Color {Red,Green,Blue
}let selectedColor: Color = Color.Green;
console.log(selectedColor); // 输出 1// 字符串枚举
enum Direction {Up = "UP",Down = "DOWN",Left = "LEFT",Right = "RIGHT"
}let direction: Direction = Direction.Right;
console.log(direction); // 输出 "RIGHT"// 常量枚举
const enum Size {Small = 1,Medium = 2,Large = 3
}let currentSize: Size = Size.Medium;
注意:没有标数字就默认从0递增,跟C++一样
6. 泛型(Generics)
泛型提供了一种机制,使组件能够与其使用的其他类型的某些方面无关地编写,从而实现更强的功能抽象。
// 简单泛型函数
function identity<T>(arg: T): T {return arg;
}let output = identity<string>("Hello"); // 输出 "Hello"
let output2 = identity<number>(42); // 输出 42// 泛型接口
interface GenericIdentityFn<T> {(arg: T): T;
}function identityFn<T>(arg: T): T {return arg;
}let myIdentity: GenericIdentityFn<number> = identityFn;// 泛型类
class GenericNumber<T> {zeroValue: T;add: (x: T, y: T) => T;constructor(zeroValue: T, add: (x: T, y: T) => T) {this.zeroValue = zeroValue;this.add = add;}
}let numberGeneric = new GenericNumber<number>(0, (x, y) => x + y);
console.log(numberGeneric.add(1, 2)); // 输出 3
注意:
<T>
在TypeScript中是类型参数的声明,表示这是一个泛型函数。<T>
中T是一个类型变量(占位符),表示"这个函数可以处理任何类型"。
解释:
interface GenericIdentityFn<T> {(arg: T): T;
}
GenericIdentityFn<T>
:这是一个泛型接口,<T>
表示类型参数,可以接受任何类型{ (arg: T): T; }
:接口定义了一个函数类型,该函数:- 接受一个类型为
T
的参数arg
- 返回类型为
T
的结果
- 接受一个类型为
这个接口实际上描述的是一个"身份函数"(identity function),它接收一个参数并返回相同的参数,但保持类型不变。
7. 类型断言
当开发者对值有更多了解,但TypeScript编译器不知道时,可以使用类型断言。
// 类型断言
let someValue: any = "This is a string";
let strLength: number = (<string>someValue).length; // 类型断言// 或者使用as关键字
let strLength2: number = (someValue as string).length;// 类型断言在DOM操作中常用
let input = document.getElementById("myInput") as HTMLInputElement;
input.value = "Hello, TypeScript!";
8. 类(Classes)
TypeScript支持基于类的面向对象编程。
// 基本类
class Person {name: string;age: number;constructor(name: string, age: number) {this.name = name;this.age = age;}greet(): string {return `Hello, my name is ${this.name} and I am ${this.age} years old.`;}
}const person = new Person("Alice", 30);
console.log(person.greet()); // 输出: Hello, my name is Alice and I am 30 years old.// 继承
class Employee extends Person {department: string;constructor(name: string, age: number, department: string) {super(name, age);this.department = department;}getDetails(): string {return `${super.greet()} I work in ${this.department}.`;}
}const employee = new Employee("Bob", 35, "Engineering");
console.log(employee.getDetails()); // 输出: Hello, my name is Bob and I am 35 years old. I work in Engineering.// 访问修饰符
class Car {private make: string;protected model: string;public year: number;constructor(make: string, model: string, year: number) {this.make = make;this.model = model;this.year = year;}getMake(): string {return this.make;}
}class ElectricCar extends Car {private batteryCapacity: number;constructor(make: string, model: string, year: number, batteryCapacity: number) {super(make, model, year);this.batteryCapacity = batteryCapacity;}getBatteryCapacity(): number {return this.batteryCapacity;}// 可以访问protected属性getModel(): string {return this.model;}
}
9. 函数
TypeScript支持函数类型、箭头函数、函数重载等。
// 函数类型
function add(x: number, y: number): number {return x + y;
}// 箭头函数
const subtract = (x: number, y: number): number => x - y;// 函数重载
function formatName(firstName: string, lastName: string): string;
function formatName(name: string): string;
function formatName(firstNameOrName: string, lastName?: string): string {if (lastName) {return `${firstNameOrName} ${lastName}`;} else {return firstNameOrName;}
}console.log(formatName("John", "Doe")); // "John Doe"
console.log(formatName("Jane")); // "Jane"// 可选参数和默认参数
function printUser(id: number, name: string, age?: number, gender: string = "Unknown") {console.log(`ID: ${id}, Name: ${name}, Age: ${age}, Gender: ${gender}`);
}printUser(1, "Alice"); // ID: 1, Name: Alice, Age: undefined, Gender: Unknown
printUser(2, "Bob", 30, "Male"); // ID: 2, Name: Bob, Age: 30, Gender: Male// 剩余参数
function sum(...numbers: number[]): number {return numbers.reduce((acc, curr) => acc + curr, 0);
}console.log(sum(1, 2, 3, 4)); // 10
10. 数组与元组
// 数组
let numbers: number[] = [1, 2, 3];
let names: Array<string> = ["Alice", "Bob", "Charlie"];// 元组(固定长度和类型的数组)
let person: [string, number] = ["Alice", 30];
console.log(person[0]); // "Alice"
console.log(person[1]); // 30// 元组类型
let personInfo: [string, number, boolean] = ["Alice", 30, true];
11. 类型推断
TypeScript具有强大的类型推断能力,可以自动推断变量类型。
let message = "Hello, TypeScript!"; // 类型推断为string
let count = 42; // 类型推断为number// 函数返回类型推断
function addNumbers(a: number, b: number): number {return a + b;
}// 对象字面量类型推断
const user = {id: 1,name: "Alice"
}; // 类型推断为{ id: number; name: string; }
高级语法特性
1. 联合类型(Union Types)
联合类型允许变量可以是多种类型中的一种。
// 联合类型
function printId(id: number | string) {console.log(`ID: ${id}`);
}printId(100); // 正确
printId("100"); // 正确
// printId(true); // 错误// 类型守卫
function printIdWithGuard(id: number | string) {if (typeof id === "string") {console.log(`ID is a string: ${id.toUpperCase()}`);} else {console.log(`ID is a number: ${id}`);}
}
2. 交叉类型(Intersection Types)
交叉类型将多个类型合并为一个类型。
interface CanDrive {drive(): void;
}interface CanSwim {swim(): void;
}type CanDriveAndSwim = CanDrive & CanSwim;function travel(vehicle: CanDriveAndSwim) {vehicle.drive();vehicle.swim();
}class Car implements CanDrive {drive() {console.log("Driving a car");}
}class Boat implements CanSwim {swim() {console.log("Swimming in a boat");}
}// 无法直接组合Car和Boat
// 但可以创建一个同时实现两者的类
class AmphibiousVehicle implements CanDrive & CanSwim {drive() {console.log("Driving the amphibious vehicle");}swim() {console.log("Swimming with the amphibious vehicle");}
}const amphibious = new AmphibiousVehicle();
travel(amphibious);
3. 类型别名(Type Aliases)
类型别名可以为类型创建新名称。
type ID = number | string;
type User = {id: ID;name: string;email: string;
};function getUser(id: ID): User {// 实现...return { id, name: "John Doe", email: "john@example.com" };
}
4. 类型保护(Type Guards)
类型保护用于在代码中缩小类型范围。
interface Bird {fly(): void;layEggs(): void;
}interface Fish {swim(): void;layEggs(): void;
}function isBird(animal: Bird | Fish): animal is Bird {return (animal as Bird).fly !== undefined;// 或者:return 'fly' in animal;
}function describeAnimal(animal: Bird | Fish) {if (isBird(animal)) {animal.fly();} else {animal.swim();}
}
参考文章:TypeScript类型守卫(类型保护)
5. 模块系统
TypeScript支持模块化组织代码。
// mathUtils.ts
export function add(a: number, b: number): number {return a + b;
}export function subtract(a: number, b: number): number {return a - b;
}// main.ts
import { add, subtract } from './mathUtils';console.log(add(1, 2)); // 3
console.log(subtract(5, 3)); // 2
实用技巧与最佳实践
1. 使用类型推断:尽可能让TypeScript推断类型,减少冗余代码
2. 避免使用any:在大型项目中,使用any会破坏TypeScript的类型检查优势
3. 使用严格模式:在tsconfig.json中启用"strict": true,启用所有严格的类型检查
4. 使用接口定义结构:而不是使用类型别名定义对象结构
5. 合理使用泛型:在需要类型安全的通用代码中使用泛型
6. 使用类型守卫:在处理联合类型时,使用类型守卫来缩小类型范围
7. 利用TypeScript Playground:在编写和测试TypeScript代码时使用在线Playground
总结
TypeScript通过添加静态类型系统,显著提高了JavaScript代码的可维护性和可靠性。从基础语法到高级特性,TypeScript提供了丰富的工具来帮助开发者编写更健壮、更易维护的代码。
掌握TypeScript语法不仅仅是学习新的关键字,更是掌握一种更好的编程思维。随着TypeScript在前端和后端开发中的广泛应用,掌握TypeScript将成为现代开发者的核心技能之一。