ts基础

发布时间 2023-06-17 08:01:19作者: 轻舟渡过桥儿

ts基础

官网:中文网
version: v4.6.3(最新版)


概念

添加了类型系统的 JavaScript,适用于任何规模的项目,它强调了 TypeScript 的两个最重要的特性——类型系统、适用于任何规模。从 TypeScript 的名字就可以看出来,「类型」是其最核心的特性。
我们知道,JavaScript 是一门非常灵活的编程语言:
● 它没有类型约束,一个变量可能初始化时是字符串,过一会儿又被赋值为数字。
● 由于隐式类型转换的存在,有的变量的类型很难在运行前就确定。
● 基于原型的面向对象编程,使得原型上的属性或方法可以在运行时被修改。
● 函数是 JavaScript 中的一等公民,可以赋值给变量,也可以当作参数或返回值。
这种灵活性就像一把双刃剑,一方面使得 JavaScript 蓬勃发展,无所不能,从 2013 年开始就一直蝉联最普遍使用的编程语言排行榜冠军;另一方面也使得它的代码质量参差不齐,维护成本高,运行时错误多。
而 TypeScript 的类型系统,在很大程度上弥补了 JavaScript 的缺点

安装

// 安装 npm install -g typescript

使用

tsc 文件路径

原始数据类型

JavaScript 的类型分为两种:原始数据类型(Primitive data types)和对象类型(Object types)

原始数据类型主要有

boolean、number、string、null、undefined 以及 ES6 中的新类型 Symbol 和 ES10 中的新类型 BigInt。

基本上使用

// 声明一个isDone为boolean类型
let isDone: boolean = false;

// 声明一个decLiteral为数值类型类型
let decLiteral: number = 6;

let myName: string = 'Tom';

let u: undefined = undefined;

let n: null = null;

// 声明一个 void 类型的变量没有什么用,因为你只能将它赋值为 undefined 和 null
// (如果没有特别设置编译的话)
let unusable: void = undefined;

// 声明函数的返回值
// 函数返回一个 字符串
function fun (): string {
  return '你好'
}
// JavaScript 没有空值(Void)的概念,
// 在 TypeScript 中,可以用 void 表示没有任何返回值的函数
function fun (): void {
  alert("我啥都没返回")
}

注意null、undefind和void的区别
undefined 和 null 是所有类型的子类型。也就是说 undefined 类型的变量,可以赋值给 number 类型的变量

任意数据类型(不推荐用)

概念

任意值(Any)用来表示允许赋值为任意类型。如果是一个普通类型,在赋值过程中改变类型是不被允许的,但如果是 any 类型,则允许被赋值为任意类型,简单来说就是任何方法和对象都可以用any来表示。

使用

let myFavoriteNumber: any = 'seven';
myFavoriteNumber = 1

const fun = (): any => 2

类型推论

概念

如果没有明确的指定类型,那么 TypeScript 会依照类型推论(Type Inference)的规则推断出一个类型。

具体代码

// 这行代码我们并没有手动指定name为string类型,但是ts会自动推断他为string
let name = '张三'

// 同理这个方法ts 也会自动推断出返回值为number类型
const fun = () => 1****

联合类型

概念

联合类型(Union Types)表示取值可以为多种类型中的一种

简单使用

// 允许 myFavoriteNumber 的类型是 string 或者 number,但是不能是其他类型
let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;

枚举

/**
 * 使用 enum定义 后面跟我们的枚举名
 * 
 */
enum OrderStaus {
  // SUCCESS 这个大写的是枚举名,后面跟小写的是枚举值
  SUCCESS = 'success',
  ERROR = 'error',
};

// 使用,他拿到的结构就是success
OrderStaus.SUCCESS

interface Order {
  status: OrderStaus
}

// 首先定义一个接口
const order: Order = {
  /**
   * 接口里面有个字段是可以枚举的,如果说这个对象使我们手动创建的,
   * 就需要去使用枚举值进行赋值
   * 
   * OrderStaus.SUCCESS 的枚举值是 success
   */
  status: OrderStaus.SUCCESS
}
const order2: Order = {
  status: OrderStaus.ERROR
}

console.log(order, order2)

// 如果感觉上述做枚举,太麻烦了,则可以直接使用
interface Order {
  // 字符串枚举的形式
  status: 'success' | 'error'
}

const order: Order = {
  status: "success"
}

const order2: Order = {
  success: 'error'
}

对象类型——接口

概念

