学习typeScript (第三周 )

1.开发环境搭建
1.1 安装node地址:https://nodejs.org/zh-cn/
1.2 使用npm全局安装typescript window+ R => npm i -g typescript
1.3 使用tsc 对 typescript 进行编译成 js tsc xxx.ts
1.4 运行ts 可以全局安装 ts-node =>npm i -g ts-node
1.5 运行ts文件 ts-node xxx.ts
ts 可以编译任意版本的 js // 确保兼容
如果变量的声明和赋值是同时进行的(变量声明可以省略),TS可以自动对变量进行检测

let c = false
c = true
c === 123 // 报错

2.TS 的类型说明
2.1 声明变量为number 类型

let a :number = 1
a = '222' // 会报错,但是可以编译 js文件

2.2 声明变量为 String 类型

let a:string = '我是小仙女'

2.3 声明变量为 boolean类型

let a:boolean = true

2.4 为函数声明默认值并指定类型
在函数后面跟:number 是规定函数返回值的类型

function sum(a:number,b:number):number{
    return a+b
    return a + '2222'// 报错
}
let res = let res = sum(1,1) // 代码提示 res:number
console.log(sum(1,1)) // 传参多少都会报错

2.5 字面量进行类型声明 (联合类型)

 | 代表或的意思 a 的值只能是下面定义的 不能进行修改
let a :'小仙女' | '大帅哥'
 a = '小仙女'
 a = '大帅哥'
 let b :boolean | string | number
 b = false
 b = '小仙女'
 b = 1

2.6 any 表示任意类型 一个百年来设置any 后相当于对该变量关闭了ts 的类型检测 (不建议使用)
声明变量如果比指定类型,则ts解析器会自动判断变量的类型为any (隐式的any)

let b; // 要避免使用
let b :any // 要避免使用
b = 1
b = '小仙女'
b = false
注:any 值它可以赋值给任意变量
let s = string
s = b
console.log(c) // false

2.7 unknown 未知类型的值
unknown 实际上就是一个类型安全的any
unknown 类型的变量,不能直接赋值给其他变量
类型断言 语法:1 : 变量 as 类型 2.<类型> 变量

let b :unknown
b = 1
b = 'aaa'
b = false
let s : string
b = 'wwww'
s = b // 报错不能将类型 unknown 分配给 类型 string
// 解决办法1 
if (typeof b === 'string') {
    s = b
}
// 解决办法2  类型断言 可以用来告诉解析器变量的实际类型
s = b as string
s = <string> b

2.8 void 用来表示空 以函数为例 就表示没有返回值 空值 或 undefiend

 function fn() :void{
    return 123 // 报错
}

2.9 never 表示永远不会返回结果
3.0 Object 定义对象

 let a :object
 a = {}
 a = function name() {
 } 这种声明不常用 因为 在js 中 万物皆对象

{} 用来指定对象张包含那些属性
语法:{属性名:属性值,属性名:属性值}
在属性名后面加?,代表属性是可选的

let b: { name: string, age: number }
b = { name: '小仙女', age: 12 ,like:'男' } // 报错 因为在 b中没有声明 like 属性
let b: { name: string, age: number,like?:string } ? 代表可选 但是 不能 每一个参数都这样赋值
b = { name: '小仙女', age: 12  }
let b: { name: string, [prpName:string]:any } // 代表name 必有属性 后面都是可选的属性
b = {name:'122',age:12,num:'1111',like:undefined}

3.1 定义 函数
设置函数结构的类型说明 语法:(形参:类型) =>返回值

let b: (a: number, b: number) => number
b = function (n: number, n2: number) {
    return n + n2
}

3.2 数组 array
表示方式 1 类型[] 2.Array<类型>

let s :string[]
s = ['1','2','3']
let n :number[]
n = [12,3,4]
let a :Array<string>
a = ['1','1']
let f :Array<number> // => any 尽量不要用
f = [1,2,3]

3.3 元组 tuple 就是固定长度的数组

let b :[string,number]
b = ['1',3] // 不能多不能少

注意:函数中的泛型

我认为泛型 就是 泛指类型 通常用 T 代替
// 泛型 函数中的 泛型
function join<T>(first:T,second:T) {
    console.log(first,second);
    
}
join<string>('nsskjs','2') // 指定类型
join<number>(1,2)
两个 参数
function join<T,N>(first:T,second:N) {
    console.log(first,second);
    
}
join<string,number>('nsskjs',2)

泛型中数组的使用

