学习:TypeScript (1)

TypeScript 简介

TypeScript 是由微软开发的一种编程语言,它是 JavaScript 的超集(TypeScript⊇JavaScript),于 2012 年首次发布。TypeScript 添加了静态类型和其他特性到 JavaScript 中,使得大型应用程序的开发更加容易和维护性更强。

TypeScript 的主要特点:

  1. 静态类型系统 - 允许在编码阶段捕获类型错误
  2. 面向对象编程 - 支持类、接口、继承等特性
  3. 现代 JavaScript 特性 - 支持最新的 ECMAScript 标准
  4. 更好的 IDE 支持 - 提供更精准的代码补全、重构和导航
  5. 编译时错误检查 - 在代码运行前发现潜在问题

JavaScript 与 TypeScript 的主要区别

让我通过一个表格和代码示例来展示它们的主要区别:

特性 JavaScript TypeScript
类型系统 动态类型 静态类型(可选)
编译 解释执行 编译为 JavaScript
错误检测 运行时 编译时 + 运行时
代码补全 基础 更精准
学习曲线 较低 较陡峭

代码示例对比

JavaScript 示例:
javascript 复制代码
function calculateTotal(price, quantity) {
    return price * quantity;
}

// 调用函数
let total = calculateTotal(10, 5);
console.log(total); // 输出: 50

// 可能的错误 - JavaScript 不会报错
let wrongTotal = calculateTotal("10", "5"); 
console.log(wrongTotal); // 输出: "50" (字符串拼接)
TypeScript 示例:
TypeScript 复制代码
function calculateTotal(price: number, quantity: number): number {
    return price * quantity;
}

// 正确调用
let total: number = calculateTotal(10, 5);
console.log(total); // 输出: 50

// 错误调用 - TypeScript 会在编译时报错
// let wrongTotal = calculateTotal("10", "5"); 
// 错误: 类型"string"的参数不能赋给类型"number"的参数

主要差异详解

1.类型注解

  • JavaScript: 不需要显式声明类型
  • TypeScript: 可以使用类型注解明确变量、函数参数和返回值的类型

2.接口定义

  • TypeScript 允许定义接口,强制对象结构符合特定形状
TypeScript 复制代码
// TypeScript 接口示例
interface User {
    id: number;
    name: string;
    email?: string; // 可选属性
}

function processUser(user: User) {
    console.log(`Processing user: ${user.name}`);
}

// JavaScript 中没有这种强制结构的方式

3.枚举类型

  • TypeScript 提供枚举,JavaScript 没有原生枚举支持
TypeScript 复制代码
// TypeScript 枚举示例
enum Color {
    Red,
    Green,
    Blue
}

let favoriteColor: Color = Color.Blue;

4.泛型

  • TypeScript 支持泛型,使代码更加灵活和可重用
TypeScript 复制代码
// TypeScript 泛型示例
function identity<T>(arg: T): T {
    return arg;
}

let output = identity<string>("myString");

5.访问修饰符

  • TypeScript 支持 public、private 和 protected 访问修饰符
TypeScript 复制代码
class Person {
    private name: string;
    public age: number;
    
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
    
    public getInfo(): string {
        return `${this.name} is ${this.age} years old`;
    }
}

为什么要学习 TypeScript?

  1. 减少运行时错误:通过类型检查在开发阶段捕获更多错误
  2. 提高代码质量:类型系统使代码更加自文档化
  3. 更好的团队协作:明确的类型定义使团队成员更容易理解代码
  4. 强大的工具支持:提供更精确的自动补全、重构和导航功能
  5. 现代 JavaScript 特性:支持最新的 ECMAScript 特性,并可编译到旧版本

TypeScript 安装

在安装 TypeScript 之前,请确保您的系统已安装:

  • Node.js(建议版本 14 或更高)
  • npm(通常随 Node.js 一起安装)

方法一:全局安装(推荐初学者)

全局安装后,可以在任何项目中使用 TypeScript:

TypeScript 复制代码
npm install -g typescript

安装完成后,检查版本:

TypeScript 复制代码
tsc -v

方法二:项目级安装

在特定项目中安装 TypeScript:

TypeScript 复制代码
# 初始化项目(如果还没有 package.json)
npm init -y

