• TypeScript 第一章:入门教程


    介绍

    typescript 是 javascript 的一个超集,typescript 可以运行于任何系统,并且是开源免费的。

    typescript 有以下几个特点:

    • typescript 会在编译时对代码进行严格的静态类型检查,可以在编码阶段就发现问题,而不是在上线运行时才发现
    • typeScript 语法遵循 ES 规范,更细速度快,不断支持最新的 ECMAScript 新特性,如装饰器、public/private 修饰符
    • typescript 支持 OOP(面向对象)的接口,抽象类,多态特性
    • typescript 可以为 IDE 提供更好的代码补全、接口提示、跳转到定义
    • 还有重要一点是众多科技公司已经采用 typeScript 进行开发,也是前端工程师需要掌握的就业技能

    安装环境

    全局安装 TS

    npm install typescript -g
    
    • 1

    项目安装

    npm install typescript -D
    
    • 1

    查看版本

    tsc -V
    
    • 1

    编译TS

    tsc 01.ts
    
    # 或开启监听
    
    tsc 01.ts -w
    
    • 1
    • 2
    • 3
    • 4
    • 5

    01.ts

    const hhh  = 'ok'
    
    • 1

    执行 tsc 01.ts

    01.js

    var hhh = 'ok';
    
    • 1

    配置文件

    TS 支持对编译过程使用配置项自定义

    初始化

    执行以下命令创建配置项 tsconfig.json

    tsc --init
    
    • 1

    然后执行以下命令使用配置项的定义进行监测

    tsc -w
    
    • 1

    配置选项

    配置说明
    noImplicitAny禁止使用隐含的 any 类型,如函数参数没有设置具体类型
    strictNullChecks开启时不否允许将 null、undefined 赋值给其他类型比如字符串
    target转换成 JS 的版本
    strict是否严格模式执行
    module

    TS的类型推断

    当没有明确设置类型时,系统会根据值推断变量的类型

    字符串

    下例中系统会根据值推断 hj 变量为 string,当将 hj 设置为 18 的 number 类型时编译时将报误

    let hj = 'ok'; // let hhh: string
    hj = 18; // 不能将类型“number”分配给类型“string”
    
    • 1
    • 2

    数值

    ts 中的数值类型包括了小数、负数、整数

    let hj = 1 // let hj: number
    hj = 1.1
    hj = -111
    
    • 1
    • 2
    • 3

    布尔值

    值为 true 或 false 会被推断为 boolean 类型

    let state = true; // let state: boolean
    
    • 1

    数组

    下面是数组类型的推断结果,表示数组内容值为字符串

    const hj = ['okk', 'hj'] // const hj: string[]
    
    • 1

    下面会推断数组允许的值为字符串或数值

    const hj = ['ok', 'hj', 1] // const hj: (string | number)[]
    hj.push(2, 'hk') // 数组允许数值、字符串类型,所以编译通过
    hj.push(true) // 类型“boolean”的参数不能赋给类型“string | number”的参数
    
    • 1
    • 2
    • 3

    对象

    const hj = {
      name: 'hj',
      age: 20,
      status: true,
      otherInfo: {
          desc: '前端'
      },
      skill: ['Node.js', 'Webapck']
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    推断结果如下

    const hj: {
        name: string;
        age: number;
        status: boolean;
        otherInfo: {
            desc: string;
        };
        skill: string[];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    基本类型

    字符串

    字符串使用 string 来声明

    const hj: string = 'hj'
    
    • 1

    数值

    在 TS 中不区分整数与浮点数,都使用 number 来声明

    const hj:number = 100
    
    • 1

    布尔

    使用 boolean 来声明布尔类型

    const hj: boolean = true
    
    • 1

    数组

    下面是对数组值类型为字符串

    let hj2: string[] = []
    hj.push('hj', 'ok')
    
    • 1
    • 2

    下面是对数组值类型为字符串或数字

    let hj2: (string | number)[] = []
    hj2.push('hj', 2)
    
    • 1
    • 2

    下面是数据限制类型为字符串或 由数字组成的数组

    let hj3: string | number[] = []
    hj3 = 'hj'
    hj3 = [1, 2]
    
    • 1
    • 2
    • 3

    也可以使用泛型来声明数组(泛型的详细使用后面内容会介绍)

    let hj:Array<string> = []
    hj.push('hj', 'ok')
    
    • 1
    • 2

    Tuple 元组

    元组与数组类似,但元组要为每个值进行类型声明。

    数组只是定义了值的类型,并没有约束某个位置的值必须是什么类型,请看下例

    const arr: (number | string | boolean)[] = ['hj', 2030, true];
    
    arr[1] = 'hj' // 不会报错,可以将原来是数值的更改为字符串,这是数组允许的类型范围
    arr[10] = 'hj' // 不会报错,类型也是允许的
    console.log(arr);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    下面看使用元组来限制值的类型

    const hj: [string, number] = ['hj', 2030]
    hj[0] = true // 报错,第一个值必须是字符串
    
    • 1
    • 2

    对象

    下面是声明对象类型但不限制值类型

    let hj: object
    hj = {name: 'hj'}
    hj = {} // 使用字面量声明对象
    hj = [] // 数组是对象
    hj = function () {} // 函数是对象
    hj = Object.prototype // 原型对象
    hj = 'hj' // 报错,不能将类型“number”分配给类型“object”
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    限定对象值类型

    let hj: {name: string, year: number}
    
    hj = {name: 'hj', year: 2010}
    
    hj.a = 1 // error: 类型“{ name: string; year: number; }”上不存在属性“a”
    
    • 1
    • 2
    • 3
    • 4
    • 5

    属性后面跟上? 用来指定 url 为可选值,这样的属性是非必填项

    let hj: {name: string, year: number, url?: string}
    hj = {name: 'hj', year: 2010}
    
    • 1
    • 2

    any

    使用 any 指包含所有值的顶部类型,所以 any 不进行类型检查,等于关闭了 TS 对该变量的严格类型校验

    • 使用 any 类型等同于使用纯 JavaScript 的开发方式
    • any 类型是顶部类型,所有其他类型是他的子类型
    • 使用 any 类型将失去 typescript 静态类型的强制检测
    • 只有在描述一个根本不知道的类型时使用 any

    可以将 any 视为所有类型的组合表示

    let hj: string | boolean | number;
    hj = 'hj'
    
    let hj: any
    hj = 'hj'
    
    • 1
    • 2
    • 3
    • 4
    • 5

    下面是设置基本 any 的示例

    let hj: any;
    
    // 以下赋值不会报错
    hj = "hj";
    hj = 2010;
    hj = true;
    hj = [];
    hj = {};
    hj = class {};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在数组中使用 any 类型,可以设置任意类型的值

    let hj: any[] = []
    
    hj.push(1, '2', true, undefined, null, function() {})
    
    • 1
    • 2
    • 3

    为对象属性设置类型

    let hj:{
        name: any,
        year: any
    }
    // 以下设置都不会报错
    hj = {name:'hj', year: 2010}
    hj = {name: 2010, year: 'hj'}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    any 太过宽泛所以不建议使用,他会丢失 TS 的严格类型校验,比如下面的示例并不会报错

    let hj: any
    hj.get() // 不会报错
    
    • 1
    • 2

    下面再来看一下对象的使用 any 类型造成的问题

    class Hj {
        constructor() { }
        get = () => 'Hj'
    }
    
    const obj: any = new Hj;
    console.log(obj.get());
    
    obj.show() // 虽然obj原型链中没有show方法,但编译过程不会报错
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    所以上例需要指定正确的 Hj 类型,而不是使用 any

    ...
    const obj: Hj = new Hj;
    ...
    
    • 1
    • 2
    • 3

    能过设置 tsconfig.jsonnoImplicitAny = true 配置项,可以禁止隐含的 any 类型。以下代码会在编译时报错

    function sum(a, b) { // 参数“a”隐式具有“any”类型, 参数“b”隐式具有“any”类型
      return a + b
    }
    
    // 需改为如下
    
    function sum(a: number, b: number) {
      return a + b
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    unknown

    unknown 类型也是顶部类型这与 any 一样

    • unknown 用于表示未知的类型
    • 会进行 TS 的类型检查,any 不进行 TS 检查
    • 使用 unknown 类型时可以使用 as 类型断言来明确类型

    下面是 any 与 unknown 赋值上的区别,unknown 需要明确类型后赋值,any 则不需要

    let hk: any = 'hj'
    let hj: unknown = 'hj'
    
    let a: string = xj
    let b: string = hj // 报错: 'unknown'未知类型不能赋值给'string'类型
    
    // unknown 类型需要明确类型后赋值
    let c: string = hj as string
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    可以把任何值赋值给 unknown 类型,但在使用时需要指明类型

    let hj: unknown
    hj = 'houdunren'
    hj = 100
    
    //在使用时,TS不知道是什么类型,所以需要使用类型断言进行告之
    let c = hj as number + 20
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    使用 keyof 类型工具时 unknown 与 any 的区别

    type HJ<T> = { [P in keyof T]: string }
    
    // {[x: string]: string;}
    type HK = HJ<any>
    
    // 结果为{},因为 keyof unknow 是never,所以被忽略了
    type K = HJ<unknown>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    不同类型赋值时会报错

    let hj: string = 'hj'
    
    let a: number = hj as number // 类型 "string" 到类型 "number" 的转换可能是错误的,因为两种类型不能充分重叠。如果这是有意的,请先将表达式转换为 "unknown"
    
    • 1
    • 2
    • 3

    这里需要使用 unknown 做个中间层转换,将其先转换为 unknown 未知类型,再转换为 string 类型

    let hj: string = 'hj'
    
    let a: number = hj as unknown as number // 不会报错
    
    • 1
    • 2
    • 3

    any 与 unknown 在类型检查上是有区别的

    let hj: any
    hj.show(); // any不进行类型检查,所以不会报错
    
    let hk: unknown
    hk.show(); // unknown进行类型检查,unknown是未知类型所以报错
    
    • 1
    • 2
    • 3
    • 4
    • 5

    使用 any 类型 ts 不进行类型校验,所以在编译时不会报错,但执行编译后的 js 后会显示 NaN

    function get(val: any) {
      val = val * 100;
      return val
    }
    
    console.log(get('hj'));  // NaN
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    使用 unknown 类型时,结合 typeof 进行类型判断,根据不同类型使用不同逻辑

    function get(val: unknown) {
      if (typeof val === 'number') {
        return val * 100;
      }
      return 0
    }
    
    console.log(get(2)); // 200
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    void

    void 类型的值为 null 或 undefined,常用于对函数返回值类型定义

    • 严格模式(tsconfig.json 配置中关闭strict)时,void 值只能是 undefined(有关 TS 配置会在后面章节介绍)
    • 如果函数没有返回值请使用 void 类型,这会使用代码更易读,并可对不小心造成的函数返回内容进行校验
    • 你也可以将 void 理解为对返回 null 或 undefined 的函数返回值声明
    • TypeScript 中,不返回任何内容的 void 函数实际上返回的是 undefined

    void 类型的值可以是 null 或 undefined,但如果 TS 配置开启了 strictstrictNullChecks则不允许 void 为 null

    let hj: void
    
    hj = undefined
    hj = null
    
    • 1
    • 2
    • 3
    • 4

    void 不允许设置其他类型

    let hj: void
    hj = 'hj' // 不能将类型“string”分配给类型“void”
    
    • 1
    • 2

    TypeScript 中,不返回任何内容的 void 函数实际上返回的是 undefined

    function hj(): void {}
    
    console.log(hj()) // undefined
    
    • 1
    • 2
    • 3

    经过 void 限定后是不允许函数返回内容的,所以以下代码将报错

    function hj(): void{
        return 'hj' // 不能将类型“string”分配给类型“void”
    }
    
    • 1
    • 2
    • 3

    never

    never 是任何类型的子类型,可以赋值给任何类型,没有类型是 never 的子类型。

    never 类型的特点

    • never 没有任何子类型,所以任何类型都不可以赋值给 never
    • 函数抛出异常或无限循环时返回值是 never
    • 可以将每个类型理解为某类值的集合,比如 number 类型包含所有数字,但 never 类型没有任何值。
    function hj(): never{
    	throw new Error("出错了")
    }
    
    • 1
    • 2
    • 3

    never 是所有类型的子类型,可以分配给任何类型,所以下面类型为 string

    type HJ = never extends string ? string : boolean // string
    
    • 1

    其他类型不可以分配给 never 类型

    type HJ = string extends never ? string : boolean // boolean
    
    • 1

    never 是所有类型的子类型,所以下面实际类型是 string | number

    type HJ = never | string | number // string | number
    
    • 1

    null & undefined

    null 与 undefined 也是对变量类型,用于定义值为 null 或 undefined

    let hj: null = null
    let hk: undefined = undefined
    
    console.log(hj, hk); // null undefined
    
    • 1
    • 2
    • 3
    • 4

    下面是函数返回值的使用

    function getName(): string | null{
        return null
    }
    
    console.log(getName()); // null
    
    • 1
    • 2
    • 3
    • 4
    • 5

    当配置项启用 strictNullChecks 时,null 与 undefined 只能赋值给 void、null、undefined 类型

    let hj: string = undefined; // 配置strictNullChecks = true 时将报错
    
    • 1

    union 联合类型

    union 联合类型是多个类型的组合,使用 | 进行连接,| 类似于 javascript 中的 || 或运算符。

    下面是为变量声明字符串或数值类型

    let hj: string | number = 'hj'
    hj = 2010
    
    • 1
    • 2

    下面是为数组声明多种类型

    let hj: (string | number | boolean)[]  = []
    hj.push('hj', 2010, true)
    
    • 1
    • 2

    也可以使用泛型方式声明(泛型的详细使用后面内容会介绍)

    let hj: Array<string | number | boolean> = []
    hj.push('hj', 2010, true)
    
    • 1
    • 2

    函数

    函数定义

    下面是 TS 自动推断的函数类型

    let hj = () => 'hj' // let hj: () => string
    
    hj = '1' // 不能将类型“string”分配给类型“() => string”
    
    • 1
    • 2
    • 3

    使用 Function 来声明函数类型,注意是大写,这与 string/number/boolean 是有区别的

    let hk: Function = () => 'hk'
    
    hj = 1 // 不能将类型“number”分配给类型“Function”
    
    • 1
    • 2
    • 3

    参数类型

    通过对函数参数类型的声明,让函数更加稳定

    const hj: Function = (a: number, b: number) => a + b
    
    hj(1, 2) // 3
    
    • 1
    • 2
    • 3

    下面的函数没有声明函数参数类型,所以其是不稳定的

    const hj : Function = (a, b) => a + b
    
    hj('1', 2) // 12
    
    • 1
    • 2
    • 3

    可选参数可以通过 ? 来声明

    const hj: Function = (a: number, b: number, c?: number) => {
        c = c || 0
        return a + b + c
    }
    
    console.log(hj(1, 2)) // 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    如果想要设置默认值就不要设置可选参数?了,因为它们是互相矛盾的

    const hj: Function = (a: number, b: number, c: number = 0) => a + b + c
    
    console.log(hj(1, 2)) // 3
    
    • 1
    • 2
    • 3

    返回值类型

    下面函数的参数类型都是number,那么返回值类型也应当是number

    const hk = (a: number, b: number): number => a + b
    
    function hj (a: number, b: number): number {
        return a + b
    }
    
    const h = function (a: number, b: number): number {
        return a + b
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    下面函数的参数类型都是number,返回值类型设置为string显然编译会报错

    function hj (a: number, b: number): string {
        return a + b // 不能将类型“number”分配给类型“string”
    }
    
    • 1
    • 2
    • 3

    如果函数没有返回值你可以不写返回值类型,但我建议你写上 void,毕竟这样在函数第一行就可以看到返回值类型,并且这个函数也更加稳定

    const hj = (a: string) : void => console.log(a);
    
    • 1

    参数声明

    有时多个函数会用到相同的类型的参数,比如下面的示例

    let addUser = (user: { name: string; age: number }): void => {
      console.log('添加用户')
    }
    
    let updateUser = (user: { name: string; age: number }): void => {
      console.log('更新用户')
    }
    
    updateUser({ name: '后盾人', age: 18 })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    我们可以使用 type 对参数对象进行声明,通过这种复用的手段可以很好的优化代码

    // 使用 `type` 对参数对象进行声明
    type userType = { name: string; age: number }
    
    let addUser = (user: userType): void => {
      console.log('添加用户')
    }
    
    let updateUser = (user: userType): void => {
      console.log('更新用户')
    }
    
    updateUser({ name: 'hj', age: 18 })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    函数结构的定义

    对没有返回值函数结构的定义

    let hj: () => void // 定义函数结构
    
    hj = (): void => console.log('hj') // 实现函数
    
    • 1
    • 2
    • 3

    下例是对 hj 函数的定义

    • 函数定义中声明的变量 a,在具体实现函数是可以为任何名称
    let hj: (a: number, b: number) => number
    
    hj = (x: number, y: number): number => {
        return x + y
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    也可以在声明函数时就定义函数的结构

    let hj: (a: number, b: number) => number = (x: number, y: number): number => {
        return x + y;
    }
    
    console.log(hj(2, 3));
    
    • 1
    • 2
    • 3
    • 4
    • 5

    参数是对象结构的函数定义

    • 下例中的参数 u 不定义类型结构,TS 也是可以推断出来的
    let addUser: (user: { name: string, age: number }) => boolean;
    
    addUser = (u: { name: string, age: number }): boolean => {
        console.log('添加用户');
    
        return true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    上例中使用了重复的参数描述 { name: string, age: number } ,下面我们将参数对象使用 type 进行描述,就可以很好的优化代码

    type userType = { name: string, age: number }
    
    let addUser: (user: userType) => boolean;
    
    addUser = (u: userType): boolean => {
        console.log('添加用户');
    
        return true;
    }
    
    addUser({ name: 'hj', age: 12 })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    上面是将参数使用 type 进行了描述,我们也可以将函数结构使用 type 进行描述

    type userType = { name: string, age: number }
    
    type addUserFunc = (user: userType) => boolean;
    
    let addUser: addUserFunc = (u: userType): boolean => {
        console.log('添加用户');
    
        return true;
    }
    
    addUser({ name: 'hj', age: 12 })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    剩余参数

    下面的求合函数接收多个参数

    function sum(...args: any[]): number {
        return args.reduce((s, n) => s + n, 0);
    }
    
    console.log(sum(1, 2, 3, 4, 5));
    
    • 1
    • 2
    • 3
    • 4
    • 5

    下面通过第二个参数接收剩余参数,来实现数据追加的示例

    function push(arr: any[], ...args: any[]): any[] {
        arr.push(...args)
        return arr;
    }
    
    const hj: any[] = ['hj']
    
    console.log(push(hj, 'hk', 'hh')); // [ 'hj', 'hk', 'hh' ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8



    静待 第二章:枚举与断言

  • 相关阅读:
    Python的collections原来这么好用
    微信小程序 - WXML 模板语法 - 事件绑定
    在关系数据库中允许空值的一些缺点
    Wi-Blog 项目拆解(一):Maven项目的创建和常用Dependency配置
    并发编程基础底层原理学习(四)
    flutter系列之:做一个下载按钮的动画
    解决Nacos配置刷新问题: 如何启用配置刷新功能以及与`@RefreshScope`注解的关联问题
    Hotcoin Academy 市场洞察-2024年4月15日-21日
    SQL Server SSIS ETL job执行相关操作
    虚拟机作为master远程控制台式机中的机器人在仿真环境中进行slam地图构建与自主导航
  • 原文地址:https://blog.csdn.net/qq_41887214/article/details/125476037