泛型中数组的使用 2种 写法

function addnum(params:T[]) {
console.log(params);
}
addnum(['1','2'])
// 第二种 
function addnum<T>(params:Array<T>) {
    console.log(params);
    
}
addnum<string>(['1','2'])
类中使用泛型
class SlectGirl{
    constructor(private girls:string[]){}
    getGril(index:number):string {
        return this.girls[index]
    }
}
const slectGirl = new SlectGirl <string> (['小红','小丽','小静'])
console.log(slectGirl.getGril(1)); // 小丽
泛型中的继承
interface girl {
    name:string;
    age:number
}
class GirlName <T extends girl>{
    constructor(private girl: T[]) {}
    getAge(index:number) : string | number {
        return this.girl[index].name + '年龄是' + this.girl[index].age
    }
}
const Girl = new GirlName (
    [
        {name:'小红',age:15},
        {name:'小丽',age:16},
        {name:'小静',age:17}
    ]
)
console.log(Girl.getAge(2));

先声明一个接口,让泛型进行继承,就必须要求传递肥肉参数要有 name 属性,getAge 返回参数就是接口参数格式

// 泛型的约束 extends

class GirlName <T extends string | number>{ // 约束泛型 必须是 string 或者 number
    constructor(private girl: T[]) {}
    getAge(index:number) : T {
        return this.girl[index]
    }
}
const Girl = new GirlName <string>(
    [
        '小红','小丽','小静'
    ]
)
console.log(Girl.getAge(2));


3.4 枚举 就是列车 某一个值 可能存在的情况

enum Status {
    like = 1,
    age,
    name,
}
function getStatus(status:any) {
    if (status === Status.like) {
        return '我喜欢ni'
    } else if (status === Status.age) {
        return '我年龄18岁'
    } else if (status === Status.name) {
        return '我的名字是关关'
    }
}
console.log(getStatus(0)); // 我喜欢ni
console.log(getStatus(Status.age)); // 我年龄18岁
console.log(Status.like); // 0 默认从0 开始 不想从0 开始需要 将上面的赋值 改成 1 后 下标就从 1开始了

3.5 补充 & 要同时满足

let b :{name:string} & {age:number}
b = {name:"小仙女",age:12}

类型的别名

type myType = 1 | 2 | 3 | 4 | 5
let k : myType
let j : myType