# 安装 TypeScript 作为开发依赖
npm install --save-dev typescript

使用项目级安装的 TypeScript:

TypeScript 复制代码
# npx 命令会使用项目本地安装的版本
npx tsc -v

验证安装

创建一个简单的 TypeScript 文件来测试安装:

1.创建一个名为 test.ts 的文件:

TypeScript 复制代码
function greet(name: string): string {
    return `Hello, ${name}!`;
}

console.log(greet("TypeScript"));

2.编译该文件:

复制代码
tsc test.ts

3.运行生成的 JavaScript 文件:

复制代码
node test.js

输出: Hello, TypeScript!

配置 TypeScript 项目

对于正式项目,建议创建一个 TypeScript 配置文件:

1.生成 tsconfig.json 文件:

复制代码
tsc --init

2.常用配置选项(编辑生成的 tsconfig.json ):

TypeScript 复制代码
{
  "compilerOptions": {
    "target": "ES2020",          // 编译目标 JavaScript 版本
    "module": "commonjs",        // 使用的模块系统
    "outDir": "./dist",          // 输出目录
    "rootDir": "./src",          // 源代码目录
    "strict": true,              // 启用所有严格类型检查选项
    "esModuleInterop": true,     // 启用更好的 CommonJS 模块互操作性
    "skipLibCheck": true,        // 跳过库文件的类型检查
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],       // 包含的文件
  "exclude": ["node_modules"]    // 排除的目录
}

默认的

TypeScript 复制代码
{
  // Visit https://aka.ms/tsconfig to read more about this file
  "compilerOptions": {
    // File Layout
    // "rootDir": "./src",
    // "outDir": "./dist",

    // Environment Settings
    // See also https://aka.ms/tsconfig/module
    "module": "nodenext",
    "target": "esnext",
    "types": [],
    // For nodejs:
    // "lib": ["esnext"],
    // "types": ["node"],
    // and npm install -D @types/node

    // Other Outputs
    "sourceMap": true,
    "declaration": true,
    "declarationMap": true,

    // Stricter Typechecking Options
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,

    // Style Options
    // "noImplicitReturns": true,
    // "noImplicitOverride": true,
    // "noUnusedLocals": true,
    // "noUnusedParameters": true,
    // "noFallthroughCasesInSwitch": true,
    // "noPropertyAccessFromIndexSignature": true,

    // Recommended Options
    "strict": true,
    "jsx": "react-jsx",
    "verbatimModuleSyntax": true,
    "isolatedModules": true,
    "noUncheckedSideEffectImports": true,
    "moduleDetection": "force",
    "skipLibCheck": true,
  }
}

常用编译命令

复制代码
# 编译单个文件
tsc filename.ts

# 监视文件变化,自动编译
tsc filename.ts --watch

# 使用配置文件编译项目
tsc

# 监视整个项目
tsc --watch

安装额外工具

安装 TypeScript 声明文件

许多 JavaScript 库有类型定义,可以安装以获得更好的类型支持:

复制代码
# 安装 Node.js 类型定义
npm install --save-dev @types/node

# 安装特定库的类型定义
npm install --save-dev @types/jquery

安装 ts-node(直接运行 TypeScript 文件)

复制代码
npm install -g ts-node

使用 ts-node 运行 TypeScript 文件而无需先编译:

复制代码
ts-node filename.ts

在代码编辑器中设置 TypeScript

Visual Studio Code

VS Code 对 TypeScript 有内置支持,但您可以:

  1. 安装 "TypeScript Importer" 扩展自动导入模块
  2. 安装 "TypeScript Hero" 更好地组织导入

其他编辑器

  • WebStorm:内置 TypeScript 支持
  • Sublime Text:安装 "TypeScript" 插件
  • Atom:安装 "atom-typescript" 包

TypeScript 特性

TypeScript 作为 JavaScript 的超集,添加了许多强大的类型系统和编程特性。

1. 静态类型系统

TypeScript 最显著的特性是静态类型系统,它允许在编译时检测类型错误,而不是等到运行时才发现。

基本类型注解

TypeScript 复制代码
// 基本类型
let isDone: boolean = false;
let decimal: number = 6;
let color: string = "blue";
let list: number[] = [1, 2, 3];
let x: [string, number] = ["hello", 10]; // 元组

