什么是 TypeScript、基本语法、高级类型、工程应用

# TypeScript 入门

# 什么是 TypeScript

# 发展历史

2012-10:微软发布了 TypeScript 第一个版本 (0.8)

2014-10:Angular 发布了基于 TypeScript 的 2.0 版本

2015-04:微软发布了 Visual Studio Code

2016-05:@types/react 发布,TypeScript 可开发 React

2020-09:Vue 发布了 3.0 版本,官方支持 TypeScript

2021-11:v4.5 版本发布

# 特点

JS:动态类型、弱类型

TS:静态类型、弱类型

JS 的本质是脚本语言,当被执行时才会匹配类型

TS 是不能被直接执行的,会在执行前进行类型匹配,编译后才能执行

# 优势

  1. 静态类型:

    可读性增强:基于语法解析 TSDoc,ide 增强

    可维护性增强:在编译阶段暴露大部分错误 => 多人合作的大型项目中,获得更好的稳定性和开发效率

  2. JS 的超集:

    包含于兼容所有 JS 特性,支持共存

    支持渐进式引入与升级

# 基本语法

# 基础数据类型

/* 字符串 */
const q: string = 'string';
/* 数字 */
const w: number = 1;
/* 布尔值 */
const e: boolean = true;
/* null */
const r: null = null;
/* undefined */
const t: undefined = undefined;

# 对象类型

const bytedancer: IBytedancer = {
    jobId: 9303245,
    name: 'Lin',
    sex: 'man',
    age: 28,
    hobby: 'swimming',
}
interface IBytedancer {
    /* 只读属性:约束属性不可在对象初始化外赋值 */
    readonly jobId: number;
    name: string;
    sex: 'man' | 'woman' | 'other';
    age: number;
    /* 可选属性:定义该属性可以不存在 */
    hobby?: string;
    /* 任意属性:约束所有对象属性都必须是该属性的子类型 */
    [key: string]: any;
}
/* 报错:无法分配到 "jobId",因为它是只读属性 */
bytedancer.job1d = 12345;
/* 成功:任意属性标注下可以添加任意属性 */
bytedancer.plateform = 'data ';
/* 报错:缺少属性 "name", hobby 可缺省 */
const bytedancer2: IBytedancer = {
    jobId: 89757,
    sex: 'woman',
    age: 18,
}

# 函数类型

function add(x: number, y: number): number{
    return x + y;
}
const mult: (x: number, y: number) => number = (x, y) => x * y;

# 函数重载

/* 对 getDate 函数进行重载,timestamp 为可缺省参数 */
function getDate(type: 'string ' , timestamp?: string): string;
function getDate(type: 'date' , timestamp? : string): Date;
function getDate(type: 'string' | 'date', timestamp?: string): Date | string {
    const date = new Date(timestamp);
    return type === 'string' ? date.toLocaleString() : date;
}
const x = getDate( 'date' ); // x: Date
const y = getDate( 'string', '2018-01-10' ); //  y: string
interface IGetDate {
    (type: 'string' , timestamp?: string): string;
    (type: 'date', timestamp? : string): Date;
    (type: 'string' | 'date ', timestamp?: string): Date | string;
}
/* 不能将类型 "(type: any,timestamp: any) => string | Date" 分配给类型 "IGetDate"。
不能将类型 "string | Date" 分配给类型 “string”。
不能将类型 "Date" 分配给类型 “string"。ts (2322) */
const getDate2: IGetDate = (type, timestamp) => {
    const date = new Date(timestamp)
    return type == 'string' ? date.toLocaleString() : date;
}

# 数组类型

/*「类型+方括号」表示 */
type IArr1 = number[];
/* 泛型表示 */
type IArr2 = Array<string | number | Record<string,number>>;
/* 元祖表示 */
type IArr3 = [number, number, string, string]; 
/* 接口表示 */
interface IArr4 {
    [key: number] : any;
}
const arr1: IArr1 = [1, 2, 3, 4, 5, 6];
const arr2: IArr2 = [1, 2, '3', '4', { a: 1 }];
const arr3: IArr3 = [1, 2, '3', '4'];
const arr4: IArr4 = ['string', () => null, {}, []];

# 泛型

