认识TypeScript

205 阅读6分钟

TS官网演练场:www.typescriptlang.org/zh/play/

一、TypeScript基础类型

1、数字number

const num1: number = 10; // 十进制
const num2: number = 0b0101; // 二进制
const num3: number = 0o17; // 八进制
const num4: number = 0xff; //十六进制

2、字符串string

const str: string = 'str';

3、布尔值boolean

const isBool: boolean = true;

4、nullundefined

  • null和undefined类型一般不会单独使用,一般会用在联合类型中。

  • 这两个类型是所有类型的子类型,一般情况下我们可以给其他类型赋值为null和undefined(如果报错的话,可能是tsconfig.json中开启了严格模式)。

const n: null = null;
const u: undefined = undefined;

const v: number | null = null;

5、数组Array

数组有两种写法:

  • 数组元素类型后面加上[]
  • 泛型数组Array<数组类型>
const list1: number[] = [1, 2];
const list2: Array<number> = [1, 2];

6、元组Tuple

元组类型表示一个已知元素数量和数组的数组,各元素的类型可以不用相同。

const tuple: [number, string] = [1, '2'];

//也可以使用?表示这个值是可选的
const tuple: [number, string?] = [1];

7、枚举enum

enum是对JavaScript标准类型的一种补充,使用枚举类型可以为一组数值赋予语义化的名字。

枚举值默认从0开始,也可以设置初始值从1开始递增,也可以为每一个名称设置值。

enum Color {
    Red = 1,
    Green = 3,
    Blue = 4,
}

// 我们可以通过Color根据定义的名字获取枚举的数值,也可以根据数值获取枚举值的名字
const myColor: Color = Color.Red;
console.log(myColor, Color.Red, Color[3]); // 1 1 'Green'

8、任意any

对于不确定的类型可以使用any

let value: any = 1;
value = false;

const arr: any[] = [1, false, 'str'];

9、函数void

void表示没有任何类型,一般用来说明函数的返回值不能是null或undefined之外的值(严格模式下只支持返回undefined)

// 没有参数或返回值
function a(): void {
    return undefined;
}
// 有参数和返回值,最后一个值设置可选
function fun(a: number, b?: string): number {
    return 100;
}
fun(100);
//使用rest
function fun(a: number, b: string, ...rest: number[]): number {
    return 100;
}
fun(100, '100', 1, 2);

10、对象object

  • 我们可以使用接口定义对象类型

  • 严格模式下可以返回undefined,非严格模式下可以返回null和undefined

function func(obj: object): object {
    console.log(obj);
    return {};
}

func(new Number(1));
func(1); // Error

// 使用接口定义对象
interface Obj {
    name: string,
    age: number
}

const o1: Obj = {
    name: 'name',
    age: 3
}

11、 联合类型

联合类型(Union Types)变量的值可以为多种类型中的一种

const a: string | number = 1;

12、类型断言

TypeScript 允许你覆盖它的推断,并且能以你任何你想要的方式分析它,这种机制被称为「类型断言」。

类型断言是一个编译型的语法。

它之所以不被称为「类型转换」,是因为转换通常意味着某种运行时的支持。但是,类型断言纯粹是一个编译时语法,同时,它也是一种为编译器提供关于如何分析代码的方法。

参考:类型断言

/* 
类型断言(Type Assertion): 可以用来手动指定一个值的类型
语法:
    方式一: <类型>值
    方式二: 值 as 类型  tsx中只能用这种方式
*/

const array = [1, 2, 3];
let result = array.find(item => item > 2) as number;
// 如果不加 as number,result 会报错 “result可能为undefined”
// 加上 as number 覆盖 ts 的推断,表示我断言这是一个数字
result *= 5; 

13、类型推断

不推荐使用,最好使用明确的类型注解

TS会在没有明确指定类型的时候进行类型推测

  • 定义变量时赋值了,推测为对应的类型
  • 定义变量时没有赋值,推断为any类型

14、类型别名type

type myUserName = string | number

let u1: myUserName = 12
let u2: myUserName = '12'

二、接口

1、普通对象

使用接口来定义对象的类型,接口是对对象的状态(属性)和行为(方法)的抽象(描述)。

当我们定义了接口类型的对象之后,不可以多写或少写属性,但是可以设置属性可选?,也可以设置属性只读readonly

