[ts] Advanced: Basic Knowledge

Ref: TypeScript 2022 再入门

 

 

准备阶段


NPM for TS

  • npm 配置

支持 ts。

-----------------------------------------------
jeffrey@jeffrey-EnlargeDS:.../work$ npm init -y
Wrote to
/root/xiaoma_ts/xiaoma_ts_01-27/work/package.json: { "name": "work", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" } jeffrey@jeffrey-EnlargeDS:.../work$ ls package.json
--------------------------------------------------------------------- jeffrey@jeffrey-EnlargeDS:.../work$ npm install --save-dev typescript npm notice created a lockfile as package-lock.json. You should commit this file. npm WARN work@1.0.0 No description npm WARN work@1.0.0 No repository field. + typescript@5.0.4 added 1 package from 1 contributor and audited 1 package in 3.32s found 0 vulnerabilities ╭───────────────────────────────────────────────────────────────╮ │ │ │ New major version of npm available! 6.14.159.6.6 │ │ Changelog: https://github.com/npm/cli/releases/tag/v9.6.6 │ │ Run npm install -g npm to update! │ │ │ ╰───────────────────────────────────────────────────────────────╯ jeffrey@jeffrey-EnlargeDS:.../work$

 

  • 执行: 编译成 js

ts是开发时可见,运行时不可见。

jeffrey@jeffrey-EnlargeDS:.../work$ vim main.ts 
jeffrey@jeffrey-EnlargeDS:.../work$ ls
main.ts  node_modules  package.json  package-lock.json

---------------------------------------------------
jeffrey@jeffrey-EnlargeDS:.../work$ npx tsc main.ts
jeffrey@jeffrey-EnlargeDS:.../work$ ls
main.js  main.ts  node_modules  package.json  package-lock.json

 

    • tsconifg.json 配置文件

如果不想写 main.ts 这个路径,那就配置到tsconifg.json中。

命令:$tsc init  // 生成默认的配置文件

 {
     "compilerOptions": {
         "target": "es6",
         "module": "commonjs",
         "rootDir": "./src",
         "outDir": "./dist",
         "removeComments": true,
         "esModuleInterop": true,
         "forceConsistentCasingInFileNames": true,
         "strict": true,
         "skipLibCheck": true
     }
 }

命令:$npx tsc(执行),如下图。

Ref: https://www.typescriptlang.org/tsconfig

Ref: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html

 

 

webpack for TS

  • webpack Doc

Ref: www.webpack.js.org

Ref: Webpack 5 最热前端打包工具

webpack 是一个模块打包器。它的主要目标是 将JavaScript 文件打包在一起,打包后的文件用于在浏览器中使用

 

  • 1. 安装

09 使用webpack打包ts代码(1) <--- 这个比较好

https://www.youtube.com/playlist?list=PLmOn9nNkQxJGwOhSsQ5H9JTPmiXGmy8Zw 尚硅谷的这个ts课程可以作为参考,讲师貌似也不错。

执行:$npm i -D webpack webpack-cli typescript ts-loader

// packages.json

{ "name": "part3", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { // 之后这里配置 to support: npm build, npm start, 如下例子所示 "test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"start": "webpack serve --open chrome.exe" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "ts-loader": "^9.4.2", "typescript": "^5.0.4", "webpack": "^5.82.1", "webpack-cli": "^5.1.1" } }
    • 增强的 "scripts"

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "main": "clear && npx tsc && node dist/main.js",
    "tsmain": "clear && npx ts-node src/main.ts",
    "serve": "webpack serve --config webpack.config.js"
}

如上设置后,可以用ts的方式去执行。

$ npm run tsmain
$ npx ts-node src/main.ts

 

  • 2. 使 webpack 支持 ts编译

// webpack.config.js

const path = require('path') module.exports = { entry: "./src/index.ts" } module.exports = { entry: "./src/index.ts", output: { path: path.resolve(__dirname, 'dist'), filename: "bundle.js" environment: { arrowFunction: false // webpack支持箭头函数不太好,通过此设置搞定。 } }, mode: 'development', module: { rules:[ { // test 制定的是规则生效的文件 test:/\.ts$/, // 要使用的loader use: "ts-loader" // 要排除的文件 exclude: /mode-modules/ } ] } }

 

    • 增强

因为这里是ts,所以 js的模块引入如下机制,增强后才能支持。

resolve: {
    extensions: ['.ts', '.js']
}

 

    • 继续增强

如下的配置文件 ,enable了两个功能。

a) 如果需要自动准备一个 ./dist/index.html:npm i -D html-webpack-plugin

b) 打包时,自动清空dist中过去的文件。

const HTMLWebpackPlugin = require('html-webpack-plugin')
const {CleanWebpackPlugin} = require('clean-webpack-plugin') plugins: [ new CleanWebpackPlugin(), new HTMLWebpackPlugin( { // title: "this is one custom title." template: "./src/index.html" }), ]

 

最后开始打包:npm run build,会同时生成

--> ./dist/bundle.js

--> ./dist/index.html

 

    • 再次增强

为了支持旧浏览器 in bundle.js

虽然 tsconfig.json 中可设置;但是 bundle更强大,支持新语法到旧语法,新技术被支持。

 

首先需要安装这些包:npm i -D @babel/core @babel/preset-env babel-loader core-js

在webpack.config.js中,添加下述定制兼容老的浏览器。

module.exports = {
    ... ...
    module: {
        rules:[
            {
                test:/\.tx(x),
                use:[
                    // 配置 babel.
                    {
                        // 指定加载器.
                        loader: "babel-loader",
                        option: {
                            // 设置预定义的环境
                            presents: [
                                [
                                    // 指定环境的插件
                                    "@babel/preset-env",
                                    // 配置信息
                                    {
                                        // 要兼容的目标浏览器
                                        targets: {
                                            "chrome":"58",
                                            "ie":"11"
                                        },
                                        // 基于老版本的api构建的高级语法。
                                        "corejs": "3",
                                        // 使用corejs的方式 “usage" 表示按需加载
                                        "useBuiltIns": "usage"
                                    }
                                ]
                            ]
                        }
                    },
                    "ts-loader"
                ]
            }
        ]
    }
}
webpack.config.js

 

 

 

TS 语法


变量

旧Repo可作参考:https://github.com/komavideo/LearnTypeScript/tree/master

let myAge: number = 25
​
let myCareer: string = "sys engineer"
​
let isVIP: boolean = true
​
console.log(typeof isVIP)
​
// any类型让编译器忽略类型检测
let mylang:any = "typescript";
console.log("My Language is " + mylang);
mylang = 100;
console.log("My Language is " + mylang);
​
// 联合类型的使用
let mydata: string | boolean;

// 字典的使用 const mySite
= { name: "haha" url: "www..." } ​ console.log(mySite.name) ​ // --> 推荐的方式如下。 const mySite: { name: string, url: string, tags: string[] // <---- 数组的类型定义 } = { name: "haha", url: "www...", tags: ["IT", "AWS"] } for (const item of mySite.tags) { console.log("-", item) } ​ tags.push("new-item") ​

//------------------------------------------------------------------
// 定义数组
//------------------------------------------------------------------
let data:string[] = ['Java', 'Ruby', 'Kotlin', 'Dart']; console.log(data); console.log(data[0]); console.log(data[3]); console.log(data[4]); ​ // 追加赋值 data[4] = 'PHP'; console.log(data); console.log(data[4]); ​ // 越界赋值(ts支持) data[10] = 'Go'; console.log(data); console.log(data[10]);

// 相当于只定义了key,而没有value enum IAMRole { AdministratorAccess, AmazonDynamoDBFullAccess, AmaonS3FullAccess }

 字典的解构 destructure:

console.log("helo js.")

var myobj = {
    pname: "Curry",
    age: 33,
    height: 195,
    weight: 84
}
let { pname, age, weight } = myobj
console.log(pname, age, weight)

 

箭头函数

const add = (x: number, y: number): number => x+y;
const main = () => {
    add(1,2)
}

 

延展操作符

就是一个典型的reduce操作 of array。如下,箭头函数定义了reduce的细节。

const add = (...numbers: number[]) => {
    return numbers.reduce(
        (prev, current) => {
            return prev+current;    
        }, 0)  // 0 is init value.
}

作为数组中的一个元素。

const mylist = [1, 2, 3];

console.log(mylist)
console.log(...mylist)

const new_mylist = [...mylist, 4, 5, 6]
console.log(new_mylist)
// [1,2,3,4,5,6]

const new_mylist2 = [mylist, 4, 5, 6]
console.log(new_mylist2)
// [[1,2,3], 4, 5, 6]

 

作为函数参数。
const addXYZ = (...args) => {
    // args是个数组,这里反倒是“包裹”的效果。
    console.log(args)
    args.forEach(item => console.log(item));
}

addXYZ(1,2,3,4,5,6)

 

 

 

OOP


// constructor
class Site {
    constructor(pubic name: string, private url: string);
    
    sayhelo() {
        console.log(`Welcome ${this.name}`)
        console.log("->", this.url)
    }
}
  • 只读的变量

// readonly...
class Site {
    constructor(
        private readonly id: number,
        public name: string,
        private url: string 
    ) {}
    
    setId(newId: number) {
        this.id = newId;  // <-- error.
    }
}

 

继承

// super...
class DB {
    constructor(
        public name: string,
        public port: number,
        public dbtype: string,
    ) { }
    desc() {
        console.log(`${this.name}-${this.port}-${this.dbtype}`)  
    }
}

class RDB extends DB {
    constructor(
        public name: string,
        public port: number,
    ) {
        super(name, port, "RDB")        
    }
}

class NoSqlDB extends DB {
    constructor(
        public name: string,
        public port: number,
    ) {
        super(name, port, "NoSql")        
    }
}

const main = () => {
    const myDb = new DB("mysql", 3306, "RDB")
    myDb.desc()
const mySql
= new DB("mysql", 3306) mySql.desc()
const mongodb
= new DB("mongoDB", 27017) mongodb.desc() } main()

 

抽象类与接口类

链接:https://www.jianshu.com/p/28e3b4d61945

抽象类适合用来定义某个领域的固有属性,也就是本质,接口适合用来定义某个领域的扩展功能

当需要为一些类提供公共的实现代码时,应优先考虑抽象类。因为抽象类中的非抽象方法可以被子类继承下来,使实现功能的代码更简单。

当注重代码的扩展性跟可维护性时,应当优先采用接口。

① 接口与实现它的类之间可以不存在任何层次关系,接口可以实现毫不相关类的相同行为,比抽象类的使用更加方便灵活;

② 接口只关心对象之间的交互的方法,而不关心对象所对应的具体类。接口是程序之间的一个协议,比抽象类的使用更安全、清晰。一般使用接口的情况更多。 e.log("数据库通用类")

 

  • 抽象类

abstract class DB {
    // 构造函数
    constructor(
        public name: string,
        public port: number,
        public dbtype: string,
    ) { }
    
    desc() {
        console.log("数据库通用类")
    }
    
    abstract connect(): void;
}

 

  • 接口类

interface IDB {
    name: string;
    port: number;
    
    connect(): void;
}

class PostgreSqlDB implements IDB {
    constructor(public name: string, public port: number) {
    }
    connect(): void {
        console.log("链接到", this.name, this.port)
    }
}

 

定义类型 type (类似结构体)

type User = {
    name: string,
    age: number,
    weight: number,
}

type Role = {
    role: string,
    tel: string,
}

// 合并两个类型
type Staff = User & Role;

// ---------------------- const main
= () => {
let user1: User
= { name: "Koma", age: 25, weight: 70, } console.log(user1) // 实现一个员工 let staff: Staff = { name: "Koma", age: 25, weight: 70, role: "Admin", tel: "01-1234-5678" } console.log(staff) }

 

 

 

模块管理 - Namespace


简单的案例

// 这里定义
namespace
Utils {
// 定义并直接导出让大家使用。 export class DB { constructor( public name: string, public port: number, public dbtype: string, ) { } connect () { console.log(`${this.name}...`) } } } // 这里使用 namespace App { const main = () => { let db: Utils.DB = \ new Utils.DB("mysql", 3306, "RDS") db.connect() } main() }

 

一个落伍的文件引用

./src/Utils/DB.ts

namespace Utils {
    export class DB {
        // 构造函数
        constructor (
            public name: string,
            public port: number,
            public dbtype: string,
        ) { }
        // 数据库连接方法
        connect() {
            console.log(`${this.name}`)
        }
    }
}

 

./src/main.ts

这里告诉解析器,我们引用的类的文件的位置

/// <reference path = "Utils/DB.ts" />
// 以上一行是个必须的写法,看着都别扭
namespace App { const main
= () => { let db: Utils.DB = new Utils.DB("mysql", 3306, "RDS") db.connect() } main() }

 

然后,需要再修改下 tsconfig.json

{
    "compilerOptions": {
        // "module": "commonjs",
        "module": "amd",
        // Add this new line.
        "outFile": "./dist/main.js",
    }
}

执行命令:npm run main,所有的内容就会都打包到一个文件中:./dist/main.js

    • 参考

"模块JS"的一个例子: 

import * as util from './util.mjs'
console.log(util) console.log(util.add) console.log(util.SITENAME)

 

 

ES Modules

以下才是当前流行的写法,简洁。顺便恢复tsconfig.json原来的样子:commonjs 即可。

直接将 DB 倒进来 成为 ”可用“。

import { DB } from './Utils/DB'

// namespace App {
    const main = () => {
        let db: DB = new DB("mysql", 3306, "RDS")
        db.connect()
    }
    main()
// }

 

posted @ 2022-03-23 21:38  郝壹贰叁  阅读(38)  评论(0编辑  收藏  举报