TypeScript的常用方法

接口(Interfaces)类型

接口可以用来定义对象应该具有的属性和方法,而无需实现它们。下面是定义接口的基本语法:

interface InterfaceName {
  // 属性定义
  propertyName: Type;
  // 可选属性
  propertyName?: Type;
  // 只读属性
  readonly propertyName: Type;
  // 方法定义
  methodName(param1: Type, param2: Type): ReturnType;
}

下面是一些定义接口的例子:

简单接口

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

function greet(person: Person) {
  return "Hello, " + person.name;
}

let user: Person = {
  name: "Alice",
  age: 25
};

console.log(greet(user));

可选属性

在接口中,属性名后加上?表示该属性是可选的:

interface Person {
  name: string;
  age?: number;
}

let user: Person = {
  name: "Alice"
  // age 属性是可选的,可以不提供
};

只读属性

在接口中,使用readonly关键字定义只读属性,表示该属性在创建后不能被修改:

interface Person {
  readonly id: number;
  name: string;
}

let user: Person = {
  id: 1,
  name: "Alice"
};

// user.id = 2; // 错误,id 是只读属性

方法定义

接口也可以包含方法签名,但不提供具体实现:

interface Person {
  name: string;
  sayHello(): string;
}

let user: Person = {
  name: "Alice",
  sayHello: function() {
    return `Hello, my name is ${this.name}`;
  }
};

console.log(user.sayHello());

扩展接口

接口可以继承其他接口,使用extends关键字:

interface Named {
  name: string;
}

interface Greetable extends Named {
  greet(phrase: string): void;
}

class Person implements Greetable {
  name: string;

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

  greet(phrase: string) {
    console.log(`${phrase}${this.name}`);
  }
}

let user = new Person("Alice");
user.greet("Hello, I'm");

通过定义接口,TypeScript可以帮助你在编码时进行类型检查,确保对象符合特定的结构。这有助于在开发过程中捕获潜在的错误,并且使得代码更加清晰和易于维护。

泛型(Generics)

这种方法可以适用于多种类型而不是单一类型。泛型可以应用于函数、接口和类。以下是泛型的基本使用方法:

泛型函数

泛型函数可以处理多种类型的数据。下面是一个简单的泛型函数示例:

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

let output1 = identity<string>("Hello, World!");
let output2 = identity<number>(100);

在这个例子中,T是一个类型变量,它被用来捕获用户传入的类型(比如stringnumber),然后返回相同类型的值。

泛型接口

泛型也可以用于接口,以创建可复用的组件。下面是一个泛型接口的示例:

interface GenericIdentityFn<T> {
  (arg: T): T;
}

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

let myIdentity: GenericIdentityFn<number> = identity;

这里,GenericIdentityFn是一个泛型接口,它描述了一个函数类型,这个函数接受一个类型为T的参数并返回一个类型为T的值。

泛型类

泛型类看起来类似于泛型接口。泛型类在实例部分可以使用类型变量。

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; };

let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = "";
stringNumeric.add = function(x, y) { return x + y; };

console.log(myGenericNumber.add(myGenericNumber.zeroValue, 100));
console.log(stringNumeric.add(stringNumeric.zeroValue, "Test"));

在这个例子中,GenericNumber类的类型变量T在实例属性zeroValueadd方法中被使用。

泛型约束

有时候,你可能希望泛型函数能够处理多种类型,但又限制这些类型必须拥有某些共同的属性或方法。这时可以使用泛型约束:

interface Lengthwise {
  length: number;
}

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

loggingIdentity({ length: 10, value: 3 });
// loggingIdentity(3); // 错误,数字没有 length 属性

在这个例子中,loggingIdentity函数被约束为只能接收具有length属性的参数。

多个类型参数

泛型函数可以有多个类型参数:

function swap<T, U>(tuple: [T, U]): [U, T] {
  return [tuple[1], tuple[0]];
}

let result = swap<string, number>(["hello", 42]);
console.log(result); // [42, "hello"]

