Typescript 笔记

一. 类型申明

  1. 常见类型
    string、number、boolean

    let a: string = '111'
    let b: number = 222
    let c: boolean = false
    
    // 函数参数类型,返回值类型
    function sum(a: number, b: number): number {
        return a + b
    }
    
    console.log(sum(1, 2));
    
  2. 联合类型
    使用 | 连接多个类型

    let a: string | boolean
    a = '111'
    a = false
    
    // 直接使用字面量进行声明,类似常量
    let b: 10
    // b= 11 报错
    let c: 10 | '10'
    c = '10'
    
  3. any 类型
    any 表示任意类型

    // any 表示任意类型,一个变量设置类型为 any 后相当于对该变量关闭了 TS 的类型检测,不建议使用
    // let d:any
    
    // 声明变量如果不指定类型,则 TS 解析器会自动判断变量的类型为 any (隐式的 any)
    let d
    d = 1
    d = '1'
    d = true
    
  4. unknown 类型
    表示未知类型的值

    // d 是 any 隐式类型
    let d
    d = '1'
    
    // unknown 类型
    let e: unknown
    e = 1
    e = true
    e = '1'
    
    let s: string
    
    // any 可以赋值给任何变量,不会报错;unknown 一个安全类型的 any,不能直接赋值给变量
    // s= d 不错报
    // s= e 报错
    
  5. 类型断言
    告诉解析器变量的实际类型

    /*
    语法:
        变量 as 类型
        <类型>变量
    */
    s = e as string
    s = <string>e
    
  6. void 和 never 类型

    // void:表示空 undefined ,以函数为例,表示没有返回值的函数
    function fn1(): void {
    
    }
    
    // never:表示永远不会返回结果
    function fn2(): never {
        throw new Error('报错了!')
    }
    
  7. object 类型
    对象类型

    // {} 用来指定对象中可以包含哪些属性
    // 语法:{属性名:属性值,属性名:属性值....}
    // 在属性名后面加上 ?, 表示属性是可选的
    let f: { name: string, age?: number }
    // f = { name: '11' }
    f = { name: '11', age: 12 }
    
    // [propName: string]: any 表示任意类型的属性
    let g: { name: string, [propName: string]: any }
    g = { name: '11', age: 18, gender: '男' }
    
    // 设置函数结构的类型申明
    // 语法:(形参:类型,形参:类型...) => 类型
    let u: (a: number, b: number) => number
    u = function (n1: number, n2: number) {
        return 10
    }
    
  8. Array类型
    数组类型

    // 语法:
    //      类型[]
    //      Array<类型>
    // string[] 表示字符串数组
    let i: string[]
    i = ['1', '2']
    
    // number[] 表示数字数组
    let p: number[]
    p = [1, 2]
    
    let y: Array<string>
    y = ['1']
    
  9. 元组
    固定长度的数组

    // 语法:[类型,类型,类型]
    let r: [string, number]
    r = ['1', 2]
    
  10. enum
    枚举

    // 如果不指定数值,则从 0 开始
    enum Gender {
        Male = 1,
        FeMale = 0
    }
    let w: { name: string, gender: Gender }
    w = {
        name: '11',
        gender: Gender.Male
    }
    console.log(w.gender);
    
  11. & 和 别名

    // & 表示同时
    let j: { name: string } & { age: number }
    j = { name: '1', age: 18 }
    
    // 类型别名
    type myType = 1 | 2 | 3
    let k: myType
    let z: myType
    
    z = 2
    

二. tsconfig.json

tsconfig.json 包含 TypeScript 编译的相关配置,通过更改编译配置项,我们可以让 TypeScript 编译出 ES6、ES5、node 的代码。

重要字段

files - 设置要编译的文件的名称;
include - 设置需要进行编译的文件,支持路径模式匹配;
exclude - 设置无需进行编译的文件,支持路径模式匹配;
compilerOptions - 设置与编译流程相关的选项。

compilerOptions 选项