在 TypeScript 中,我们使用接口(Interfaces)来定义对象的类型。在面向对象语言中,接口(Interfaces)是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类(classes)去实现(implement)。TypeScript 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对「对象的形状(Shape)」进行描述

使用

// 使用interface 定义一个接口 接口名为Person注意接口明首字母大写
interface Person {
    name: string;
    age: number;
}
// 使用接口Person 定义这个tom这个对象的类型
let tom: Person = {
    name: 'Tom',
    age: 25
};
// 上面的例子中,我们定义了一个接口 Person,接着定义了一个变量 tom,
// 它的类型是 Person。这样,我们就约束了 tom 的形状必须和接口 Person 一致

如果对象里面有个值可能没有则在对应的key前面使用?标注

interface Person {
    name: string;
    age?: number;
}
// 使用接口Person 定义这个tom这个对象的类型
let tom: Person = {
    name: 'Tom',
};

// age使用了?就表示使用这个接口约束对象的时候可以不写age这个属性

如果对象里面会多出来一些属性,这些属性的key不确定则可以(当然也可以用keyof 的形式)

interface Person {
    name: string;
    // 这种形式代表这个对象可以包含任何的key
    [key: string]: string
}
// 使用接口Person 定义这个tom这个对象的类型
let tom: Person = {
    name: 'Tom',
    aaa: '我是随便弄的'
};

数组类型

// 这个数组里面的值都是数组
let arr : number[] = [1, 1, 2, 3, 5];

interface Person {
    name: string;
}

// 这是个数组包对象的形式,对象的格式为Person
let arr2: Person[] = [{name: '李四'}]

函数

在interface里面使用函数类型

// 比如说sex是个函数,这个函数返回一个字符串
interface Person {
    sex: () => string;
}

// 如果说这个函数需要传参数,参数的类型为string则
interface Person {
    sex: (name: string) => string;
}

定义函数接口参数的类型

// 这个函数接收一个name,并且name类型为string,且是必填参数
const fun = (name: string) => {
  console.log(name)
}

// 这个函数接收一个age,age不是必传参数
const fun2 = (age?: number) = > {
  
}

interface Person {
    sex: boolean
}
// 这个函数接收一个data参数参数为必传类型是个对象
// arr 可以不传,类型是个数组包对象 
// 注意:必传参数一定要在非必传参数前面
const fun2 = (data:Person, arr?: Person[]) => {

}

类型断言

用途

手动断定它的类型

interface Cat {
    name: string;
    // 这是一个函数
    run(): void;
}

interface Fish {
    name: string;
    swim(): void;
}

// animal 有可能是 Cat 也有可能是 Fish
function isFish(animal: Cat | Fish) {
    // 判断animal 里面的 swim 是不是一个方法,如果是则返回true
    if (typeof animal.swim === 'function') {
        return true;
    }
    return false;
}
// 这个时候,以上代码会报错 这个时候就可以用类型断言,
// 来手动告诉ts animal 里面有 swim 这个类型
function isFish2(animal: Cat | Fish) {
  // 使用as 来进行 类型断定
    if (typeof (animal as Fish).swim === 'function') {
        return true;
    }
    return false;
}

类里面修饰方法的属性

静态属性,不需要new 就可以直接使用

// 不需要new 就可以直接用
class Animal {
  static num = 42;
}

console.log(Animal.num); // 42

public private 和 protected

public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的
private 修饰的属性或方法是私有的,不能在声明它的类的外部访问
protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的

class Animal {
  public name;
  private age;
  protected sex;
}

const animal = new Animal()

// 可以正常获取或者修改
animal.name

// 获取不到,并且也不能修改
animal.age

// 可以获取到但是不能修改
animal.sex

泛型(很重要)

概念

泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性
在方法名或者接口名前面可以定义泛型,或者说传入泛型

// 如这个方法我们并不知道value的类型是什么只能用any
function createArray(length: number, value: any): Array<any> {
    let result = [];
    for (let i = 0; i < length; i++) {
        result[i] = value;
    }
    return result;
}

createArray(3, 'x');

// 上面的那个方法可以用 泛型来解决
// 在函数名后面加一个<T>这个T就是传入的类型,然后把这个类型约束到value上
function createArray<T>(length: number, value: T): Array<T> {
    let result: T[] = [];
    for (let i = 0; i < length; i++) {
        result[i] = value;
    }
    return result;
}

// 接口接收一个泛型
interface A<T> {
  val: T
}

// 给接口传入泛型
const fun = (data: A<string>) => {

}

fun({
  val: 'string'
})