TypeScript划重点【纯干货版】

TypeScript 的主要特点包括:

  • 静态类型:TypeScript 允许开发者为变量、函数参数和返回值指定类型。这有助于在编译时捕捉错误,而不是在运行时。
  • 类和接口:TypeScript 支持基于类的面向对象编程,允许定义类、接口和继承。这有助于组织复杂的代码结构。
  • 模块系统:TypeScript 有一个模块系统,允许将代码分割成可重用的模块。这有助于管理依赖关系并提高代码的可维护性。
  • 装饰器:TypeScript 支持装饰器,这是一种在声明类、方法、属性或参数时添加注解的高级特性。
  • 泛型:TypeScript 的泛型允许创建可重用的组件,这些组件可以在不同的类型之间通用。
  • 编译目标:TypeScript 可以编译到不同版本的 JavaScript,包括 ES3、ES5、ES6(ES2015)、ESNext 等。
  • 工具支持:TypeScript 有丰富的工具链支持,包括 Visual Studio Code、WebStorm、Sublime Text 等流行的编辑器和 IDE。
  • 社区和生态系统:TypeScript 有一个活跃的社区和不断增长的生态系统,提供了大量的库和框架支持。

长话短说,只搞重点和干货,ts就是js的超集,就是在js的基础上做了封装和拓展。

基础类型

Number、String、Boolean、Object、Null、Undefined没意思不多说
any也没什么说的,ts的救命类型,但是不建议大量使用
void表示没有任何类型。 一般用于给函数没有返回值时
never类型表示的是那些永不存在的值的类型

数组Array【重点】

// 元素类型[ ]
let list: number[] = [1, 2, 3];

// Array<元素类型>
let list: Array<number> = [1, 2, 3];

元组Tuple

其实就是数组的一种,简单说就是可以定义多种类型的数组,并且已知元素数量和类型,各元素的类型不必相同。

let t1: [string, number]
t1 = ['hello', 10] // OK
t1 = [10, 'hello'] // Error

枚举enum

枚举可以定义一些带名字的常量。

enum Color {
  Red,
  Green,
  Blue
}
 
// 枚举数值默认从0开始依次递增
// 根据特定的名称得到对应的枚举数值
let myColor: Color = Color.Green  // 0
console.log(myColor, Color.Red, Color.Blue)

枚举使用场景

状态管理

使用枚举来表示不同的状态,例如 enum Status { Pending, Active, Inactive }。

enum Status {
  Pending,
  Active,
  Inactive
}

function updateStatus(entity: { status: Status }) {
  switch (entity.status) {
    case Status.Pending:
      console.log('Processing the entity...');
      break;
    case Status.Active:
      console.log('The entity is active.');
      break;
    case Status.Inactive:
      console.log('The entity is inactive.');
      break;
    default:
      console.log('Unknown status.');
  }
}

const entity = { status: Status.Pending };
updateStatus(entity);
方向

表示方向或方位,例如 enum Direction { Up, Down, Left, Right }。

enum Direction {
  Up,
  Down,
  Left,
  Right
}

class Player {
  direction: Direction;

  move(d: Direction) {
    this.direction = d;
    console.log(`Player moved to the ${Direction[this.direction]}`);
  }
}

const player = new Player();
player.move(Direction.Right); // 输出: Player moved to the Right
错误码

定义错误代码和消息,例如 enum ErrorCode { NotFound = 404, BadRequest = 400 }。

enum ErrorCode {
  NotFound = 404,
  BadRequest = 400,
  InternalServerError = 500
}

function handleError(code: ErrorCode) {
  switch (code) {
    case ErrorCode.NotFound:
      console.log('The resource was not found.');
      break;
    case ErrorCode.BadRequest:
      console.log('There was an error with the request.');
      break;
    case ErrorCode.InternalServerError:
      console.log('The server encountered an internal error.');
      break;
  }
}

handleError(ErrorCode.InternalServerError); // 输出: The server encountered an internal error.
配置选项

在配置文件中使用枚举来定义配置选项的合法值。

enum ConfigurationOption {
  DarkMode = 'dark',
  LightMode = 'light',
  AutoMode = 'auto'
}

interface AppSettings {
  theme: ConfigurationOption;
}

const settings: AppSettings = {
  theme: ConfigurationOption.AutoMode
};

function applySettings(settings: AppSettings) {
  if (settings.theme === ConfigurationOption.DarkMode) {
    console.log('Applying dark mode settings.');
  } else if (settings.theme === ConfigurationOption.LightMode) {
    console.log('Applying light mode settings.');
  } else {
    console.log('Applying automatic mode settings based on user preferences.');
  }
}

applySettings(settings); // 输出: Applying automatic mode settings based on user preferences.

联合类型(Union Types)

