typescript 快速入门

TypeScript

ts 是 js 的超集,它是一种基于类的面向对象编程语言,支持类型注解,可以编译成纯 JavaScript 代码。

为了解决 js 的一些问题, 如:

  1. 不清不楚的数据类型

  2. 错误逻辑不能提醒

  3. 访问未定义的变量

  4. 拼写错误

ts 的核心是静态类型检查

类型声明

typescript 复制代码
let age: number = 25;
let name: string = 'John';
let isMarried: boolean = true;

cosnt add = (x: number, y: number): number =>{
  return x + y;
}

console.log(age + '\n'); // 25
console.log(name + '\n'); // John
console.log(isMarried + '\n'); // true
console.log(add(2, 3) + '\n'); // 5

// age = '25'; // 报错

类型推断

typescript 复制代码
let age = 25;

// 自动类型推断
// age = '25'; // 报错

类型总览

较 js, 新增了:

  1. any
  2. void
  3. unkonwn
  4. never
  5. tuple
  6. enum

自定义类型:

  1. type
  2. interface

注意:

typescript 复制代码
let str1: string;
let str2: String;

str1 = "hello";

str2 = "world";
str2 = new String("world");

// str1 = new String("hello"); // 报错

常用类型

any

一旦设置为 any, 则不进行类型检查。

有显示和隐式两种方式。

any 类型的变量可以赋值给任何其他类型的变量

unknown

typescript 复制代码
let value: unknown;

value = "hello";
value = 123;
value = true;

unknown 类型的变量不能赋值给任何其他类型的变量

typescript 复制代码
let a: unknown;

a = "world";

let b: string = "hello";

// 使用断言
b = a as string;
b = <string>a; // node.js 不能识别

可以把 unkonw 看作保守的 any

never

限制函数的返回值类型,永远不会返回值。

函数要么异常结束, 要不永远不会结束:

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

function loop(): never {
  loop();
}

never 是 ts 可以主动推断出来的类型, 例如:

typescript 复制代码
let a: string = "hello";

if (typeof a === "string") {
  console.log(a.length);
} else {
  console.log(a); // a 的类型被推断为 never
}

void

调用者不应该对其返回值做任何处理, 这是与 : undefined 的区别

typescript 复制代码
function log(message: string): void {
  console.log(message);
}

log("hello"); // 隐式返回undefined which is a kind of void

object

object 类型表示非原始类型, 因为范围较大, 实际应用较少。

Object

能够调用 Object 方法的类型

除了 null 和 undefined, 其他类型都可以作为 Object 类型。

声明对象类型

为了解决 object 和 Object 的问题:

typescript 复制代码
let Person: {
  name: string; // ; , \n 均可
  age: number;
  gender?: string; // ? 表示可选属性
};

person = {
  name: "John",
  age: 25,
  gender: "male",
};

如果还有更多的属性要添加, 可以使用索引签名:

typescript 复制代码
let person: {
  name: string;
  age: number;
  [key: string]: any;
};

person = {
  name: "John",
  age: 25,
  gender: "male",
  address: "New York",
};

声明函数类型

typescript 复制代码
let add: (x: number, y: number) => number; // 声明函数的参数类型和返回类型, TS语法, 非箭头函数

add = (x, y) => x + y; // add 只能赋值这种类型的函数, JS语法, 箭头函数和 function 均可

声明数组类型

typescript 复制代码
let arr1: string[];
let arr2: Array<string>; // 使用泛型

arr1 = ["hello", "world"];
arr2 = ["hello", "world"];

tuple

tuple 是一种特殊的数组类型, 可以储存固定数量的元素, 各元素类型已知, 顺序一定。

typescript 复制代码
let tuple1: [string, number];
let tuple2: [string, number, boolean?];
let tuple3: [string, number[]];
let tuple4: [string, ...number[]];

tuple1 = ["hello", 123];
tuple2 = ["hello", 123, true];
tuple3 = ["hello", [1, 2, 3]];
tuple4 = ["hello", 1, 2, 3];

enum

enum 类型是一种特殊的对象类型, 用于定义一组命名常量。

数字枚举

typescript 复制代码
enum Direction {
  Up = 0,
  Down,
  Left,
  Right,
}

const walk = (direction: Direction) => {
  if (direction === Direction.Up) {
    console.log("Go up");
  } else if (direction === Direction.Down) {
    console.log("Go down");
  } else if (direction === Direction.Left) {
    console.log("Go left");
  } else if (direction === Direction.Right) {
    console.log("Go right");
  }
};