3.TS 编译选项

  1. tsc XXX.ts -w // -w 代表watch 但是编译会有时间间隔
    只能监视一个文件,文件多,需要监视多文件,不利于开发
  2. 新建一个 tsconfig.json 在执行 tsc -w 进行所有文件监听
    编译选项
    {
      /*
          tsconfig.json 是ts 编译器的配置文件,ts编译器可以根据它的信息碎代码进行编译
          根目录的
          “include” : 用来指定哪些ts 需要被编译
          路径:** 表示任意目录 
                * 表示任意文件
          "exclude" : 不需要被编译的文件目录
          默认值:["node_modules","bower_components","jspm_packages"]
          extends:定义被继承的配置文件
          eg: 'extends':'./config/base'
          files: 指定被编译文件的列表,只有需要编译的文件少时才会用到
          'files':["a.ts","b.ts"]
      */
      "include": [
          "./src/**/*"
      ],
        // 重要
          "compilerOptions": {
          // target 用来指定ts 被编译为 ES 的版本 ESnext 最新版本
          // 可以编译 为es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'esnext
          "target": "es5",
          "module": "es2015",
          //module可选 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015', 'es2020', 'esnext'
          // "lib": ['']
          // 项目中 用到的库
          // 可选 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'webworker.iterable', 'scripthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.string', 'es2017.intl', 'es2017.typedarrays', 'es2018.asyncgenerator', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', 'es2018.regexp', 'es2019.array', 'es2019.object', 'es2019.string', 'es2019.symbol', 'es2020.bigint', 'es2020.promise', 'es2020.sharedmemory', 'es2020.string', 'es2020.symbol.wellknown', 'es2020.intl', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable', 'esnext.intl', 'esnext.bigint', 'esnext.string', 'esnext.promise', 'esnext.weakref'.
          "outDir": "./dist",
          // 编译后的当文件的目录
          // "outFile": "./dist/index.js",
          // 全局作用域的代码会合并到同一个文件中
          "allowJs": true,
          // 是否对 js 文件进行编译 默认是 false
          "checkJs": true,
          // 是否检测js 代码是否符合语法规范 默认是false
          "removeComments": true,
          // 是否移除注释 编译后
          "noEmit": false,
          // 不生成编译文件
          "noEmitOnError": false,
          // 编译有错误的时候 不生成编译后文件
          "strict": false,
          // 所有严格格式下总开关 如果设置 true 下面可以不写
          "alwaysStrict": false,
          // 用来设置编译后的文件是否使用严格模式,默认false
          "noImplicitAny": true,
          // 不允许 隐式any
          "noImplicitThis": true,
          // 不允许不明确的 this
          "strictNullChecks": true
          // 严格下检查 空值 下面的例子 box 不存在 可以做判断  if (box !== null) { 方法}
          // let box = document.getElementById('#box')
          //box.addEventListener('click',function () {
          //   alert(1111)
          //})
      }

4.使用webpack 打包typescript
41. 创建一个文件夹 在目录下 npm init -y 初始化文件
42. 然后 cnpm i -D webpack webpack-cli typescript ts-loader (ts-loader ts加载器,将webpack和ts整合) (typescript核心包) (webpack-cli 命令行工具) (webpack核心代码) (-D安装开发依赖 全写 --save dev)
43. 在跟目录新建一个 webpack.config.js
// webpack 中得所有配置文件都要写在这里 module.exports

module.exports = {
    1.首先要引入一个node path 用来连接路径 
    const path =  require ('path')
  const HtmlWebpackPlugin = require('html-webpack-plugin')
    2.指定入口文件
    entry: 'src/index.ts',
    3.指定出口文件
    output:{
    // 指定打包出口文件夹
    path: path.resolve(__dirname,dist)
    // 打包后得文件
    filename: 'bundle.js',
    // 告诉webpack 不要使用 箭头函数
        environment:{
            arrowFunction:false
        }
    },
   // 指定webpack打包时要使用得模块
   module:{
        // 指定要加载得规则
     rules:[
           // 指定规则生效得文件
             test:/\.ts$/,
        // 使用losder
        use:'ts-loader',
       // 不使用得文件 
       exclude: /node-modules/
     ]
    },
      // 配置webpack插件
    plugins:[
        new HtmlWebpackPlugin({
            template:'./src/index.html' //位置可以任意
        })
    ],
     // 用来告诉文件 哪些文件可以当作模块引用   用来设置引用模块
     resolve: {
        extensions: ['.ts', '.js']
    }
}

上述如果想在 网页中浏览得话,需要在根目录新建html 使用script 标签引入 ,但是这样如果有100 个ts 文件怎么办?,这时候就需要安装一个webpack 插件,项目中有多少js css 等等,进行自动引入,则需要安装 cnpm i -D html-webpack-plugin 作用帮助我们自动生成 html 文件

plugins:[
        new HtmlWebpackPlugin(
          {
            //  title:'小仙女文件'
            template:'./src/index.html' //位置可以任意
          }
        )
    ]

引入后 执行npm run build 这时候就会发现 dist 文件下 多出一个index.html 查看html 会发现script标签自动引入了bundle.js
相关改 html title的话 上述,但是设置是实现了自定义,但是网页比较复杂,不能一个一个去自定义,所有这时候需要一个模板,在配置中添加一个模板,并指定文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>我是小仙女</title>
</head>
<body>
    <div>我是一个王爷</div>
</body>
</html>
// 执行 npm run build 查看 dist -> index.html 
<!doctype html>
  <html lang="en"><head><meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>我是小仙女</title><script defer="defer" src="bundle.js"></script>
     </head>
   <body><div>我是一个王爷</div></body>
   </html>
 想要打开文件 vs code 右键直接在浏览器中打开运行,但是我们有一个更加灵活的方式,我们的浏览器和服务器是有联系的,当我们修改代码,浏览器自动刷新更新内容。需要安装 插件 cnpm i -D webpack-dev-server

需要在 package.json 进行配置 "start": "webpack serve --open chrome.exe" 意思为
意思为 打开webpack 服务 并且打开谷歌浏览器 npm start
但是现在我们每次编译,其实是不会删去原来 dist 文件下的文件内容的,如果生成新的文件,是在原来的基础上进行替换的,这样回带来一些不必要的问题,所以需要每次编译前,先把 dist 目录下的文件内容先清空。在把新文件放进去,这样确保,每次构建,都是最新的文件,避免存在旧文件的情况。cnpm i -D clean-webpack-plugin
和index.ts 同级新建一个 data.ts 在data.ta 暴露一个常量,在index.ts 引入并使用,在运行 build 会发出报错
图片说明
是因为 data.ts 是一个模块,拓展名是 .ts, 在webpack中是不知道,.ts 可以当作模块使用的,所以需要告诉,webpack 哪些文件能当作模块被使用,及引用的,和 plugins 同级 resolve :{extensions:['.ts','.js']},如上展示 在bundlr.js 就可以看到
上述初步的配置是完成,但是在bundlr.js会发现 是以箭头函数运行,一些浏览器是不兼容的,下面重点学习loader,低浏览器兼容。但是这时候你会问,webpack.config.js 中的 target不是可以指定ts代码编译的版本么,但是有些功能 ts 里面是不具备的,target 里面的转换只是进行简单的语法转换,但是对一些复杂的功能,比如es6 promise 通过语法的转换,是转不过去的。就需要工具去解决。
5.babel 学习
babel,新语法转换旧语法,还可以新的技术,新的类等,在浏览器中不支持的,通过一些方式让他进行支持。
安装依赖 cnpm i -D @babel/core @babel/preset-env babel-loader core.js (core 核心工具 ) (preset-env 预先设置的开发环境 比如 谷歌 火狐等开发环境) (babel-loader 将babel 和 webpack 结合的工具) (core.js 模拟js 运行环境)
开始改 webpack.config.js 在model 模块进行修改,因为都是对 .ts 文件生效,所以不需要在增加一个规则,之前只用一个 ts-loader 加载器,现在需要两个加载器 增加一个 babel 所以把 use 改成 [],加载器的执行顺序谁在后面先执行谁。所以需要把 ts-loader 放在后面,需要把 ts 转 js 在用babel 转低版本的 js。

rules: [
            {
                test: /\.ts$/,
                // 指定规则生效的文件
                use: [
                    {
                        loader: "babel-loader,
                       //设置配置项
                      // options 里面配置了 我这边 出错了,具体什么原因 不太了解
                        options: {
                            presets: [
                                [
                                    // 配置指定环境插件
                                    "@babel/preset-env",
                                    // 配置信息
                                    {
                                        // 要兼容的目标浏览器
                                        targets: {
                                            "chrome": "86", // 高版本
                                                                     "chrome": "56", // 高版本
                                                                "ie":"11"
                                        },
                                        //指定corejs的版本 usage 按需加载
                                        "corejs": "3",
                                        "useBuiltIns": "usage"
                                    }
                                ]
                            ]
                        }
                    }, // 复杂版 可以进行配置 
                      //谁写在后面谁先执行 执行顺序从后往前执行 所以需要将ts转 js 在将 新js 转 旧版 js
                    'babel-loader' // 不需要配置 可以这样写
                    'ts-loader',
                ],
                // 要使用loader 
                exclude: / node - modules/
            }
        ]

ts 文件 没有用babel

const obj = {
    name:'孙悟空',
    age:19
}

obj.age = 80
console.log(obj);

打包后
图片说明
*ts 文件 用babel 发现打包后还是 const 是因为上面写的targets 兼容浏览器是 86 版本的 是支持 const *
*打包后是 var *
在 ts 中简单 console.log(promise)
接下来说 core.js ,比如说 ts 文件中使用 promise 但是 ie11 不支持特殊类的,即使用了 babel 但是老的版本还是不能使用,这时候就需要 core.js ,这时候 引入 core.js 中的 promise ,供 ie11 使用,这时候你就会问,那是不是ie 11就可以使用了。这是为啥啊?我们打开 ie 看
图片说明
看到 bundel.js 第4个字符出错。发现第4个字符是箭头函数,自调用的形式。创建了一个作用域,防止代码之前互相干扰。即使最简单代码打包后也是 箭头函数,也会报错。
但是在 ts 文件中写箭头函数,打包后,也是会编译成普通的函数。
图片说明
为什么最外层打包后编译比成普通函数呢?这个箭头函数不是我们手写的,是webpack自动生成的,没有经过babel,可能是webpack 已经不想兼容 ie 了,这时候我们怎么办呢?所以我们的告诉 webpack 我们需要兼容老的浏览器。 需要在

output: {
        // 指定打包出口文件夹
        path: path.resolve(__dirname, 'dist'),
        // 打包后文件的文件
        filename: 'bundle.js',
        // 告诉webpack 不要使用 箭头函数 重要
        environment:{
            arrowFunction:false
        }
    },

图片说明
图片说明

全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务