入门TypeScript看这一篇就够了

前言

TypeScript是一种由Microsoft开发的编程语言,它是JavaScript的超集,意味着它可以编写与JavaScript完全兼容的代码,并且可以扩展其功能。TypeScript的主要目标是提供类型安全性和更好的可维护性,使得开发大型复杂应用程序更加容易。在本文中,我们将介绍入门TypeScript的基础知识。

安装TypeScript

首先,我们需要安装TypeScript。可以使用npm包管理器全局安装TypeScript:

css 复制代码
bashCopy code
npm install -g typescript

安装完成后,可以通过输入以下命令来检查是否安装成功:

css 复制代码
bashCopy code
tsc --version

编写第一个TypeScript程序

让我们从一个简单的"Hello, World!"程序开始。创建一个名为hello.ts的文件,然后在其中编写以下代码:

javascript 复制代码
typescriptCopy code
function sayHello(name: string) {
  console.log(`Hello, ${name}!`);
}

sayHello("TypeScript");

保存并退出文件。然后使用以下命令将其编译为JavaScript:

css 复制代码
bashCopy code
tsc hello.ts

执行上述命令后,将生成一个名为hello.js的文件。要运行这个程序,可以在命令行中输入以下命令:

css 复制代码
bashCopy code
node hello.js

输出应该是:

css 复制代码
bashCopy code
Hello, TypeScript!

在上面的代码中,我们定义了一个名为sayHello的函数,它有一个参数name,类型为字符串。在函数体内,我们使用console.log打印出"Hello, "和name的值,并使用模板字面量将它们组合在一起。最后,我们调用这个函数并将参数设置为"TypeScript"。

类型注释

TypeScript的主要特点之一是提供类型注释,可以在编译时检查类型错误。在上面的示例中,我们定义了一个name参数的类型为字符串,这是通过在函数声明中使用冒号和类型名称来实现的。

TypeScript支持多种类型注释,包括:

  • 基本类型:如数字、字符串、布尔值、null、undefined、void等。
  • 对象类型:如数组、元组、枚举、类等。
  • 函数类型:如函数声明、函数表达式、箭头函数等。

例如,以下是一个函数声明的完整类型注释:

typescript 复制代码
typescriptCopy code
function add(x: number, y: number): number {
  return x + y;
}

在这个示例中,我们定义了两个参数xy,它们的类型都是数字,并且函数返回值的类型也是数字。

元组

元组是一种特殊的数组类型,它可以存储多个类型不同的值。在 TypeScript 中,我们可以使用元组来表示一组有序的值。

下面是一个简单的示例:

arduino 复制代码
typescriptCopy code
let tuple: [string, number, boolean] = ["hello", 42, true];

console.log(tuple[0]); // "hello"
console.log(tuple[1]); // 42
console.log(tuple[2]); // true

在这个示例中,我们定义了一个名为tuple的元组,它具有三个元素,分别是stringnumberboolean类型的值。我们使用索引访问元组中的元素。

枚举

TypeScript支持枚举,它是一组具有名称的常量。下面是一个简单的示例:

ini 复制代码
typescriptCopy code
enum Color {
  Red,
  Green,
  Blue
}

let color: Color = Color.Red;
console.log(color); // 0

let colorName: string = Color[1];
console.log(colorName); // "Green"

在这个示例中,我们定义了一个名为Color的枚举,它有三个值:RedGreenBlue,它们分别对应0、1和2。我们可以使用枚举的值来声明变量,或使用枚举的名称和值之间的映射来获取名称。

泛型

TypeScript支持泛型,它允许我们编写可重用的代码,可以适用于多种类型。下面是一个简单的示例:

sql 复制代码
typescriptCopy code
function identity<T>(arg: T): T {
  return arg;
}

let result = identity<string>("Hello");
console.log(result); // "Hello"