数字枚举的成员会被赋值为从 0 开始递增的数字, 也可以手动指定成员的值。

本质上是一个对象, 属性是只读, 不能赋值

并且反向映射

typescript 复制代码
// 控制台打印为:
{0:'Up', 1:'Down', 2:'Left', 3:'Right', Up: 0, Down: 1, Left: 2, Right: 3}

console.log(Direction[0]) // Up
console.log(Direction.Up) // 0

字符串枚举

typescript 复制代码
enum Color {
  Red = "red",
  Green = "green",
  Blue = "blue",
}

没有 反向映射

常量枚举

typescript 复制代码
cosnt enum Direction {
  Up = 0,
  Down,
  Left,
  Right,
}

console.log(Direction.Up); // 0

编译后:

javascript 复制代码
console.log(0 /* Direction.Up */);

可以减少代码量

type

基本类型别名

typescript 复制代码
type shuzi = number;
lat a: shuzi;
a = 123;

联合类型

typescript 复制代码
type status = number | string;

function slog(status: status): void {
  console.log(status);
}

slog(404);
slog("404");

或者使用字面量

typescript 复制代码
type gender = "male" | "female" | "other";

function sayHello(gender: gender): void {
  console.log(`Hello,I am ${gender}!`);
}

sayHello("male");
sayHello("female");
sayHello("other");

交叉类型

typescript 复制代码
type Person = {
  name: string;
  age: number;
  gender: string;
};

type Student = {
  school: string;
  grade: number;
  subject: string;
};

type PersonAndStudent = Person & Student;

let personAndStudent: PersonAndStudent = {
  name: "John",
  gender: "male",
  school: "Harvard",
  grade: 12,
  subject: "Math",
  age: 25,
};

特殊情况

typescript 复制代码
type myfun = () => void;

let myfunvar: myfun = () => {
  return "hello"; // 合法
};

console.log(myfunvar()); // hello

比如, 在某些操作:

typescript 复制代码
const arr: number[] = [1, 2, 3, 4, 5];

const brr: number[] = [];

arr.forEach((item) => brr.push(item)); // 这时会返回lenth, 不是void

说白了, 就是为了兼容 js

类修饰符

  1. public: 默认修饰符, 允许在任何地方访问
  2. protected: 只允许在类的内部和子类中访问
  3. private: 只允许在类的内部访问
  4. readonly: 只读属性, 只能在声明时或构造函数中初始化, 可以和其他修饰符连用

属性的简写形式

简写前:

typescript 复制代码
class Person {
  public name: string;
  age: number; // 不写修饰符默认public
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

简写后:

typescript 复制代码
class Person {
  constructor(public name: string, public age: number) {}
}

抽象类

不能被实例化, 只能被继承, 用于定义一组抽象方法和属性, 让子类去实现, 也可以有普通的方法

何时使用抽象类:

  1. 为一组相关的类定义通用的行为(方法和属性)
  2. 提供某些方法和实现, 让子类去继承
  3. 强制子类去实现抽象方法
  4. 共享代码逻辑
typescript 复制代码
abstract class Person {
  constructor(public name: string, public age: number, public gender: string) {}

  abstract greet(): string;

  introduce(): void {
    console.log("this is PersonClass");
  }
}

class Student extends Person {
  constructor(name: string, age: number, gender: string, public major: string) {
    super(name, age, gender);
  }

  greet(): string {
    return `Hello, my name is ${this.name}, I am a ${this.age}-year-old ${this.gender} student majoring in ${this.major}.`;
  }
}

const student1 = new Student("John", 20, "male", "Computer Science");
console.log(student1.greet());

接口

定义类结构

typescript 复制代码
interface PersonInterface {
  name: string;
  age: number;
  greet(): string;
}

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

  greet(): string {
    return `Hello, my name is ${this.name}, I am a ${this.age}-year-old person.`;
  }
}

定义对象的接口

typescript 复制代码
interface PersonInterface {
  name: string;
  age: number;
  gender?: string;
  greet(): string;
}

const person: PersonInterface = {
  name: "John",
  age: 25,
  greet(): string {
    return `Hello, my name is ${this.name}, I am a ${this.age}-year-old person.`;
  },
};

定义函数的接口

typescript 复制代码
interface AddInterface {
  (x: number, y: number): number;
}

const add: AddInterface = (x, y) => x + y;

接口继承

typescript 复制代码
interface AnimalInterface {
  name: string;
  eat(): void;
}

interface DogInterface extends AnimalInterface {
  bark(): void;
}

class Dog implements DogInterface {
  constructor(public name: string) {}