function getRepeatArr(target) {
    return new Array(100).fill(target);
}
type IGetRepeatArr = (target: any) => any[];
/* 不预先指定具体的类型,而在使用的时候再指定类型的一种特性 */
type IGetRepeatArrR = <T>(target: T) => T[];
/* 泛型接口 & amp; 多泛型 */
interface IX<TU>{
    key: T;
    val: U;
}
/* 泛型类 */
class IMan<T> {
    instance: T;
}
/* 泛型别名 */
type ITypeArr<T> = Array<T>;
/* 泛型约束:限制泛型必须符合字符串 */
type IGetRepeatStringArr = <T extends string>(target: T) => T[];
const getStrArr: IGetRepeatStringArr = target => new Array(100).fill(target);
/* 报错:类型 "number” 的参数不能赋给类型"string" 的参数 */
getStrArr(123);
/* 泛型参数默认类型 */
type IGetRepeatArr<T = number> = (target: T) => T[];
const getRepeatArr: IGetRepeatArr = target => new Array(100).fill(target);
/* 报错:类型 “string"的参数不能赋给类型"number" 的参数 */
getRepeatArr('123');

# 类型别名 & 类型断言

/* 通过 type 关键字定义了 I0bjArr 的别名类型 */
type IObjArr = Array<{
    key: string;
    [objKey: string] : any;
}>
function keyBy<T extends IObjArr>(objArr: Array<T>) {
    /* 未指定类型时,result 类型为 {(}*/
    const result = objArr.reduce(( res, val, key) => {
        res [key] = val;
        return res;
    }{});
    /* 通过 as 关键字,断言 result 类型为正确类型 */
    return result as Record<stringT>;
}

# 高级类型

# 联合 / 交叉类型

常规写法:繁琐且不准确

interface IHistoryBook {
    author: string;
    type: string;
    range: string}
interface IStoryBook {
    author: string;
    type: string;
    theme: string;
}
type IBookList = Array<IHistoryBook | IStoryBook>;

联合和交叉类型:

联合类型:IA IB;联合类型表示一个值可以是几种类型之一

交叉类型:IA & IB;多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性

type IBookList = Array<{
    author: string;
} & ({
    type: 'history';
    range: string;
} | {
    type: 'story';
    theme: string;
})>

# 类型保护与类型守卫

interface IA { a: 1, a1: 2 }
interface IB { b: 1, b1: 2 }
function log(arg: IA|IB{
    /* 报错:类型 “IA│IB"上不存在属性"a"”。类型 “IB” 上不存在属性 “a" */
    /* 结论:访问联合类型时,处于程序安全,仅能访问联合类型中的交集部分 */
    if (arg.a) {
        console.log(arg.a1)
    } else {
        console.log(arg.b1);
    }
}
/* 类型守卫:定义一个函数,它的返回值是一个类型谓词,生效范围为子作用域 */
function getIsIA(arg: IA |IB) : arg is IA {
    return !!(arg as IA).a;
}
function log2(arg: IA | IB){
    if (getIsIA(arg)){
        console.log(arg.a1)
    } else {
        console.log(arg.b1);
    }                          
}

# 高级类型

interface IMerge {
    <extends Record<string,any>>(sourceObj: Partial<T>, targetObj: T):T;
}
type IPartial<T extends Record<string,any>> = {
    [P in keyof T]?: T[P];
}
// 索引类型:关键字【keyof】,其相当于取值对象中的所有 key 组成的字符串字面量,如
type IKeys = keyof { a: string; b: number }; // = >type IKeys = "a"|"b"“
// 关键字【in】,其相当于取值字符串字面量中的一种可能,配合泛型 P,即表不母个 key
// 关键字【?】,通过设定对象可选选项,即可自动推导出子集类型

# 函数返回值类型

type IDelayCall = <T extends () =>any>(func: T) => ReturnType<T>;
type IReturnType<T extends (...args: any) => any> = T extends (...args: any)>infer R? R: any
// 关键字【extends】跟随泛型出现时,表示类型推断,其表达可类比三元表达式
// 如: T == 判断类型?类型 A: 类型 B
    
// 关键字【infer】出现在类型推荐中,表示定义类型变量,可以用于指代类型
// 如该场景下,将函数的返回值类型作为变量,使用新泛型 R 表示,使用在类型推荐命中的结果中

# 工程应用

  1. Webpack

    在 webpack 中导入 awesome-typescript-loader、babel-loader,配置 tsconfig.js 文件

  2. Node.js

    使用 npm 安装 tsc,配置 tsconfig.js,运行 tsc 编译 ts 文件

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

TagBug 微信支付

微信支付

TagBug 支付宝

支付宝