表示取值可以为多种类型中的一种,用 | 连接类型。

let value: string | number | boolean;

交叉类型(Intersection Types)【重点】

表示取值可以是多种类型的合并,用& 连接类型。一般用来合并接口等

type IntersectionType = Type1 & Type2 & ... & TypeN;

经常用来组合接口、合并类、与类型别名一起使用

// 组合接口
interface IUser {
  name: string;
  id: number;
}

interface IAdmin {
  manage: boolean;
  delete: boolean;
}

let userAdmin: IUser & IAdmin;
userAdmin = {
  name: 'Alice',
  id: 1,
  manage: true,
  delete: true
};


// 合并类
class Person {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}

class Employee {
  jobTitle: string;
  constructor(jobTitle: string) {
    this.jobTitle = jobTitle;
  }
}

let person: Person & Employee;
person = {
  name: 'Bob',
  jobTitle: 'Developer'
};


// 使用类型别名来定义交叉类型
type StringOrNumber = string | number;
type StringAndNumber = StringOrNumber & { toFixed: () => string } & { toString: () => string };

let value: StringAndNumber;
value = '100'; // 使用 string 的方法
value = 100; // 使用 number 的方法

类型别名(Type Aliases)【重点】

简单来说就是为现有的类型定义一个新的名字,可以配合联合类型、交叉类型、接口等来组合。

// 最常用的,比如说渲染一个list,数据都是数组对象的
interface IPerson {
	name: string;
	age: number;
	icon: string;
	.....可能还有其他的等等
}

type PersonList = IPerson[]
// 或者
type PersonList = Array<IPerson>

未知类型unknown

用来处理那些你不确定具体类型的值。

类型推断

ts默认是支持 类型推断的,就是你不用特意指定每一个类型
类型推断:定义变量时赋值了, 推断为对应的类型。 定义变量时没有赋值, 推断为any类型

类型断言【重点】

有时间你定义的变量或者函数啥的,需要使用一些特定的属性或者方法,然后ts它也不确定你定义的到底有没有属性或者方法,这时候就需要我们去主动告诉ts它有。就会用到类型断言了。

“尖括号”语法
let someValue: any = "this is a string";

let strLength: number = (<string>someValue).length;
as语法
let someValue: any = "this is a string";

let strLength: number = (someValue as string).length;
!非空断言

注意,滥用 ! 运算符可能会导致运行时错误,因此应该谨慎使用。

let optionalValue: string | null = getOptionalString();
let length: number = optionalValue!.length; // 非空断言,使用 ! 断言 optionalValue 不是 null

再比如这样

const length = someObject?.property?.length;
console.log(someObject!.property!.length); // 使用 ! 断言 property 不是 undefined

接口interface 【重点】

接口对于后端的同学更熟悉,前端同学可以这样理解,接口就是定义对象用的,代码里要写对象就要想到接口是一种方式。

interface IListData {
	name: string; // 定义属性
	speak(n: number | string): void; // 定义方法 
	age?: 18;  // ?可选属性
	readonly sex: string;   // readonly 只读属性
	[propName: string]: any;    // 索引签名
}


// 接口继承 使用 extends 
interface IListItemData extends IListData {
	// 继承了IListItemData 所有属性并且可以添加其他属性
	itemName: string;
}

// 还可以继承多个接口,使用逗号
interface IViewData {
	width: string | number;
	height: string | number;
}

interface IListItemData extends IListData, IViewData {}

类class【重点】

TypeScript中的class是面向对象编程的基础构建块之一,它提供了多种特性来支持面向对象的设计模式和实践。

constructor构造函数

构造函数是类的特殊方法,用于创建和初始化类的新实例。

class Person {
  constructor(public name: string, public age: number) {}
}

const person = new Person("Alice", 30);
console.log(person.name); // 输出: Alice

修饰符

public、private和protected是TypeScript中用于控制成员访问级别的关键字。

class Car {
  readonly name: string; // 只读,不可修改
  public make: string; // 公开的属性,可以在任何地方访问
  private model: string; // 私有的属性,只能在类的内部访问
  protected year: number; // 受保护的属性,可以在类和子类中访问
}

const car = new Car();
car.make = "Toyota"; // 有效
// car.model = "Corolla"; // 无效,因为 model 是私有的

extends 继承

子类可以继承父类的属性和方法

class Vehicle {
  startEngine() {
    console.log("Vehicle engine started.");
  }
}

class Car extends Vehicle {
  drive() {
    console.log("Car is driving.");
  }
}

const car = new Car();
car.startEngine(); // 继承自 Vehicle
car.drive(); // Car特有的方法

implements实现接口

类可以实现一个或多个接口,确保类定义了接口中所有声明的成员。

interface Drivable {
  startEngine(): void;
  drive(): void;
}