// 输出基本类型
console.log("基本类型输出:");
console.log("isDone:", isDone);
console.log("decimal:", decimal);
console.log("color:", color);
console.log("list:", list);
console.log("x:", x);

// 枚举
enum Color {
  Red,
  Green,
  Blue,
}
let c: Color = Color.Green;

// 输出枚举
console.log("\n枚举输出:");
console.log("Color.Green:", c);

// any 类型 - 可以是任意类型
let notSure: any = 4;
notSure = "maybe a string";

// 输出any类型
console.log("\nany类型输出:");
console.log("notSure:", notSure);


// void 类型 - 通常用于函数返回值
function warnUser(): void {
  console.log("This is a warning message");
}

2. 接口 (Interfaces)

接口定义了对象的结构,确保对象符合特定的形状。

TypeScript 复制代码
interface Person {
    name: string;
    age: number;
    // 可选属性
    nickname?: string;
    // 只读属性
    readonly id: number;
}

function greetPerson(person: Person): string {
    return `Hello, ${person.name}!`;
}

// 正确使用
let user: Person = { id: 1, name: "Alice", age: 30 };
greetPerson(user);

// 错误 - 缺少必需属性
// let invalidUser: Person = { name: "Bob" };

3. 类 (Classes)

TypeScript 提供了完整的基于类的面向对象编程支持。

TypeScript 复制代码
class Animal {
  // 私有属性
  private name: string;

  // 受保护的属性
  protected species: string;

  // 公共属性
  public age: number;

  constructor(name: string, species: string, age: number) {
    this.name = name;
    this.species = species;
    this.age = age;
  }

  // 公共方法
  public move(distanceInMeters: number): void {
    console.log(`${this.name} moved ${distanceInMeters}m.`);
  }

  // 私有方法
  private sleep(): void {
    console.log(`${this.name} is sleeping.`);
  }
}

// 继承
class Dog extends Animal {
  constructor(name: string, age: number) {
    super(name, "Canine", age);
  }

  public bark(): void {
    console.log("Woof! Woof!");
  }
}

// 创建实例并调用方法
const myDog = new Dog("Buddy", 3);
console.log(`Dog's name: ${myDog["name"]}`); // 注意:name是私有属性,这里只是为了演示
console.log(`Dog's age: ${myDog.age}`);
myDog.bark();
myDog.move(10);

4. 泛型 (Generics)

泛型使代码更加灵活和可重用,同时保持类型安全。

TypeScript 复制代码
// 泛型函数
function identity<T>(arg: T): T {
  return arg;
}

let output1 = identity<string>("myString");
let output2 = identity<number>(100);

// 泛型接口
interface GenericIdentityFn<T> {
  (arg: T): T;
}

let myIdentity: GenericIdentityFn<number> = identity;

// 泛型类
class GenericNumber<T> {
  zeroValue: T = {} as T; // 添加初始化表达式
  add: (x: T, y: T) => T = (x, y) => x; // 添加初始化表达式
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x, y) {
  return x + y;
};

// 添加输出语句
console.log("泛型函数输出:");
console.log("output1:", output1);
console.log("output2:", output2);

console.log("泛型接口输出:");
console.log("myIdentity(5):", myIdentity(5));

console.log("泛型类输出:");
console.log("zeroValue:", myGenericNumber.zeroValue);
console.log("add(10, 20):", myGenericNumber.add(10, 20));

// 使用字符串类型的泛型类
let stringGeneric = new GenericNumber<string>();
stringGeneric.zeroValue = "";
stringGeneric.add = function (x, y) {
  return x + y;
};

console.log("字符串类型的泛型类:");
console.log("zeroValue:", stringGeneric.zeroValue);
console.log(
  'add("Hello, ", "World!"):',
  stringGeneric.add("Hello, ", "World!")
);

5. 联合类型与交叉类型

联合类型 (Union Types)

联合类型表示一个值可以是几种类型之一。

TypeScript 复制代码
// 联合类型
function displayValue(value: string | number): void {
  if (typeof value === "string") {
    console.log(`String value: ${value.toUpperCase()}`);
  } else {
    console.log(`Number value: ${value.toFixed(2)}`);
  }
}

