Day04:TypeScript 的发展与基本语法 | 青训营笔记

63 阅读4分钟

这是我参与「第五届青训营」伴学笔记创作活动的第 4 天。

更棒的一份参考笔记:

「1.9W字总结」一份通俗易懂的 TS 教程,入门 + 实战! - 掘金 (juejin.cn)

为什么需要TypeScript(TS)?

  • 由微软开发
  • 主流框架(React、Vue)均受支持
  • 推荐编辑器:Visual Studio Code
JavaScriptTypeScript
动态类型静态类型
弱类型类型弱类型类型
  • 动态类型:在运行期才判断类型
  • 静态类型:在编译时就判断类型
  • 弱类型语言:容许隐式类型转换

【TS的语言优势】

  • 采用静态类型

    • 可读性增强:基于语法解析TSDoc,IDE增强(类型提示/语法补全)
    • 可维护性增强:在编译阶段暴露大部分错误

    在多人合作的大型项目中可以获得更好的稳定性和开发效率

  • 是 JS 的超集

    • 包含于兼容所有Js特性,支持共存
    • 支持渐进式引入与升级

TS基本语法

基础数据类型

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

添加上类型标注后,就形成了等价的TS:

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

对象类型

interface(接口)是TS设计出来用于定义对象类型的,可以对对象的属性进行描述。它不是 JS 中的关键字。

接口的命名通常以大写I开头。

接口中可以定义:

  • 只读属性:约束属性不可在对象初始化外赋值
  • 可选属性:定义该属性可以不存在
  • 任意属性:约束所有对象属性都必须是该属性的子类型
interface IBytedancer {
    /* 只读属性 */
    readonly jobId: number;
    name: string;
    sex:'man' | 'woman' | 'other';
    age: number
    /* 可选属性 */
    hobby?: string;
    /* 任意属性 */
    [key: string]: any;
}

const bytedancer: IBytedancer ={
    jobId: 9303245
    name: 'Lin',
    sex: 'man',
    age: 28,
    hobby:'swimming',
}
/* 报错:无法分配到"jobId",因为它是只读属性 */
bytedancer.jobId = 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;
    

    定义函数对象也可以先定义接口:

    interface IMult {
        (x: number, y: number): number;
    }
    const mult: IMult = (x, y) => x * y;
    

利用接口也可以实现函数重载:

interface IGetDate {
    (type: 'string', timestamp?: string): string;
    (type: 'date', timestamp?: string): Date;
    (type: 'string' | 'date', timestamp?: string): string | Date;
}

/* 报错 */
const getDate: IGetDate = (type, timestamp) => {
    const date = new Date(timestamp);
    return type === 'string' ? date.toLocaleString() : date;
}

这里似乎有点问题,还在等待老师回复……

数组类型

利用type关键字可以定义类型别名。

  • “类型+方括号”表示【常用】
    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, {}, []];

其他类型

  • 空类型:表示无返回值

    type IEmptyFunction = () => void;
    
  • 任意类型:是所有类型的子类型

    type IAnyType = any;
    
  • 枚举类型:支持枚举值与枚举名的双向映射

    enum EnumExample {
        add = '+',
        mult = '*',
    }
    EnumExample['add'] === '+';
    EnumExample['+'] === 'add';
    

泛型

泛型:不预先指定具体的类型,而是在使用时再推断/指定类型

// 生成一个重复给定元素100次的数组
type IGetRepeatArrR = <T>(target: T) => T[];

const getRepeatArr: IGetRepeatArrR = (target) => {
    return Array(100).fill(target);
}

这样一来,getRepeatArr(1)返回的就是number[]类型。

TS中不需要像C++一样每次使用都明确指定泛型中的T是什么类型,TS可以自行推断。

除了函数、接口、类、别名也可以是泛型,甚至泛型中的类型placeholder还可以是多个:

/* 泛型接口 & 多泛型 */
interface IX<T, U> {
    key: T;
    val: U;
}
/* 泛型类 */
class IMan<T> {
    instance: T;
}
/* 泛型别名 */
type ITypeArr<T> = Array<T>;

泛型约束:可以对泛型的类型placeholder做约束

type IGetRepeatStringArr = <T extends string>(target: T) => T[];
const getStrArr: IGetRepeatStringArr = target => new Array(100).fill(target);

泛型参数默认值:可以对泛型的类型placeholder设置默认值

type IGetRepeatArr<T = number> = (target: T) => T[];
const getStrNumArr: IGetRepeatArr= target => new Array(100).fill(target);
const getStrStrArr: IGetRepeatArr<string> = target => new Array(100).fill(target);

let a = getStrNumArr("1"); // 报错
let b = getStrStrArr("1"); // 正常

类型断言

通过as关键字,可以断言(修改)推断出的类型:

let a: any = [1, 2, 3];
let b: number = (a as number[]).reduce(v => v);

字符串/数 字面量 多选一

type IDomTag = "html" | "body" | "div";