class SportsCar implements Drivable {
  startEngine() {
    console.log("Sports car engine started.");
  }
  drive() {
    console.log("Sports car is driving.");
  }
}

抽象类

抽象类不能被实例化,它通常用作基类,定义了一组必须由子类实现的方法。

abstract class Animal {
  abstract makeSound(): void;
  move(): void {
    console.log("Animal can move.");
  }
}

class Dog extends Animal {
  makeSound() {
    console.log("Woof woof!");
  }
}

const dog = new Dog();
dog.makeSound(); // Dog必须实现makeSound方法
dog.move(); // 有效

属性装饰器

属性装饰器可以用来在类定义后,设置属性的元数据。

class Person {
  @loggable
  public name: string;

  constructor(name: string) {
    this.name = name;
  }
}

function loggable(target: any, propertyKey: string) {
  let value = target[propertyKey];
  target[propertyKey] = function() {
    console.log(`Getting the value of ${propertyKey}`);
    return value;
  };
}

存取器

存取器允许您定义如何访问和修改类的属性。

class Employee {
  private _name: string;

  get name(): string {
    return this._name;
  }

  set name(value: string) {
    this._name = value.toUpperCase();
  }
}

const employee = new Employee();
employee.name = "Alice"; // 实际存储的是 ALICE
console.log(employee.name); // 输出: ALICE

static / # 静态成员

类可以包含静态属性和方法,它们属于类本身,而不是类的实例。

在TypeScript 3.8及以后的版本中,引入了一种新的语法来声明类的私有字段,这种语法使用井号(#)作为私有字段的前缀。这种新的私有字段语法提供了一种更简洁和明确的方式来定义类的私有成员,包括属性、方法和访问器。

class Employee {
  static _name: string;
  #name: string;

  get name(): string {
    return this._name;
  }
  
  get #name(): string {
    return this.#name;
  }
  
  set name(value: string) {
    this._name = value.toUpperCase();
  }
  
  set #name(value: string) {
    this.#name = value.toUpperCase();
  }
}

const employee = new Employee();
employee.name = "Alice"; // 实际存储的是 ALICE
console.log(employee.name); // 输出: ALICE

泛型【重点】

泛型是一种在编写代码时创建可重用组件的技术。泛型允许你编写一段在多种类型之间通用的代码,而不是为每一种类型编写重复的代码。这样,你可以创建类似数组、函数、类等结构时,让它们能够适应任何类型。

泛型使用 语法来表示类型参数,其中 Type 是一个占位符,代表任何类型。

function identity<T>(arg: T): T {
  return arg;
}

let output1 = identity<string>("myString");  // 类型为 string
let output2 = identity<number>(100);        // 类型为 number

泛型函数

泛型函数可以处理不同类型的参数和返回值,而不需要为每种类型编写重复的代码。

function combineValues<T, U>(a: T, b: U): [T, U] {
  return [a, b];
}

let combined = combineValues("hello", 42);  // 结果类型为 [string, number]

泛型接口

泛型接口可以定义通用的数据结构,使其能够适应不同的数据类型。

interface Container<T> {
  value: T;
}

let myContainer: Container<string> = { value: "Hello World" };
let myNumberContainer: Container<number> = { value: 42 };

泛型类型别名

// 泛型类型别名
type Pair<T> = {
  key: T;
  value: T;
};

// 使用类型别名
const numberPair: Pair<number> = { key: 1, value: 2 };
const stringPair: Pair<string> = { key: "a", value: "b" };

泛型类

泛型类可以定义通用的对象结构,允许其实例化时指定具体的类型。

class Stack<T> {
  private items: T[] = [];
  push(item: T) {
    this.items.push(item);
  }
  pop(): T | undefined {
    return this.items.pop();
  }
}

let numberStack = new Stack<number>();
numberStack.push(1);
numberStack.push(2);
console.log(numberStack.pop()); // 输出: 2

泛型约束

有时候你可能需要限制泛型只能被某些类型所使用。这可以通过泛型约束来实现。

interface Lengthwise {
  length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length);  // 现在我们知道它有一个 .length 属性,因为它符合 Lengthwise 接口
  return arg;
}

let result = loggingIdentity(["hello", "world"]);  // 使用数组,数组有 length 属性
// loggingIdentity({ a: "hello" });  // 错误: 类型 "{ a: string; }" 缺少属性 "length"

装饰器(Decorators)【重点】

装饰器是一种特殊的声明,可以附加到类声明、方法、访问符、属性或参数上,用来标注或修改它们。装饰器提供了一种强大的元编程机制,允许在运行时修改或观察类及其成员的行为。

类装饰器

类装饰器可以用来记录类的创建日志、修改类的构造函数以添加额外的功能,或者创建单例模式的类。

