TypeScript学习笔记

最大的特点: 类型声明(type)

把js变成静态类型的语言

从技术上讲TypeScript就是具有静态类型的 JavaScript 。

静态类型更有利于构建大型应用

静态类型在编译时就能发现类型上的错误

项目越大、越复杂,优势越明显。

和javascript的区别:

1.这使开发人员能够快速检测错误并调试应用程序

2.js的超集,所有的js代码都可以在ts中使用

3.TypeScript 通过类型注解提供编译时的静态类型检查。

4.TypeScript 中的数据要求带有明确的类型,JavaScript不要求。

5.TypeScript 中引入了模块的概念,可以把声明、数据、函数和类封装在模块中。

 

 

 

类型 

类型例子描述
number 1, -33, 2.5 任意数字
string 'hi', "hi", hi 任意字符串
boolean true、false 布尔值true或false
字面量 其本身 限制变量的值就是该字面量的值
any * 任意类型
unknown * 类型安全的any
void 空值(undefined) 没有值(或undefined)
never 没有值 不能是任何值
object {name:'孙悟空'} 任意的JS对象
array [1,2,3] 任意JS数组
tuple [4,5] 元组,TS新增类型,固定长度数组
enum enum{A, B} 枚举,TS中新增类型

 

1. 安装

cnpm install -g typescript
//or yarn global add typescript

2.检查版本

tsc -v

常用编译选项

 --noEmitOnError  报错时不生成输出文件

 

 

严格模式

  开启以下默认选项

{
    "noImplicitAny": true,
    "strictNullChecks": true, 
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "alwaysStrict": true
}

 

 

ts代码有错误,但是符合js规范的,依然可以编译,为了推广。

js中的函数是不考虑参数的类型和个数的

function sum(a,b) {
  return a + b ;
}
console.log('让我康康sum1',sum(123,'456')) // '123456' 没有提示,也没有报错,一不小心就算成了一个字符串,这个结果如果用到别的地方,可能导致一连串的错误,而且这个错误不好找。

ts 类型声明 可以用在变量、参数和返回值上

function tsSum(a:number,b:number): number {// 函数返回值的类型
  return a + b;
}

声明多个类型

let d: boolean | string; //  可以使用|来连接多个类型(联合类型)

关闭TS的类型检测(和JS一样了,不建议使用)

let f: any; // 显式any, 关闭TS的类型检测
let f; // 隐式any,一样关闭了TS的类型检测
x = f // f赋值给x后,会关闭x的类型检测

unknown

let e: unknown;
// unknown 实际上是一个类型安全的any
// unknown 类型的变量,不能直接赋值给其他变量 要先判断类型
if( typeof e === 'string'){
  d = e
}
// 类型断言, 可以用来告诉解析器变量的实际类型
d = e as boolean; //语法1
d = <boolean>e; //语法2

void

// void 用来表示空,以函数为例,就表示没有返回值的函数。
function fn(): void {
  
}

never

// 永远不会返回结果,用来检查报错的
function fn2(): never {
  throw new Error("报错了!");
}

 object  限制对象不是为了限制他是不是一个对象,而是限制对象中的属性。

// 这样写就只能传一个类型为string的参数
let g: {name:string};
g = {name:'小子'};
// 属性可写可不写
let h: {name:string,age?:number}
// 可以传任意个数,任意类型的参数
let i: {name:string,[propName: string]:any}
i = {name:'小子',age:20,sex:'male'}

设置函数结构的类型声明

// 规定函数的传参类型以及返回类型
let sum2: (a: number, b: number) => number;

array

// 定义字符串数组
let j: string[];

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

let k: [string,number];

enum 枚举

enum Gender {
  male = 0,
  female = 1
}
console.log('让我康康male的值',Gender.male) // 0

&两个条件都要满足

let m: {name:string} & {age:number}

类型的别名

// 类型的别名
type myType = 1 | 2 | 3 | string | boolean;
let n: myType; // n 为1 2 3 字符串 布尔值都可以

 

编译

ts编译器 tsconfig.json( 直接在终端输入 tsc即可)