  eat(): void {
    console.log(`${this.name} is eating.`);
  }

  bark(): void {
    console.log(`${this.name} is barking.`);
  }
}

注: 接口可以自动合并, 并且一个类实现多个接口

泛型

泛型允许我们在定义函数, 接口, 类的时候, 使用类型参数来表示未指定的类型, 这些参数在具体使用时, 才被指定具体的类型, 泛型能让同一段代码适用于多种类型, 同时任然保持类型的安全性

泛型函数

typescript 复制代码
function logData<T>(data: T) {
  console.log(data);
}

logData<string>("hello");
logData<number>(123);
typescript 复制代码
function logData<T, U>(data1: T, data2: U): T | U {
  return Date.now() % 2 === 0 ? data1 : data2;
}

console.log(logData<string, number>("hello", 123));
console.log(logData<number, string>(123, "world"));

泛型接口

typescript 复制代码
interface DataInterface<T> {
  data: T;
}

const data1: DataInterface<string> = {
  data: "hello",
};

泛型类

typescript 复制代码
class DataClass<T> {
  constructor(public data: T) {}

  logData() {
    return this.data;
  }
}

const data1 = new DataClass<string>("hello");

类型声明文件

.d.ts, 在 ts 文件中引入 js 时, 需要使用声明文件对 js 进行类型声明, 否则会报错

装饰器

装饰器的本质是一种特殊的函数, 它可以对: 类、方法、属性、参数等进行扩展, 同时能让代码更加简洁

类装饰器

类装饰器是一个应用在类声明上的函数, 可以为类添加额外的功能, 或添加额外的逻辑

typescript 复制代码
function Demo(target: Function) {}

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

返回值

如果返回一个类, 则会替换原来的类

其他则不做影响

类型限制

Function 类型太宽泛了

可以用

typescript 复制代码
type Constructor = new (...args: any[]) => {};

替换被装饰的类

typescript 复制代码
type Constructor = new (...args: any[]) => {};

interface Person {
  getCreationTime(): Date;
}

function logTime<T extends Constructor>(Target: T) {
  return class extends Target {
    createdTime: Date;
    constructor(...args: any[]) {
      super(...args);
      this.createdTime = new Date();
    }
    getCreationTime() {
      return this.createdTime;
    }
  };
}

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

const person = new Person("John", 25);

console.log(person.getCreationTime());

装饰器工厂

一个能返回装饰器函数的函数

typescript 复制代码
function logInfo(cut: number) {
  return function (target: Function) {
    target.prototype.introduce = function () {
      for (let i = 0; i < cut; i++) {
        console.log(this.name + " " + this.age);
      }
    };
  };
}

interface Person {
  introduce(): void;
}

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

const p = new Person("John", 30);

p.introduce();

装饰器组合

ts 优先执行装饰器工厂, 从上到下, 所以先输出 test2 工厂, test3 工厂

再从下到上执行装饰器, test4, test3, test2, test1

typescript 复制代码
@test1
@test2()
@test3()
@test4
class Person {
  constructor(public name: string, public age: number) {}
}

属性装饰器

typescript 复制代码
function Demo(target: object, key: string) {
  console.log(target, key);
}

class Person {
  @Demo name: string;
  age: number;

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

target: 构造函数(类)的 prototype

key: 属性名

若为静态属性, target 为类本身

方法装饰器

typescript 复制代码
function logInfo(target: object, key: string, descriptor: PropertyDescriptor) {
  console.log(target, key, descriptor);
}

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

  @logInfo
  speak() {
    return "hello";
  }
}

target: 构造函数(类)的 prototype

key: 属性名

descriptor: 描述符, 包含了该属性的各种信息, 如: value, get, set, enumerable, configurable, writable

若为静态属性, target 为类本身

相关推荐
拾柒SHY35 分钟前
XSS-Labs靶场通关
前端·web安全·xss
前端婴幼儿41 分钟前
前端主题切换效果
前端
一 乐42 分钟前
水果销售|基于springboot + vue水果商城系统(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·后端
Qin_jiangshan1 小时前
如何成为前端架构师
前端
剪一朵云爱着1 小时前
PAT 1164 Good in C
c语言·开发语言
LNN20221 小时前
Qt 5.8.0 下实现触摸屏热插拔功能的探索与实践(3)
开发语言·qt
移远通信1 小时前
配网-复杂场景
服务器·开发语言·php
dolt021 小时前
基于deepseek实现的ai问答小程序
前端·开源
一只小bit1 小时前
Qt 快速开始:安装配置并创建简单标签展示
开发语言·前端·c++·qt·cpp