TypeScript 基础用法速查指南

201 阅读1分钟

01、Hello TypeScript

江湖规矩,先来个 Hello 感受一下:

const hello = (name: string) => {
    console.log(`Hello ${name}`)
}

hello('TypeScript');

很简单,通过在 name 后面使用冒号,说明参数是 string 类型,这就是 TypeScript 的基本用法。

02、原始数据类型

const a: string = 'string';

const b: number = 100;

const c: boolean = true;

const d: void = undefined;

const e: null = null;

const f: undefined = undefined;

const g: symbol = Symbol();

03、TypeScript 中的 object

所有非原始类型,包括对象、数组、函数,因此以下写法都是 OK 的:

const obj: object = {};
const ary: object = [];
const fn: object = function() {};

04、数组类型

数组的定义方式有两种:

//  1、Array<T>:先用Array说明是个数组,然后在<>里面规定数组里面的每一项的数据类型
const ary1: Array<number> = [1, 2, 3];

//  2、T[]:先规定数据类型,然后通过[]说明它是个数组
const ary2: number[] = [1, 2, 3];

实例:

function sum(...args: number[]) {
    return args.reduce((total, current) => total + current, 0);
}

//  sum(1, 2, 'c');     //  'c'会报错,因为不是number类型

05、元组

指的是明确变量类型及个数的数组。

const tuple: [number, string, boolean] = [1, 'string', true];
const [n, s, b] = tuple;

06、枚举 enum

通过 enum 关键字,给一组数据起一个固定的名字,每一个成员都有固定的值。

原始 Javascript 形式:

const STATUS_TYPES = {
    NotStart: 0,
    Starting: 1,
    Started: 2
}

枚举形式:

enum STATUS_TYPES {
    NotStart = 0,
    Starting = 1,
    Started = 2
}

索引枚举可省略数值不写,会默认从 0 开始累加,如以上可简写成:

enum STATUS_TYPES {
    NotStart,
    Starting,
    Started
}

如需从 1 开始累加,则只需要把 NotStart = 1。字符串枚举则需每个依次定义,但不常用,这里也不做示例。

直接通过 enum 定义的枚举会影响编译结果,生成双向键值对的代码,即可通过索引访问名称 STATUS_TYPES[0] = 'NotStart',若不需要,可使用常量枚举,在 enum 前面加上 const 即可:

const enum STATUS_TYPES {
    NotStart,
    Starting,
    Started
}

07、函数类型

在括号中指定入参,括号后面指定返参( return ):

function fn1(a: number, b: string, ...rest: any): string {
    //  由于返参类型指定为 string,则只能返回字符串
    return 'fn1';
}

fn1(100, 'string', {});

若不需要返参,则指定为 void

function fn2(a: number, b: string, ...rest: any): void {
    ...
}

08、类型断言 as

TypeScript 会根据函数返回值等,自动推测出数据类型。

const nums = [10, 100, 200];

let res = nums.find( i => i > 1);

上面的代码中,res 会被自动推测为 numberundefined,而 undefined 不能用来计算,因此直接使用let square = res * res;会报错,我们可以通过 as 关键字来断言,指定类型:

//  通过as关键字来断言,告诉ts: _res是number类型
let _res = res as number;

//  此写法jsx语法下会冲突,不建议使用
// let _res = <number>res;

let square = _res * _res;

09、接口 interface

可以理解为一种约定,指定了各种属性的成员。

必填成员:直接指定字段名和类型 title: string

可选成员:使用 ? 关键字 subTitle?: string

只读成员:使用 readonly 关键字 readonly summary: string

任意成员:使用 prop 关键字 [prop: string]: string

实例:

interface Post {
    title: string;
    content: string;
    subTitle?: string;          //  可选成员
    readonly summary: string    //  只读成员
    // [prop: string]: string   //  任意成员,因此会和?冲突
}

function printPost(post: Post) {
    console.log(post.title);
    console.log(post.content);
}

printPost({
    title: 'title',
    content: 'content',
    summary: 'summary'
})

10、类 class

用来描述一类具体对象的抽象成员,Typescript 增强了 class 的相关语法,关键字有以下几个:

public公有变量,外部可访问(默认,可不写)

protected 受保护的变量,只允许子类访问

private 私有变量,外部不可访问,子类也不能访问

readonly 只读变量,不允许修改

实例:

class Person {
    public name: string = 'init name'           //  公有变量,外部可访问(默认,可不写)
    private age: number = 18                    //  私有变量,外部不可访问
    protected readonly gender: boolean = false  //  受保护的变量,只允许子类访问(readonly需在后面)

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

    sayHi(msg: string): void {
        console.log(`${this.name} say ${msg}`)
    }
}

const tom = new Person('tom', 20);
// console.log(tom.age)     //  age为private变量,外部不可访问

class Student extends Person{
    private constructor(name: string, age: number) {
        super(name, age);
        // console.log(this.age);   //  age为private变量,子类也不可访问  
        console.log(this.gender);
    }

    static create(name: string, age: number) {
        return new Student(name, age);
    }
}

//  const jack = new Student('jack', 25);   //  由于constructor是private私有变量,外部不可访问
const jack = Student.create('jack', 25);    //  通过静态方法create去创建

11、类与接口、implements 关键字

//  单一职责原则,一个接口只定义一个功能
interface Eat {
    eat(food: string): void
}

interface Run {
    run(distance: number): void
}

//  使用implements关键字指定接口,多个接口使用 , 进行分割
class Person implements Eat, Run{
    eat(food: string) {
        console.log(`Person eat ${food}`);
    }

    run(distance: number) {
        console.log(`Person run ${distance}`);
    }
}

class Animal implements Eat, Run {
    eat(food: string) {
        console.log(`Animal eat ${food}`);
    }

    run(distance: number) {
        console.log(`Animal run ${distance}`);
    }
}

12、抽象类 abstract

使用 abstract 定义的类,只能被继承,不能被 new 创建实例对象;

父类中通过 abstract 定义的抽象,子类必须声明该方法。

abstract class Animal {
    eat(food: string): void {
        console.log(`Animal eat ${food}`)
    }

    //  有抽象方法时,子类必须声明该方法
    abstract run(distance: number): void
}

//  const newAnimal = new Animal();     //  报错,只能被继承,不能被 new 创建实例对象

class Dog extends Animal {
    run(distance: number): void {
        console.log(`Dog run ${distance}`);
    }
}

13、泛型 <T>

定义函数、接口、类的时候没有指定具体的类型,调用的时候才去传递。

function createNumberArray(length: number, value: number): number[] {
    const ary = Array<number>(length).fill(value);
    return ary;
}


function createStringArray(length: number, value: string): string[] {
    const ary = Array<string>(length).fill(value);
    return ary;
}

//  以上代码有大量冗余,使用泛型解决
function createArray<T>(length: number, value: T): T[] {
    const ary = Array<T>(length).fill(value);
    return ary;
}

const res = createArray<string>(3, 'string');
const _res = createArray<number>(3, 10);

14、类型声明 declare

应用场景实例:由于引入的方法没有事先声明,导致 TypeScript 报错,可使用 declare 声明后再调用。

import { camelCase } from 'lodash';

declare function camelCase(input:string): string

const res = camelCase('hello ts')
//  此方案可通过使用 npm 安装“类型声明模块”替代