{
  "compilerOptions": {
  
    /* 基本选项 */
    "target": "es5",                       // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES6'/'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'
    "module": "commonjs",                  // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015'
    "lib": [],                             // 指定要包含在编译中的库文件
    "allowJs": true,                       // 允许编译 javascript 文件
    "checkJs": true,                       // 报告 javascript 文件中的错误
    "jsx": "preserve",                     // 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react'
    "declaration": true,                   // 生成相应的 '.d.ts' 文件
    "sourceMap": true,                     // 生成相应的 '.map' 文件
    "outFile": "./",                       // 将输出文件合并为一个文件
    "outDir": "./",                        // 指定输出目录
    "rootDir": "./",                       // 用来控制输出目录结构 --outDir.
    "removeComments": true,                // 删除编译后的所有的注释
    "noEmit": true,                        // 不生成输出文件
    "importHelpers": true,                 // 从 tslib 导入辅助工具函数
    "isolatedModules": true,               // 将每个文件做为单独的模块 (与 'ts.transpileModule' 类似).

    /* 严格的类型检查选项 */
    "strict": true,                        // 启用所有严格类型检查选项
    "noImplicitAny": true,                 // 在表达式和声明上有隐含的 any类型时报错
    "strictNullChecks": true,              // 启用严格的 null 检查
    "noImplicitThis": true,                // 当 this 表达式值为 any 类型的时候,生成一个错误
    "alwaysStrict": true,                  // 以严格模式检查每个模块,并在每个文件里加入 'use strict'

    /* 额外的检查 */
    "noUnusedLocals": true,                // 有未使用的变量时,抛出错误
    "noUnusedParameters": true,            // 有未使用的参数时,抛出错误
    "noImplicitReturns": true,             // 并不是所有函数里的代码都有返回值时,抛出错误
    "noFallthroughCasesInSwitch": true,    // 报告 switch 语句的 fallthrough 错误。(即,不允许 switch 的 case 语句贯穿)

    /* 模块解析选项 */
    "moduleResolution": "node",            // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)
    "baseUrl": "./",                       // 用于解析非相对模块名称的基目录
    "paths": {},                           // 模块名到基于 baseUrl 的路径映射的列表
    "rootDirs": [],                        // 根文件夹列表,其组合内容表示项目运行时的结构内容
    "typeRoots": [],                       // 包含类型声明的文件列表
    "types": [],                           // 需要包含的类型声明文件名列表
    "allowSyntheticDefaultImports": true,  // 允许从没有设置默认导出的模块中默认导入。

    /* Source Map Options */
    "sourceRoot": "./",                    // 指定调试器应该找到 TypeScript 文件而不是源文件的位置
    "mapRoot": "./",                       // 指定调试器应该找到映射文件而不是生成文件的位置
    "inlineSourceMap": true,               // 生成单个 soucemaps 文件,而不是将 sourcemaps 生成不同的文件
    "inlineSources": true,                 // 将代码与 sourcemaps 生成到一个文件中,要求同时设置了 --inlineSourceMap 或 --sourceMap 属性

    /* 其他选项 */
    "experimentalDecorators": true,        // 启用装饰器
    "emitDecoratorMetadata": true          // 为装饰器提供元数据的支持
  }
}

三. ts 结合 webpack

  1. 新建文件夹,执行

    npm init -y
    
  2. 安装依赖

    npm i webpack webpack-cli typescript ts-loader -D
    
  3. 根目录下新建 webpack.config.js

    const path = require('path')
    
    module.exports = {
        "entry": "./src/index.ts",
        "output": {
            path: path.resolve(__dirname, 'dist'),
            filename: 'bundle.js'
        },
        "module": {
            "rules": [
                {
                    test: /\.ts$/,
                    use: 'ts-loader',
                    exclude: /node_modules/
                }
            ]
        }
    }
    
  4. 根目录下新建 tsconfig.json

    {
        "compilerOptions": {
            "module": "ES2015",
            "target": "ES2015",
            "strict": true
        }
    }
    
  5. 在 package.json 中添加 build 命令

    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "build": "webpack"
      },
    

四. 类

属性和方法

class Person {

    // 实例属性:实例化后使用
    name: string = "孙悟空"
    age: number = 18

    // 静态属性:可以直接通过类使用
    static gender: string = 'male'

    // 只读属性:无法修改
    readonly height: number = 178

    // 方法:分为实例方法和静态方法
    sayHello() {
        console.log('hello');
    }
    static sayHi() {
        console.log('Hi');
    }
}

const per = new Person()

console.log(per);
console.log(per.name);
console.log(Person.gender);
// per.height = 188
per.sayHello()
Person.sayHi()

五. 构造函数和this

constructor 被称为构造函数,会在对象创建时调用

class Person {

    name: string;
    age: number;

    // constructor 被称为构造函数,会在对象创建时调用
    constructor(name: string, age: number) {
        // 在实例方法中,this 就代表当前的实例
        // 在构造函数中当前对象就是当前新建的那个对象
        // 可以通过 this 向新建的对象中添加属性
        this.name = name
        this.age = age
    }

    sayHello() {
        // 在方法中可以通过 this 来表示当前调用方法的对象
        console.log(this);
    }

}

const per = new Person('孙悟空', 18)
const per2 = new Person('孙悟空2', 182)

