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 为类本身

相关推荐
南极星100517 分钟前
蓝桥杯JAVA--启蒙之路(十)class版本 模块
java·开发语言
未来之窗软件服务20 分钟前
未来之窗昭和仙君(六十五)Vue与跨地区多部门开发—东方仙盟练气
前端·javascript·vue.js·仙盟创梦ide·东方仙盟·昭和仙君
baidu_2474386121 分钟前
Android ViewModel定时任务
android·开发语言·javascript
嘿起屁儿整34 分钟前
面试点(网络层面)
前端·网络
Dev7z34 分钟前
基于 MATLAB 的铣削切削力建模与仿真
开发语言·matlab
不能隔夜的咖喱40 分钟前
牛客网刷题(2)
java·开发语言·算法
VT.馒头40 分钟前
【力扣】2721. 并行执行异步函数
前端·javascript·算法·leetcode·typescript
小天源1 小时前
Error 1053 Error 1067 服务“启动后立即停止” Java / Python 程序无法后台运行 windows nssm注册器下载与报错处理
开发语言·windows·python·nssm·error 1053·error 1067
有位神秘人1 小时前
Android中Notification的使用详解
android·java·javascript
肉包_5111 小时前
两个数据库互锁,用全局变量互锁会偶发软件卡死
开发语言·数据库·c++