{
    // include 用来指定哪些ts文件需要被编译
    "include": [
        // 一个*是任意文件,两个*是任意目录
        "./src/**/*"
    ],
    // 排除掉不想被编译的文件,默认值 ["node_modules","bower_components","jspm_packages"]
    "exclude": ["./src/abc/*"],
    // 指定被编译文件的列表,只有需要编译的文件少时才会用到
    "files": ["src/code.ts", "src/abc/code.ts"],
    // 编译器的选项
    "compilerOptions": {
        // 指定TS被编译的ES版本
        "target": "ES2015",
        // 指定要使用的模块化规范
        "module": "AMD",
        // lib 用来指定项目中要使用的库,一般是在浏览器环境下使用的话,不需要去修改lib配置
        "lib": ["DOM", "ES2015"],
        // 指定编译后的文件所在的目录
        "outDir": "./dist",
        // 合并编译后的文件,设置outFile后,所有的全局作用域中的代码会合并到同一个文件中(很少用)
        "outFile": "./dist/merge.js",
        // 是否对js文件进行编译
        "allowJs": false,
        // 检查js代码是否符合语法规范
        "checkJs": false,
        // 是否去除注释
        "removeComments": true,
        // 不生成编译后的文件,一般是用来检查语法
        "noEmit": false,
        // 有错误时不生成编译后的文件
        "noEmitOnError": true,
        // 所有严格检查总开关 建议打开
        "strict": true,
        // 设置编译后的文件是否开启严格模式
        "alwaysStrict": false,
        // 不允许隐式any类型
        "noImplicitAny": true,
        // 不允许不明确类型的this
        "noImplicitThis": true,
        // 严格的检查空值
        "strictNullChecks": false
    }
}

 

ts和webpack结合

需要依赖

webpack webpack-cli typescript ts-loader html-webpack-plugin webpack-dev-server

webpack.config.js配置

// 引入一个包
const path = require('path');
// 引入html插件
const HTMLWebpackPlugin = require('html-webpack-plugin');
// 引入clean插件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

// webpack中的所有的配置信息都应该写在module.exports中
module.exports = {

    // 指定入口文件
    entry: "./src/index.ts",

    // 指定打包文件所在目录
    output: {
        // 指定打包文件的目录
        path: path.resolve(__dirname, 'dist'),
        // 打包后文件的文件
        filename: "bundle.js",

        // 告诉webpack不使用箭头
        environment:{
            arrowFunction: false
        }
    },

    // 指定webpack打包时要使用模块
    module: {
        // 指定要加载的规则
        rules: [
            {
                // test指定的是规则生效的文件
                test: /\.ts$/,
                // 要使用的loader
                use: [
                     // 配置babel
                     {
                         // 指定加载器
                         loader:"babel-loader",
                         // 设置babel
                         options: {
                             // 设置预定义的环境
                             presets:[
                                 [
                                     // 指定环境的插件
                                     "@babel/preset-env",
                                     // 配置信息
                                     {
                                         // 要兼容的目标浏览器
                                         targets:{
                                             "chrome":"58",
                                             "ie":"11"
                                         },
                                         // 指定corejs的版本
                                         "corejs":"3",
                                         // 使用corejs的方式 "usage" 表示按需加载
                                         "useBuiltIns":"usage"
                                     }
                                 ]
                             ]
                         }
                     },
                    'ts-loader'
                ],
                // 要排除的文件
                exclude: /node-modules/
            }
        ]
    },

    // 配置Webpack插件
    plugins: [
        new CleanWebpackPlugin(),
        new HTMLWebpackPlugin({
            // title: "这是一个自定义的title"
            template: "./src/index.html"
        }),
    ],

    // 用来设置引用模块 可以解决import {m} from 'm.ts'; 无法打包问题 
    resolve: {
        extensions: ['.ts', '.js']
    }

};

打包后

 还是有一些浏览器无法识别,所以要引用插件 

@babel/core @babel/preset-env babel-loader core-js 

 引入less  

less less-loader

 引入postcss

postcss  postcss-loader  postcss-preset-env

 处理css

css-loader  style-loader

1.Autoprefixer 自动获取浏览器的流行度和能够支持的属性,并根据这些数据帮你自动为 CSS 规则添加前缀

2.CSS MODULES 能让你永远不用担心命名太大众化而造成冲突,只要用最有意义的名字就行了。

 

Class 类

使用class关键字来定义一个类,主要包含两个部分:属性和方法。

直接定义的属性是实例属性,需要通过对象的实例去访问
使用static开头的属性是静态属性(类属性),可以直接通过类去访问
class Person{
  name:string = '亚瑟';
  age:number = 18;
  // 属性前使用static关键字可以定义类属性(静态属性)
  static gender:string = 'male'
}
// per就是实例
const per = new Person()
// per.age 就是实例属性 
// 类属性或者叫静态属性
// Person.age  // 不存在
Person.gender // 存在

可以自定义的类

class Dog {
  name:string;
  age:number;
  // constructor 被称为构造函数 构造函数会在对象创建时调用
  constructor(name:string,age:number) {
    // 在实例方法中,this就表示当前的实例, 谁调用它,this就是谁 比如 const dog1 = new Dog('小黑',3)  this.name就是小黑
    // 在构造函数中,当前对象就是当前新建的那个对象
    // 可以通过this向新建的对象中添加属性
    this.name = name;
    this.age = age;
  }
  bark(){
    alert('汪汪汪')
  }
}