console.log("=== 联合类型示例 ===");
console.log("处理字符串值:");
displayValue("hello");
console.log("处理数字值:");
displayValue(42.5);

// 更多示例
console.log("=== 更多联合类型示例 ===");
const stringValue: string | number = "TypeScript";
console.log("当前值为字符串:", stringValue);

const numberValue: string | number = 2023;
console.log("当前值为数字:", numberValue);

// 联合类型函数
function processValue(input: string | number): string {
  return typeof input === "string"
    ? `处理字符串: ${input.length}个字符`
    : `处理数字: ${input * 2}`;
}

console.log("=== 联合类型函数示例 ===");
console.log(processValue("联合类型"));
console.log(processValue(50));

交叉类型 (Intersection Types)

交叉类型将多个类型合并为一个类型。

TypeScript 复制代码
interface BusinessPartner {
  name: string;
  credit: number;
}

interface Identity {
  id: number;
  name: string;
}

type Employee = BusinessPartner & Identity;

let emp: Employee = {
  id: 100,
  name: "John",
  credit: 7000,
};

// 添加输出语句
console.log("=== 交叉类型示例 ===");
console.log("员工信息:");
console.log(`ID: ${emp.id}`);
console.log(`姓名: ${emp.name}`);
console.log(`信用额度: ${emp.credit}`);


// 使用函数处理交叉类型
function displayEmployeeInfo(employee: Employee): void {
  console.log(`
员工 ${employee.name} (ID: ${employee.id}) 的信用额度为 ${employee.credit}`);
}

displayEmployeeInfo(emp);

// 检查属性是否存在
function hasHighCredit(employee: Employee): boolean {
  return employee.credit > 7500;
}

console.log("=== 信用额度检查 ===");
console.log(`${emp.name} 是否有高信用额度: ${hasHighCredit(emp)}`);

6. 类型守卫 (Type Guards)

类型守卫是一些表达式,它们在运行时检查类型,帮助 TypeScript 缩小类型范围。

TypeScript 复制代码
// 使用 typeof 的类型守卫
function padLeft(value: string, padding: string | number): string {
  if (typeof padding === "number") {
    return Array(padding + 1).join(" ") + value;
  }
  if (typeof padding === "string") {
    return padding + value;
  }
  throw new Error(`Expected string or number, got '${padding}'.`);
}

// 使用 in 操作符的类型守卫
interface Car {
  drive(): void;
}

interface Boat {
  sail(): void;
}

function useVehicle(vehicle: Car | Boat) {
  if ("drive" in vehicle) {
    vehicle.drive(); // TypeScript 知道这是 Car
  } else {
    vehicle.sail(); // TypeScript 知道这是 Boat
  }
}

// 添加输出语句
console.log("=== 类型守卫示例 ===");
console.log(`"${padLeft("Hello", 5)}"`);
console.log(`"${padLeft("World", "---")}"`);

const myCar: Car = {
  drive: () => console.log("汽车正在行驶...")
};

const myBoat: Boat = {
  sail: () => console.log("小船正在航行...")
};

console.log("使用汽车:");
useVehicle(myCar);
console.log("使用小船:");
useVehicle(myBoat);

7. 空值检查 (Null Checks)

TypeScript 提供了严格的空值检查选项,帮助避免常见的空引用错误。

TypeScript 复制代码
// 启用严格空值检查后
function getNameFromUser(user?: { name: string }): string {
    // 错误: 'user' 可能为 'undefined'
    // return user.name;
    
    // 正确方式
    if (user) {
        return user.name;
    }
    return "Anonymous";
}

// 非空断言操作符
function getDisplayName(user: { name: string } | null): string {
    // 告诉 TypeScript 我们确定 user 不为 null
    return user!.name;
}

8. 模块系统

TypeScript 支持现代 JavaScript 模块系统,使代码组织更加清晰。

TypeScript 复制代码
// math.ts
const add = (x: number, y: number): number => {
  return x + y;
};

function subtract(x: number, y: number): number {
  return x - y;
}

module.exports = {
  add,
  subtract,
};
// app.ts
const { add, subtract } = require("./math");

console.log(add(5, 3)); // 8
console.log(subtract(10, 4)); // 6