function logClassUsage(target: Function) {
  const original = target.prototype.constructor;
  target.prototype.constructor = function (...args: any[]) {
    console.log(`Creating an instance of ${target.name}`);
    return original.apply(this, args);
  };
}

@logClassUsage
class MyComponent {
  constructor() {
    // 构造函数内容
  }
}

let component = new MyComponent(); // 输出: Creating an instance of MyComponent

方法装饰器

方法装饰器可以用于性能监控、日志记录、权限检查、事务处理等,任何需要在方法执行前后添加额外逻辑的场景。

function timingMethodDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  descriptor.value = function (...args: any[]) {
    const start = performance.now();
    const result = originalMethod.apply(this, args);
    const end = performance.now();
    console.log(`${propertyKey} executed in ${end - start}ms`);
    return result;
  };
  return descriptor;
}

class PerformanceTracker {
  @timingMethodDecorator
  trackPerformance() {
    // 一些性能关键的操作
  }
}

const tracker = new PerformanceTracker();
tracker.trackPerformance();

访问器装饰器

访问器装饰器可以用于懒加载、缓存结果、计算属性值等,特别是当你需要对属性的获取和设置进行复杂处理时。

function cacheGetter(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  let cache;
  return {
    get() {
      if (cache === undefined) {
        cache = originalGetter.call(this);
      }
      return cache;
    },
    set(value: any) {
      cache = value;
      return originalSetter.call(this, value);
    },
  };
}

const originalGetter = () => Math.random();
const originalSetter = (value: number) => { /* 存入数据库 */ };

class RandomNumber {
  @cacheGetter
  get random() {
    return originalGetter();
  }

  @cacheGetter
  set random(value: number) {
    return originalSetter(value);
  }
}

const num = new RandomNumber();
console.log(num.random); // 获取随机数
// 再次获取相同的随机数,将不会重新计算,而是从缓存中获取

属性装饰器

属性装饰器可以用于冻结属性(使其不可变)、添加属性验证、记录属性变更、实现观察者模式等。

function freezeProperty(target: any, propertyKey: string) {
  const value = target[propertyKey];
  Object.defineProperty(target, propertyKey, {
    value: value,
    writable: false,
    enumerable: true,
    configurable: false,
  });
}

class Person {
  @freezeProperty
  name: string = 'John Doe';
}

const person = new Person();
person.name = 'Alice'; // 无效,属性被冻结

参数装饰器

参数装饰器可以用于参数验证、依赖注入、记录参数信息等,任何需要在方法调用时检查参数的场景。

function validateParameter(target: any, propertyKey: string, parameterIndex: number) {
  const parameters = Reflect.getMetadata('design:paramtypes', target, propertyKey) || [];
  const paramType = parameters[parameterIndex];

  return function(...args: any[]) {
    if (!(args[parameterIndex] instanceof paramType)) {
      throw new Error(`Parameter ${parameterIndex} is not of type ${paramType.name}`);
    }
    return target[propertyKey](...args);
  };
}

class Validator {
  @validateParameter(String)
  addString(str: string) {
    // 处理字符串
  }
}

const validator = new Validator();
validator.addString('Hello'); // 有效
validator.addString(123); // 无效,参数不是String类型

三斜线指令 ///

在 TypeScript 中,/// 是三斜杠注释的开始,它用于生成文档注释,也称为 JSDoc。这些注释可以为函数、类、接口、属性等提供描述性信息,包括类型定义、描述、参数说明和返回值说明。TypeScript 编译器和工具链使用这些注释来生成类型定义文件(.d.ts)和文档。

JSDoc 标签
JSDoc 支持多种标签,用于提供额外的信息。以下是一些常用的 JSDoc 标签:

  • @param:描述函数参数的类型和简要说明。
  • @returns 或 @return:描述函数的返回值类型和说明。
  • @type:指定变量的类型(通常与 @param 或 @returns 一起使用)。
  • @description 或 /**:提供一般描述,通常用于类、模块或函数的开始。
  • @example:提供一个代码示例。
  • @throws 或 @exception:描述可能抛出的错误及其类型。
/// <reference path="someModule.ts" />

/**
 * Adds two numbers.
 * @param {number} a The first number.
 * @param {number} b The second number.
 * @returns {number} The sum of a and b.
 */
function add(a: number, b: number): number {
  return a + b;
}

/**
 * A class that represents a user.
 * @example
 * const user = new User("Alice", "alice@example.com");
 */
class User {
  /**
   * Constructs a new User instance.
   * @param {string} name The user's name.
   * @param {string} email The user's email.
   */
  constructor(public name: string, public email: string) {}

  /**
   * Gets the user's full name.
   * @returns {string} The full name.
   */
  get fullName(): string {
    return this.name;
  }
}
  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值