这里,swap函数接受一个元组作为参数,并返回一个新的元组,其元素顺序被交换。

泛型是TypeScript中一个非常强大的特性,它提供了类型安全的同时保持了代码的灵活性。通过使用泛型,可以创建出既可复用又可适用于多种类型数据的组件。

类型断言(Type Assertions)

类型断言(Type Assertions)是一种告诉编译器你比它更了解某个值的类型的方式。类型断言类似于其他语言中的类型转换,但它不进行数据检查或重构,它只是在编译阶段告诉编译器“相信我,这个值就是这个类型”。

类型断言有两种形式:

1. “尖括号”语法

let someValue: any = "this is a string";

let strLength: number = (<string>someValue).length;

2. as语法

let someValue: any = "this is a string";

let strLength: number = (someValue as string).length;

这两种形式在功能上是等价的,但是as语法在TypeScript中使用 JSX 时更受欢迎,因为尖括号在 JSX 中有特殊含义。

使用类型断言的注意事项:

  • 类型断言不会在运行时对值进行检查,它不会改变值的类型,它只是告诉编译器如何处理该值。
  • 类型断言不是类型转换,它不会触发任何特殊逻辑或类型检查。
  • 在没有足够信息的情况下,不要过度使用类型断言,这可能会导致运行时错误。
  • 当使用类型断言时,最好确保你的断言是正确的,否则可能会引入难以追踪的bug。

以下是一些使用类型断言的场景:

将联合类型断言为其中一个类型
interface Cat {
  name: string;
  purr(): void;
}

interface Dog {
  name: string;
  bark(): void;
}

function isCat(animal: Cat | Dog): animal is Cat {
  return (animal as Cat).purr !== undefined;
}

function makeAnimalSound(animal: Cat | Dog) {
  if (isCat(animal)) {
    animal.purr();
  } else {
    animal.bark();
  }
}

在这个例子中,isCat函数使用了类型断言来检查一个动物是否是猫。

any类型断言为更具体的类型

当你从一个类型为any的变量中读取数据时,你可能想断言一个更具体的类型,以便在之后的代码中使用。

let value: any = "Hello, TypeScript";

// 断言 value 是一个字符串
let message = value as string;

请记住,尽管类型断言很有用,但它应该谨慎使用,以避免隐藏潜在的运行时错误。

TS中处理异步操作

1. 使用回调函数

传统的JavaScript异步编程是通过回调函数来实现的。在TypeScript中,你可以通过定义函数参数为回调函数来处理异步操作。

function fetchData(callback: (data: any) => void) {
  // 模拟异步操作,比如HTTP请求
  setTimeout(() => {
    callback({ message: 'Data fetched successfully' });
  }, 2000);
}

fetchData((data) => {
  console.log(data.message); // 输出: Data fetched successfully
});

2. 使用Promise

Promise是ES6引入的,用于更优雅地处理异步操作。在TypeScript中,你可以使用Promise来改进异步代码的可读性和可维护性。

function fetchData(): Promise<any> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({ message: 'Data fetched successfully' });
    }, 2000);
  });
}

fetchData()
  .then(data => {
    console.log(data.message); // 输出: Data fetched successfully
  })
  .catch(error => {
    console.error(error);
  });

3. 使用async和await

asyncawait是ES2017引入的语法,它们提供了一种更简洁的方式来处理Promise。在TypeScript中,你可以将函数声明为async,并在函数内部使用await来等待异步操作的结果。

async function fetchData(): Promise<any> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({ message: 'Data fetched successfully' });
    }, 2000);
  });
}

async function run() {
  try {
    const data = await fetchData();
    console.log(data.message); // 输出: Data fetched successfully
  } catch (error) {
    console.error(error);
  }
}

run();

 在这个例子中,fetchData函数返回一个Promise,而run函数使用async声明,并通过await等待fetchData的结果。使用try...catch可以捕获异步操作中可能出现的错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值