// console.log(per);
// console.log(per2);

per2.sayHello()

六. 继承

使用继承后,子类将会拥有父类所有的属性和方法

class Person {

    name: string;
    age: number;

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

    sayHello() {
        console.log(this);
    }

}

// 此时,Person 被称为父类,Dog 被称为子类
// 使用继承后,子类将会拥有父类所有的属性和方法
// 如果希望在子类中添加一些父类中没有的属性或方法,直接加载子类中即可
// 重写:如果在子类中添加了和父类相同的方法,则子类中的方法会覆盖父类的方法,这种方式叫
class Zs extends Person {
    sayHi() {
        console.log("hi");
    }
}

class Ls extends Person {
    sayHello() {
        console.log('hello');
    }
}


let zs = new Zs('zhangsan', 18)
zs.sayHello()
zs.sayHi()
let ls = new Ls('lisi', 28)
ls.sayHello()

七. super

如果在子类中写了构造函数,在子类构造函数中必须使用 super 调用父类构造函数

class Person {

    name: string;

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

    sayHello() {
        console.log(this);
    }

}

class Zs extends Person {
    // 如果在子类中写了构造函数,在子类构造函数中必须使用 super 调用父类构造函数
    age: number;
    constructor(name: string, age: number) {
        super(name)
        this.age = age
    }
    sayHi() {
        console.log("hi");
    }
}

let zs = new Zs('张三', 18)
zs.sayHello()
zs.sayHi()

八. 抽象类

以 abstract 开头

// 抽象类:
// 以 abstract 开头
// 只能被继承,不能用来创建对象
abstract class Person {

    name: string;

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

    // 抽象方法:
    // 使用 abstract 开头,没有方法体
    // 只能定义在抽象类中,子类必须重写该方法
    abstract sayHello(): void

}

class Zs extends Person {
    sayHello() {
        console.log('hello');
    }
    sayHi() {
        console.log("hi");
    }
}

let zs = new Zs('张三')
zs.sayHello()
zs.sayHi()

九. 接口

可以在定义类的时候去限制类的结构

// 接口:
// 可以在定义类的时候去限制类的结构
// 所有的属性都不能有实际的值
// 只定义对象的结构,而不考虑实际值
// 在接口中所有的方法都是抽象方法

interface Person {
    name: string;
    sayHello(): void
}

// 定义类时,可以使类去实现一个接口,使类满足接口的要求
class Zs implements Person {
    name: string
    constructor(name: string) {
        this.name = name
    }
    sayHello() {
        console.log('hello');
    }
}

let zs = new Zs('张三')
zs.sayHello()

十. 属性的封装

public、private、protected

class Person {

    // public 可以在任意位置访问(修改) 默认值
    // private 只能在类内部访问(修改)
    // protected 受保护的属性,只能在类和子类中访问(修改)
    // 通过在类中添加方法使得私有属性可以被外部访问和修改

    private _name: string
    private _age: number

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

    // TS 中设置 getter 和 setter,他们被叫做存取器
    // getter 方法用来读取属性
    // setter 方法用来设置属性
    get name() {
        return this._name
    }

    set name(value) {
        this._name = value
    }
}

class C {
    // 可以直接将属性定义在构造函数中
    constructor(public name: string, public age: number) {
    }
}

let Ls = new C('lisi', 38)
console.log(Ls);

let Zs = new Person('zhangsan', 18)
Zs.name = 'lisi'
console.log(Zs.name);

十一. 泛型

在定义函数时,如果遇到类型不明确可以使用泛型

// 在定义函数时,如果遇到类型不明确可以使用泛型

function fn<T>(a: T): T {
    return a
}

// 可以直接调用具有泛型的函数
let result = fn(10) // 不指定泛型,TS 自动推断
let result2 = fn<string>('hello') // 指定泛型类型
console.log(result, result2);

// 泛型可以同时指定多个
function fn2<T, K>(a: T, b: K): T {
    console.log(b);
    return a
}

fn2<number, string>(12, 'hello2222')

// T extends Inter 表示泛型 T 必须是 Inter 实现类(子类)
interface Inter {
    length: number
}

function fn3<T extends Inter>(a: T): number {
    return a.length
}

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

const mc = new myClass('孙悟空')
console.log(mc);

参考链接:
https://juejin.cn/post/7018805943710253086?share_token=c4029c41-9cc7-4e39-9e2d-c57b6617d2d8#comment
https://www.bilibili.com/video/BV1Xy4y1v7S2/?p=10&spm_id_from=pageDriver&vd_source=4e82b49ed21a06688f8dfee0c73a125f

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值