// 默认导出
class Calculator {
  add(x: number, y: number): number {
    return x + y;
  }
}

// 导入默认导出
module.exports = Calculator;

在 "verbatimModuleSyntax" 模式下,不允许在 CommonJS 模块中使用 ESM 语法

9. 高级类型技巧

映射类型 (Mapped Types)

TypeScript 复制代码
type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

type Partial<T> = {
  [P in keyof T]?: T[P];
};

interface User {
  name: string;
  age: number;
}

// 创建一个所有属性都是只读的 User 类型
type ReadonlyUser = Readonly<User>;

// 创建一个所有属性都是可选的 User 类型
type PartialUser = Partial<User>;

// 添加输出语句
console.log("=== 映射类型示例 ===");

const user: User = { name: "Alice", age: 30 };
console.log("原始用户:", user);

const readonlyUser: ReadonlyUser = { name: "Bob", age: 25 };
console.log("只读用户:", readonlyUser);

const partialUser: PartialUser = { name: "Charlie" };
console.log("部分用户:", partialUser);

条件类型 (Conditional Types)

TypeScript 复制代码
type NonNullable<T> = T extends null | undefined ? never : T;

type ExtractType<T, U> = T extends U ? T : never;

// 示例
type StringOrNumber = string | number;
type OnlyString = ExtractType<StringOrNumber, string>; // string

// 添加输出语句
console.log("=== 条件类型示例 ===");

// NonNullable 示例
const nullableString: string | null = "Hello";
const nonNullString: NonNullable<string | null> = "World";

console.log("可为空的字符串:", nullableString);
console.log("非空字符串:", nonNullString);

// ExtractType 示例
const stringOrNumber: StringOrNumber = "TypeScript";
console.log("字符串或数字:", stringOrNumber);
console.log("OnlyString 类型检查:", typeof stringOrNumber === "string" ? "是字符串" : "不是字符串");

10. 类型推断

TypeScript 能够根据上下文自动推断类型,减少显式类型注解的需要。

TypeScript 复制代码
// 类型推断示例
let x = 3; // TypeScript 推断 x 的类型为 number

// 函数返回类型推断
function add(a: number, b: number) {
  return a + b; // TypeScript 推断返回类型为 number
}

// 添加输出语句
console.log("=== 类型推断示例 ===");
console.log("变量 x 的值:", x);
console.log("变量 x 的类型:", typeof x);

const sum = add(5, 7);
console.log("add(5, 7) 的结果:", sum);
console.log("sum 的类型:", typeof sum);

// 上下文推断示例
console.log("=== 上下文推断示例 ===");

// 定义一个简单的函数来演示上下文推断
function handleMouseDown(mouseEvent: { button: number }) {
  console.log("鼠标按钮:", mouseEvent.button);
}

// 模拟鼠标点击事件
console.log("模拟鼠标点击事件:");
handleMouseDown({ button: 0 }); // 左键点击

11. 声明文件与 DefinitelyTyped

TypeScript 使用声明文件(.d.ts)来描述 JavaScript 库的类型。

TypeScript 复制代码
// 声明全局变量
declare var $: (selector: string) => any;

// 声明模块
declare module "my-library" {
    export function doSomething(): void;
}

通过 DefinitelyTyped,大多数流行的 JavaScript 库都有可用的类型定义:

TypeScript 复制代码
npm install --save-dev @types/node @types/react @types/express

TypeScript 提前支持了一些还未在所有环境中普及的 ES 特性,如装饰器(Decorators)、异步迭代器等

总结

TypeScript 的这些特性使它成为大型项目开发的理想选择:

  1. 类型安全:在编译时捕获错误,减少运行时问题
  2. 更好的代码组织:通过接口、类和模块系统
  3. 增强的工具支持:提供精确的代码补全、重构和导航
  4. 现代 JavaScript 特性:支持最新的 ECMAScript 标准
  5. 渐进式采用:可以逐步将 JavaScript 项目迁移到 TypeScript

TypeScript 基础语法

TypeScript 基础语法 | 菜鸟教程

tsc 常用编译参数如下表所示:

序号 编译参数说明
1. --help 显示帮助信息
2. --module 载入扩展模块,需要一个参数
3. --target 设置 ECMA 版本,需要一个参数
4. --declaration 额外生成一个 .d.ts 扩展名的文件。 tsc ts-hw.ts --declaration 以上命令会生成 ts-hw.d.ts、ts-hw.js 两个文件。
5. --removeComments 删除文件的注释
6. --out 编译多个文件并合并到一个输出的文件
7. --sourcemap 生成一个 sourcemap (.map) 文件。 sourcemap 是一个存储源代码与编译代码对应位置映射的信息文件。
8. --module noImplicitAny 在表达式和声明上有隐含的 any 类型时报错
9. --watch 在监视模式下运行编译器。会监视输出文件,在它们改变时重新编译。

tsc --help

tsc --module

tsc--target

tsc --removeComments

TypeScript 注释

注释用于解释代码,提高代码可读性。

单行注释

TypeScript 复制代码
// 这是一个单行注释
let count: number = 0; // 初始化计数器

// 函数说明:计算两个数的和
function add(a: number, b: number): number {
  return a + b; // 返回计算结果
}

多行注释

TypeScript 复制代码
/*
 * 这是一个多行注释
 * 用于详细解释函数的功能
 * 参数说明:
 * @param name 用户姓名
 * @param age 用户年龄
 * @returns 用户信息字符串
 */
function createUserProfile(name: string, age: number): string {
  return `姓名: ${name}, 年龄: ${age}`;
}

/**
 * 计算圆的面积
 * @param radius 圆的半径
 * @returns 圆的面积
 * @throws {Error} 当半径为负数时抛出错误
 */
function calculateCircleArea(radius: number): number {
  if (radius < 0) {
    throw new Error("半径不能为负数");
  }
  return Math.PI * radius * radius;
}

JSDoc 注释

TypeScript 复制代码
/**
 * 用户类
 * @class
 * @classdesc 表示系统中的用户实体
 */
class User {
  /**
   * 用户ID
   * @type {number}
   */
  public id: number;
  
  /**
   * 用户名
   * @type {string}
   */
  public name: string;
  
  /**
   * 创建用户实例
   * @param {number} id - 用户ID
   * @param {string} name - 用户名
   * @param {number} [age] - 用户年龄(可选)
   */
  constructor(id: number, name: string, age?: number) {
    this.id = id;
    this.name = name;
  }
  
  /**
   * 获取用户信息
   * @returns {string} 用户信息字符串
   */
  getInfo(): string {
    return `ID: ${this.id}, 姓名: ${this.name}`;
  }
}

TypeScript 基本结构

TypeScript 基本结构 | 菜鸟教程

TypeScript 基础类型

TypeScript 基础类型 | 菜鸟教程

TypeScript 复制代码
// 定义枚举类型,用于表示用户的角色
enum Role {
  Admin,
  User,
  Guest,
}

// 使用 interface 定义用户的结构
interface User {
  id: number;               // number 类型,用于唯一标识用户
  username: string;         // string 类型,表示用户名
  isActive: boolean;        // boolean 类型,表示用户是否激活
  role: Role;               // enum 类型,用于表示用户角色
  hobbies: string[];        // array 类型,存储用户的兴趣爱好
  contactInfo: [string, number]; // tuple 类型,包含电话号码的元组,格式为:[区域码, 电话号码]
}

// 创建用户对象,符合 User 接口的结构
const user: User = {
  id: 1,
  username: "Alice",
  isActive: true,
  role: Role.User,
  hobbies: ["Reading", "Gaming"],
  contactInfo: ["+1", 123456789],
};

// 定义一个返回字符串的函数来获取用户信息
function getUserInfo(user: User): string {
  return `User ${user.username} is ${user.isActive ? "active" : "inactive"} with role ${Role[user.role]}`;
}

// 使用 void 类型定义一个函数,专门打印用户信息
function printUserInfo(user: User): void {
  console.log(getUserInfo(user));
}

// 定义一个 union 类型的函数参数,接受用户 ID(number)或用户名(string)
function findUser(query: number | string): User | undefined {
  // 使用 typeof 来判断 query 的类型
  if (typeof query === "number") {
    // 如果是数字,则根据 ID 查找用户
    return query === user.id ? user : undefined;
  } else if (typeof query === "string") {
    // 如果是字符串,则根据用户名查找用户
    return query === user.username ? user : undefined;
  }
  return undefined;
}