在这个示例中,我们定义了一个名为identity的函数,它接受一个类型为T的参数,并返回同样的类型。我们使用了类型参数来指定函数应该适用于哪种类型。

接口

接口类型是一种抽象的数据类型,用于描述对象的形状和结构,可以被用作对象的类型注解,以确保对象的属性和方法符合指定的形状。

下面是一个简单的接口类型的示例:

css 复制代码
typescriptCopy code
interface Person {
  name: string;
  age: number;
}

上述代码定义了一个名为 Person 的接口类型,它有两个属性 nameage,分别表示人的姓名和年龄。在 TypeScript 中,我们可以使用这个接口类型来定义一个符合该接口类型要求的对象:

css 复制代码
typescriptCopy code
const person: Person = { name: "Tom", age: 18 };

上述代码定义了一个 person 对象,它符合 Person 接口类型的要求,因为它有 nameage 两个属性,分别为字符串和数字类型。

使用接口类型可以提高代码的可读性和可维护性,因为它能够明确指定对象的属性和方法的类型和结构。

类型别名

类型别名是一种给类型起别名的方式,用于提高代码的可读性和可维护性。在 TypeScript 中,我们可以使用type关键字来定义类型别名。

下面是一个简单的示例:

ini 复制代码
typescriptCopy code
type Point = {
  x: number;
  y: number;
};

function distance(p1: Point, p2: Point) {
  const dx = p1.x - p2.x;
  const dy = p1.y - p2.y;
  return Math.sqrt(dx * dx + dy * dy);
}

const p1: Point = { x: 0, y: 0 };
const p2: Point = { x: 3, y: 4 };

console.log(distance(p1, p2)); // 5

在这个示例中,我们定义了一个名为Point的类型别名,它表示一个具有xy属性的点。我们定义了一个distance函数,它接受两个Point类型的参数,并返回它们之间的距离。我们创建了两个Point对象,并计算它们之间的距离。

命名空间

TypeScript支持命名空间,它允许我们将相关的代码组织在一起,并避免名称冲突。下面是一个简单的示例:

arduino 复制代码
typescriptCopy code
namespace Shapes {
  export class Rectangle {
    width: number;
    height: number;
    constructor(width: number, height: number) {
      this.width = width;
      this.height = height;
    }
    getArea() {
      return this.width * this.height;
    }
  }
}

let rectangle = new Shapes.Rectangle(10, 20);
console.log(rectangle.getArea()); // 200

在这个示例中,我们定义了一个名为Shapes的命名空间,它包含一个名为Rectangle的类。我们使用export关键字将Rectangle类暴露出去,以便其他地方可以访问它。注意,在使用命名空间时,我们需要使用namespace关键字来定义命名空间,并使用.运算符来访问其成员。

联合类型

联合类型表示一个值可以是多种类型之一。它使用|符号将多个类型组合在一起。下面是一个简单的示例:

scss 复制代码
typescriptCopy code
function display(value: string | number) {
  console.log(value);
}

display("Hello"); // "Hello"
display(42); // 42

在这个示例中,我们定义了一个名为display的函数,它接受一个参数,类型可以是stringnumber。我们可以传递一个stringnumber类型的值来调用该函数。

交叉类型

交叉类型表示一个值具有多个类型的属性。它使用&符号将多个类型组合在一起。下面是一个简单的示例:

css 复制代码
typescriptCopy code
interface A {
  a: number;
}

interface B {
  b: string;
}

type AB = A & B;

let ab: AB = {
  a: 42,
  b: "Hello"
};

console.log(ab); // { a: 42, b: "Hello" }

在这个示例中,我们定义了两个接口AB,它们分别定义了ab属性。我们使用交叉类型A & B创建了一个新类型AB,它具有ab属性。我们创建了一个对象ab,它具有ab属性,并将其打印到控制台。

索引类型

索引类型允许我们使用字符串或数字类型的索引来访问对象的属性。它使用[]符号表示。下面是一个简单的示例:

css 复制代码
typescriptCopy code
interface Person {
  name: string;
  age: number;
  [key: string]: any;
}

let person: Person = {
  name: "Alice",
  age: 30,
  address: "123 Main St."
};

console.log(person.address); // "123 Main St."

在这个示例中,我们定义了一个名为Person的接口,它具有nameage属性,并使用字符串类型的索引来允许其他任意属性。我们创建了一个名为person的对象,并为其添加了一个address属性。我们可以使用person.address来访问该属性的值。

类型断言

类型断言是 TypeScript 中一种强制类型转换的机制,可以使我们的代码更加灵活、精确和安全。在 TypeScript 中,我们可以使用as关键字来进行类型断言。

下面是一个简单的示例:

ini 复制代码
typescriptCopy code
const value: unknown = "hello";
const message = (value as string).toUpperCase();

console.log(message); // "HELLO"

在这个示例中,我们定义了一个名为value的变量,并给它赋值一个字符串。我们使用as关键字将value断言为string类型,并调用toUpperCase方法,并把它的结果赋值给message变量。我们输出了message的值。

可选链操作符

在 JavaScript 中,如果我们访问一个对象的属性,而这个属性不存在,就会返回 undefined。例如:

arduino 复制代码
javascriptCopy code
const person = { name: 'John', age: 30 }
console.log(person.job.title) // Uncaught TypeError: Cannot read property 'title' of undefined

在这个例子中,由于 person 对象中没有 job 属性,所以访问 person.job.title 时就会出现错误。

为了避免这种错误,TypeScript 3.7 引入了可选链操作符 ?.。它可以让我们在访问一个对象的属性时,避免因为属性不存在而导致的错误。例如:

arduino 复制代码
typescriptCopy code
const person = { name: 'John', age: 30 }
console.log(person.job?.title) // undefined

const job = { title: 'Software Engineer' }
person.job = job
console.log(person.job?.title) // Software Engineer

在第一次使用 person.job?.title 时,由于 person 对象中没有 job 属性,所以直接返回 undefined,不会报错。

keyof 操作符

keyof操作符用于获取一个类型的所有属性名称组成的联合类型,它可以使我们的代码更加灵活和可维护。在 TypeScript 中,我们可以使用keyof操作符来定义泛型类型和访问对象属性。

下面是一个简单的示例:

typescript 复制代码
typescriptCopy code
interface Person {
  name: string;
  age: number;
  address: string;
}

type PersonKeys = keyof Person; // "name" | "age" | "address"

function getPropertyValue<T, K extends keyof T>(obj: T, key: K) {
  return obj[key];
}

const person: Person = {
  name: "Tom",
  age: 18,
  address: "Beijing",
};

console.log(getPropertyValue(person, "name")); // "Tom"
console.log(getPropertyValue(person, "age")); // 18
console.log(getPropertyValue(person, "address")); // "Beijing"

在这个示例中,我们定义了一个Person接口,它包含了nameageaddress三个属性。我们使用keyof操作符定义了一个名为PersonKeys的类型,它是Person接口的所有属性名称组成的联合类型。我们定义了一个名为getPropertyValue的函数,它接受一个泛型类型参数T和一个名为K的属性名称参数。在函数内部,我们使用泛型类型参数和keyof操作符来访问对象的属性,并返回属性的值。

装饰器

装饰器是一种特殊的声明,可以附加到类声明、方法、属性或参数上,用来描述类的行为。它们为我们提供了一种简洁明了的方式,以声明式的方式添加或修改类的行为。

装饰器在 TypeScript 中是一个实验性的功能,需要启用experimentalDecorators编译选项。

下面是一个简单的示例:

typescript 复制代码
typescriptCopy code
function log(target: any, key: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    console.log(`Calling ${key} with args ${args}`);
    const result = originalMethod.apply(this, args);
    console.log(`Returned value: ${result}`);
    return result;
  };

  return descriptor;
}