const dog = new Dog('花花',3)

类的继承

class Animal {
  name:string;
  age:number;
  // constructor 被称为构造函数 构造函数会在对象创建时调用
  constructor(name:string,age:number) {
    // 在实例方法中,this就表示当前的实例, 谁调用它,this就是谁 比如 const dog1 = new Dog('小黑',3)  this.name就是小黑
    // 在构造函数中,当前对象就是当前新建的那个对象
    // 可以通过this向新建的对象中添加属性
    // 子类中的方法,可以覆盖父类中的方法
    this.name = name;
    this.age = age;
  }
  sayHello(){
    alert('未知动物')
  }
}
class Cat extends Animal{
  sayHello(){
    alert('我是'+ this.name)
  }
};
const cat = new Cat('小花',3)
cat.sayHello()

在类的方法中,super表示当前类的父类

子类(派生类)中,对要添加属性,就要对属性进行初始化表达式,并且在构造函数中赋值

子类如果要使用构造函数,那么要先调用父类的构造函数,不然会覆盖父类的构造函数(报错)

class Bird extends Animal {
  gender: string; // 新属性
  constructor(name:string,age:number,gender:string){
    super(name,age);
    this.gender = gender;
  }
}

抽象类 以abstract开头的类

// 抽象类和其他类区别不大,只是不能用来创建对象
// 抽象类就是专门用来被继承的类
abstract class fruits {
  name:string;
  constructor(name:string){
    this.name = name
  }
  // 抽象方法使用abstract开头,没有方法体
  // 抽象方法只能定义在抽象类中,子类必须对抽象方法进行重写
  abstract sayHello():void;
}

接口 用interface开头

和类型声明的区别: 1.接口可以在定义类的时候去限制类的结构 2.类型声明不能重复声明同一个 ,而接口可以重复,最后的结果就是把所有重复的里面的属性和方法加在一起

  // 接口用来定义一个类结构,和一个类中应该包含哪些属性和方法
  // 同时接口也可以当成类型声明去使用
 // 接口中所有的属性都不能有实际的值,只定义对象的结构
// 所有方法都是抽象方法
  interface myInterface { name: string; age: number; } const obj: myInterface = { name:'小明', age:18 } // 类型声明 type myType = { name: string; age: number; };

 和抽象类的区别: 1.抽象类可以定义抽象方法,也可以定义普通方法。接口只能有抽象方法 2. 抽象类用extens继承,接口用implement继承。

 

类属性的封装

 class Person {
        // public 修饰的属性可以在任意位置访问(修改)默认值
        public _name: string;
        // 私有属性,只能在类内部进行修改
        private _age: number;
        constructor(name: string, age: number) {
            this._name = name;
            this._age = age;
        }
        // 定义方法,用来获取name属性
        getName(){
            return this._name;
        }
        
        // 定义方法,用来设置name属性
        setName(value: string){
          // 提高代码容错率 可以在里面进行判断
          if(value.length > 1){
            this._name = value;
          }
        }
    }
    const per = new Person('诸葛亮', 18);
    per._name = '周公瑾';
    per._age = 20; // 私有属性 无法访问

直接将属性定义在构造函数中

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

类型断言

 

 

解决方法:

this.element = document.getElementById('snake')!;

加一个! 是not null 的断言操作符,不执行运行时检查,告诉编译器只需要知道这个东西

2.第二个问题

 

 报错

解决方法:

this.head = document.querySelector('#snake > div') as HTMLElement;

 

 insertAdjacentText方法与 insertAdjacentHTML方法

insertAdjacentHTML(param1,param2)  

第一个参数

1.     beforeBegin: 插入到标签开始前

2.     afterBegin:插入到标签开始标记之后

3.     beforeEnd:插入到标签结束标记前

4.     afterEnd:插入到标签结束标记后

<!-- beforebegin -->
<p>
<!-- afterbegin -->
foo
<!-- beforeend -->
</p>
<!-- afterend -->

第二个参数 : HTMLElement

 与innerHTML的区别:

 

 

 innerHTML是替换容器内的元素,而这个是往特定位置去添加元素

 

insertAdjacentText(param1,param2)

第一个参数一样,第二个参数是字符串

 

 

 

开始

1.init json文件

tsc --init

把   "outDir": "./",   打开 , 改为    "outDir": "./js", 

  

 

 2.监听ts

vscode 终端 => 运行任务

 

 

 

 3.数据类型

布尔类型 boolean