// 定义一个 never 类型的函数,用于处理程序的异常情况
function throwError(message: string): never {
  throw new Error(message);
}

// 使用 any 类型处理未知类型的数据
let unknownData: any = "This is a string";
unknownData = 42; // 重新赋值为数字,类型为 any

// 使用 unknown 类型处理不确定的数据,更加安全
let someData: unknown = "Possible data";
if (typeof someData === "string") {
  console.log(`Length of data: ${(someData as string).length}`);
}

// 调用各个函数并测试
printUserInfo(user);                    // 打印用户信息
console.log(findUser(1));               // 根据 ID 查找用户
console.log(findUser("Alice"));         // 根据用户名查找用户

// 使用 null 和 undefined 类型的变量
let emptyValue: null = null;
let uninitializedValue: undefined = undefined;

TypeScript 变量声明

**注意:**变量不要使用 name 否则会与 DOM 中的全局 window 对象下的 name 属性出现了重名。

类型断言

TypeScript 复制代码
var str = "1";
var str2: number = <number>(<any>str); //str、str2 是 string 类型
console.log(str2);

类型判断

TypeScript 变量声明

TypeScript 主要包含以下几种运算:

  • 算术运算符
  • 逻辑运算符
  • 关系运算符
  • 按位运算符
  • 赋值运算符
  • 三元/条件运算符
  • 字符串运算符
  • 类型运算符

TypeScript 条件语句

TypeScript 条件语句 | 菜鸟教程

TypeScript 循环

TypeScript 循环 | 菜鸟教程

for...of 、forEach、every 和 some 循环

1. for...of 循环

for...of 是 ES6 引入的一种遍历可迭代对象(包括数组、字符串、Map、Set 等)的语法结构。

TypeScript 复制代码
// 基本语法
const numbers: number[] = [1, 2, 3, 4, 5];

for (const num of numbers) {
  console.log(num);
}

// 遍历字符串
const greeting: string = "Hello";
for (const char of greeting) {
  console.log(char); // H e l l o
}

// 在 for...of 中获取索引
const fruits: string[] = ["apple", "banana", "orange"];
for (const [index, fruit] of fruits.entries()) {
  console.log(`${index}: ${fruit}`);
}

2. forEach 方法

forEach 是数组的一个方法,对数组的每个元素执行一次提供的函数。

TypeScript 复制代码
// 基本用法
const numbers: number[] = [1, 2, 3, 4, 5];
numbers.forEach((num) => {
  console.log(num);
});

// 带索引的用法
const colors: string[] = ["red", "green", "blue"];
colors.forEach((color, index) => {
  console.log(`${index}: ${color}`);
});

// 完整回调函数参数
colors.forEach((color, index, array) => {
  console.log(`${index}: ${color}`, array);
});

// 使用 thisArg 参数
const counter = {
  count: 0,
  increment: function(value: number) {
    this.count += value;
    console.log(`Current count: ${this.count}`);
  }
};

const values = [10, 20, 30];
values.forEach(function(value) {
  this.increment(value);
}, counter);

3. every 方法

every 方法测试数组中的所有元素是否都通过了指定函数的测试。它返回一个布尔值。

TypeScript 复制代码
// 检查所有元素是否满足条件
const numbers = [2, 4, 6, 8, 10];
const allEven = numbers.every((num) => num % 2 === 0);
console.log(allEven); // true

const mixedNumbers = [1, 2, 4, 6];
const allEvenMixed = mixedNumbers.every((num) => num % 2 === 0);
console.log(allEvenMixed); // false

// 实际应用场景
const users = [
  { name: "Alice", age: 25, active: true },
  { name: "Bob", age: 30, active: true },
  { name: "Charlie", age: 35, active: true }
];

// 检查所有用户是否都是活跃的
const allActive = users.every(user => user.active);
console.log(allActive); // true

// 检查所有用户是否都成年
const allAdults = users.every(user => user.age >= 18);
console.log(allAdults); // true

4. some 方法

some 方法测试数组中是否至少有一个元素通过了指定函数的测试。它返回一个布尔值。

TypeScript 复制代码
// 检查是否有元素满足条件
const numbers = [1, 3, 5, 8, 10];
const hasEven = numbers.some((num) => num % 2 === 0);
console.log(hasEven); // true