class Calculator {
  @log
  add(x: number, y: number) {
    return x + y;
  }
}

const calculator = new Calculator();

console.log(calculator.add(2, 3)); // "Calling add with args [2, 3]", "Returned value: 5", 5

在这个示例中,我们定义了一个名为log的装饰器函数,它接受三个参数:目标类、方法名和方法描述符。我们使用装饰器修饰了Calculator类中的add方法,使其在调用时输出日志。我们创建了一个Calculator实例,并调用了add方法。

字面量类型

字面量类型是一种特殊的类型,它表示一个确定的值,可以用于增强代码的类型安全性。在 TypeScript 中,我们可以使用字面量类型来定义字符串、数字和布尔值等类型。

下面是一个简单的示例:

ini 复制代码
typescriptCopy code
type Gender = "male" | "female";

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

const person: Person = { name: "Alice", age: 30, gender: "female" };

console.log(person); // { name: "Alice", age: 30, gender: "female" }

在这个示例中,我们定义了一个名为Gender的字面量类型,它只允许取值"male""female"。我们定义了一个名为Person的接口,它具有nameagegender三个属性,其中gender的类型为Gender。我们创建了一个Person对象,并输出它的值。

类型推断

类型推断是 TypeScript 中一种自动推断类型的机制,可以使我们的代码更加简洁、易读和可维护。在 TypeScript 中,编译器会根据上下文自动推断表达式的类型,并把它们作为类型注解。

下面是一个简单的示例:

ini 复制代码
typescriptCopy code
const message = "hello";
console.log(message.toUpperCase()); // "HELLO"

在这个示例中,我们定义了一个名为message的常量,并给它赋值一个字符串。我们调用了toUpperCase方法,并输出了它的结果。TypeScript 编译器会自动推断message的类型为string,并把它作为类型注解。

空值和未定义值

在 JavaScript 中,有两种特殊的值,分别是nullundefined。在 TypeScript 中,它们分别对应了nullundefined两种类型。

下面是一个简单的示例:

ini 复制代码
typescriptCopy code
let x: null = null;
let y: undefined = undefined;

在这个示例中,我们定义了两个变量xy,分别赋值为nullundefined

never 类型

never类型表示那些永远不会发生的值,它可以用于增强代码的类型安全性和可维护性。在 TypeScript 中,never类型通常用于以下两种情况:

  • 当一个函数抛出异常或无限循环时,它的返回类型就是never类型。
  • 当一个函数返回类型是一个永远不会实现的类型,它的返回类型也是never类型。

下面是一个简单的示例:

typescript 复制代码
typescriptCopy code
function throwError(message: string): never {
  throw new Error(message);
}

function infiniteLoop(): never {
  while (true) {}
}

在这个示例中,我们定义了两个函数,一个是throwError函数,它接受一个字符串参数message,并抛出一个错误。另一个是infiniteLoop函数,它会无限循环。这两个函数的返回类型都是never类型。

条件类型

条件类型是一种根据一个条件来选择类型的方式,它可以在 TypeScript 中实现一些高级类型操作。在 TypeScript 中,我们可以使用extends关键字和条件语句来定义条件类型。

下面是一个简单的示例:

typescript 复制代码
typescriptCopy code
type IsString<T> = T extends string ? true : false;

type Result1 = IsString<string>; // true
type Result2 = IsString<number>; // false

在这个示例中,我们定义了一个名为IsString的条件类型,它接受一个泛型类型参数T。如果T类型是字符串类型,则条件类型的结果为true,否则为false。我们还定义了两个变量Result1Result2,它们分别是IsString<string>IsString<number>类型的结果。

相关推荐
uhakadotcom1 小时前
视频直播与视频点播:基础知识与应用场景
后端·面试·架构
范文杰1 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪2 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪2 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy2 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom3 小时前
快速开始使用 n8n
后端·面试·github
uhakadotcom3 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom3 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom3 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom3 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试