let flag:boolean = true;
数字类型 number
let num:number = 666;
 字符串类型 string
let str:string = 'This is TypeScript';
// 数组 方式1  
let arr:number[] = [1,2,3]; 
let arr2:object[] = [ {a:10}, {a:10}];

// 数组 方式2
let arr3:Array<number> = [1,2,3];
let arr4:Array<object> = [{a:1},{a:2}];
 
//数组 方式3
let arr33:any[] = ['123',true,66]
console.log('arr33',arr33)
 
元组类型(tuple) 指定数组中每一项值的类型
let arr5:[string,number,object,boolean] = ['123',3.14,{},false];
枚举类型 enum
enum Color {red,blue,orange};
let r:Color = Color.red; //0
 
// 如果没有定义值,那么默认值就是索引
如果你返回的是 0 不好理解是什么意思,但是你返回一个Color.red  就知道0代表的是红色
 
 
void表示方法没有返回任何类型
function run():void {
  console.log('66')
}
run();
 
// 返回/打印数字
function crnumber(type:number) {
  console.log('type',type)
  return type
}
crnumber(123)

never类型 是其他类型(null和undefined)的子类型 只能被never类型赋值,表示不会出现的值 , 几乎用不着

var a:never;
a = (()=>{
  // 抛出一个错误
  throw new Error("错误");
})()
 
// 3.1 函数的定义
// 函数声明法
function fn1():number {
  return 123
}
// 匿名函数
var fn2 = function ():string {
    return 'es50'
}
alert(fn2());
 
 
// 函数配置可选参数
function select(params:string,params2?:number) {
  console.log('配置可选参数',params,params2)
}
select('arg1')
 
//3.4 剩余参数

function sum(...array:number[]):number {
  let sum = 0;
  for (let index = 0; index < array.length; index++) {
    console.log('array[index]',array[index])
    sum +=  array[index]
  }
  return sum
}
let asr = [1,2,3,4]
alert(sum(...asr))
 
// 3.5 函数重载
function done(number:number):number;
function done(string:string):string;
function done(params:any):any {
  if (typeof params === 'string') {
    return '我叫' + params;
  }else if(typeof params === 'number'){
    return '年龄' + params;
  }
}
alert(done('张三'))
  //  ES5中的类, 可以在构造函数/原型链中 添加属性/方法;
  function Person() {
    this.name = '张三';
    this.age = 20;
    this.run = function () {
      alert(this.name + '在运动')
    }
  }
  // 静态方法
  Person.getInfo = function(name){
    alert(name + '是静态方法')
  }
  Person.prototype.sex = '男';
  // 实例方法
  Person.prototype.work = function(){
    alert(this.name + '在工作');
  }
  var p = new Person()
  p.run();
  p.work();
  console.log('p',p.sex)
  Person.getInfo('小李子')
  // Dog类 继承Person类
  function Dog() {
    Person.call(this) // 对象冒充实现继承
  }
  var d = new Dog();
  // d.work()  //   对象冒充只能继承构造函数的属性和方法 , 不能继承原型链方法和属性  Uncaught TypeError: d.work is not a function 
  console.log('d',d)
 
 // 对象冒充 + 原型链继承  可以继承原型链方法和属性, 还有构造函数的属性和方法
<script>
  //  ES5中的类, 可以在构造函数/原型链中 添加属性/方法;
  function Person(name,age) {
    this.name = name;
    this.age = age;
    this.run = function () {
      alert(this.name + '在运动')
    }
  }
  // 静态方法
  Person.getInfo = function(name){
    alert(name + '是静态方法')
  }

  Person.prototype.sex = '';
  // 实例方法
  Person.prototype.work = function(){
    alert(this.name + '在工作');
  }

  // Dog类 继承Person类

  function Dog(name,age) {
    Person.call(this,name,age) // 对象冒充实现继承 实例化子类可以给父类传参
  }
  //原型链继承
  Dog.prototype = new Person();
  var d = new Dog('花花',1);
  // d.work()  //   对象冒充不能继承原型链方法和属性  Uncaught TypeError: d.work is not a function 
d.run();
d.work()
</script>

 

// 类
var Animal = /** @class */ (function () {
    function Animal(t) {
        this.type = t;
    }
    Animal.prototype.run = function () {
        alert(this.type + '动物');
    };
    return Animal;
}());
var a = new Animal('哺乳');
a.run();

 

 
 
 
 
posted @ 2020-11-22 12:15  一路向北√  阅读(183)  评论(0编辑  收藏  举报

web应用开发&研究 -

业精于勤而荒于嬉。

工作,使我快乐。


Font Awesome | Respond.js | Bootstrap中文网