const allOdd = [1, 3, 5, 7];
const hasEvenOdd = allOdd.some((num) => num % 2 === 0);
console.log(hasEvenOdd); // false

// 实际应用场景
const products = [
  { name: "Laptop", price: 1000, inStock: true },
  { name: "Mouse", price: 25, inStock: false },
  { name: "Keyboard", price: 75, inStock: true }
];

// 检查是否有缺货商品
const hasOutOfStock = products.some(product => !product.inStock);
console.log(hasOutOfStock); // true

// 检查是否有高价商品
const hasExpensive = products.some(product => product.price > 500);
console.log(hasExpensive); // true

方法比较与使用场景

方法 返回值 用途 是否可中断
for...of 遍历元素并执行操作 可以使用 break 中断
forEach 遍历元素并执行操作 不可中断
every 布尔值 检查所有元素是否满足条件 在第一个不满足条件的元素处停止
some 布尔值 检查是否有元素满足条件 在第一个满足条件的元素处停止

性能考虑

  • 对于大型数组, for...of 循环通常比 forEach 更快,因为它是语言级别的结构,减少了函数调用的开销
  • everysome 具有短路行为,在找到匹配项时会立即停止遍历,这比手动遍历整个数组更高效
  • 如果需要在遍历过程中提前退出,使用 for...of 配合 breakreturn 是更好的选择

TypeScript 函数

TypeScript 函数 | 菜鸟教程

在 TypeScript 函数里,如果我们定义了参数,则我们必须传入这些参数,除非将这些参数设置为可选,可选参数使用问号标识 ?。

函数的最后一个命名参数以 ... 为前缀,它将成为一个由剩余参数组成的数组,索引值从0(包括)到.length(不包括)。

TypeScript Number

TypeScript Number | 菜鸟教程

TypeScript String(字符串)

TypeScript String(字符串) | 菜鸟教程

通常情况下,TypeScript 推荐直接使用 string 字面量类型,以简化代码,提高性能,避免不必要的类型转换和复杂性。

TypeScript Array(数组)

TypeScript Array(数组) | 菜鸟教程

TypeScript Map 对象

TypeScript Map 对象 | 菜鸟教程

TypeScript 元组

TypeScript 元组 | 菜鸟教程

TypeScript 联合类型

TypeScript 联合类型 | 菜鸟教程

TypeScript 接口

TypeScript 接口 | 菜鸟教程

TypeScript 命名空间

TypeScript 命名空间 | 菜鸟教程

TypeScript 中命名空间使用 namespace 来定义

TypeScript 模块

TypeScript 模块 | 菜鸟教程

JavaScript模块加载器是服务于 Node.js 的 CommonJS 和服务于 Web 应用的 Require.js

TypeScript 声明文件

TypeScript 声明文件 | 菜鸟教程

declare 关键字来定义它的类型,帮助 TypeScript 判断我们传入的参数类型对不对

declare 定义的类型只会用于编译时的检查,编译结果中会被删除。

声明文件

声明文件以 .d.ts 为后缀

相关推荐
沛沛老爹2 小时前
Web开发者快速上手AI Agent:基于Advanced-RAG的提示词应用
前端·人工智能·langchain·llm·rag·web转型·advanced-rag
5967851542 小时前
HTML元素
前端·html
崇山峻岭之间2 小时前
Matlab学习记录13
开发语言·学习·matlab
鹏多多2 小时前
React使用useLayoutEffect解决操作DOM页面闪烁问题
前端·javascript·react.js
zhengxianyi5152 小时前
vue devSever中如何配置多个proxy 代理及pathRewrite路径重写
前端·javascript·vue.js·proxy·前后端分离·devserver·pathrewrite
登山人在路上2 小时前
Vue3 Watch 完全指南:深度监听与性能优化
前端·javascript·vue.js
CodeSheep2 小时前
公司开始严查午休…
前端·后端·程序员
Rhys..2 小时前
js-运算符 ||
前端·javascript·vue.js
哟哟耶耶2 小时前
component-Echarts圆环数据展示-延长线,label,鼠标移动提示,圆环数据中心总数,信息面板
前端·javascript·echarts