interface obj {
    readonly name: string, // readonly设置属性只读
    age: number,
    sex?: string // ?表示属性可选
}

const o1: obj = {
    name: 'name',
    age: 3
}
o1.name = 'new-name' // Error

2、函数

/* 
接口可以描述函数类型(参数的类型与返回的类型)
*/

interface SearchFunc {
  (source: string, subString: string): boolean
}

// 参数名称可以不用一致,但是类型必须一致
const mySearch: SearchFunc = function (source: string, sub: string): boolean {
  return source.search(sub) > -1
}

console.log(mySearch('abcd', 'bc'))

3、类

  • 一个类可以实现多个接口
  • 一个接口可以继承多个接口
interface Alarm {
    alert(): any
}

interface Light {
    LightOn(): void,
    LightOff?(): void
}

interface Sound extends Alarm {
    turnOn(): void
}

class Car implements Alarm, Light {
    alert() {}
    LightOn() {}
}
class SmallCar implements Sound {
    alert() {}
    turnOn() {}
}

三、泛型

// 如果后续想传入两个string变量,生成string数组,这个方法就不合适了
function myFun(a: number, b: number):number[] {
    return [a, b]
}
myFun(1,2)

为了解决这个问题,我们可以使用泛型,在函数中定义泛型,函数调用时指定泛型.

这里的T是一种变量,我们也可以定义其他的变量名,也可以设置多个变量。

function myFun<T>(a: T, b: T):T[] {
    return [a, b]
}

myFun<number>(1,2)

也可以在类中使用泛型

class MyClass<T> {
    name: T;
    constructor(name: T) {
        this.name = name;
    }
}

const cla = new MyClass<string>('str');

四、进阶

1、函数重载

JavaScript不支持函数重载,但是TypeScript支持了,可以创建多个名称一样,但是参数类型和返回值不同的函数。

function hello(x: string): string;
function hello(x: number): string;
function hello(x: string | number): string {
    if (typeof x === 'string') {
        return 'string';
    }
    if (typeof x === 'number') {
        return 'number';
    }
    return '';
}

hello(1);

2、接口继承

Child接口继承自Parent,如果一个变量声明为Child类型,那么要同时具有Parent的特性。

interface Parent {
    prop1: string;
    prop2: number;
}

interface Child extends Parent {
    prop3: string;
}

const p: Child = {
    prop1: 'p1',
    prop2: 2,
    prop3: 'p3',
};

3、类的修饰符

  • ?:属性可选,可以传入这个参数,也可以不穿
  • public:可以在类、子类、实例对象中访问
  • private:只能在类中访问
  • protected:只能在类、子类中访问
  • static:静态属性,通过类来访问,可以被子类继承
  • readonly:只读属性,不可以修改
class Animal {
    // ts的语法,用来声明类Animal上存在属性name,是string
    name: string;
    // 表示该属性可选
    type?: string;
    // 自动识别为number类型,并设置为默认值,相当于age: number,并且在construct中设置初始值为1
    age = 1;
    // 默认都是public,可以在类、子类、实例对象中访问
    // private表示只能在类Animal中访问,属于类的私有属性
    private data?: number[];
    // protected:受保护的,只能在Animal类及其子类中使用
    protected pData?: string[];
    // 静态属性,只能在类内部使用
    static sData: string;
    // 只读,不可修改
    readonly rDate?: string;

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

class Cat extends Animal {
    constructor(name: string) {
        super(name);
        console.log(this.pData);
    }
}
const d = new Animal('dog');
console.log(d.age);

image.png

4、类的存取器

class User {
    private _password: string = '';

    get password(): string {
        return this._password + '****';
    }

    set password(newPassword: string) {
        this._password = newPassword;
    }
}

const user1 = new User()
console.log(user1.password); // 会调用get方法

5、抽象类

抽象类是作为子类的基类去使用,抽象类本身不具备实例化的这种需求,可以理解为规范了一种格式,我们从抽象类派生出一些子类,通过子类进行实例化。

抽象类通过abstract声明,不可被实例化,内部可以包含抽象属性和方法,也可以包含非抽象属性和方法。

抽象属性不需要被初始化,在子类中被实现(初始化)。

abstract class A {
    abstract a: string;
    abstract b(): void;
}

class B extends A {
    a: string = '1';
    b() {
        console.log('');
    }
}

学习资料:

24kcs.github.io/vue3_study/…

www.bilibili.com/video/BV1q6…