草庐IT

TypeScript学习笔记(一)

如果皮卡会coding 2023-04-07 原文

TS学习笔记

文章目录

一. 环境搭建

  1. 安装Node.js
  2. npm i -g typescript
  3. 创建ts文件test.ts,编译:tsc test.ts

二. 基本类型

1. 类型声明

语法:

let 变量:类型;
let 变量:类型=;
function fn(参数:类型,参数:类型):类型{}

实例:

let myStr: string = "123";
let myNum: number;

console.log(myStr);
myNum = 100;
console.log(myNum);

输出:

var str = "123";//默认编译为ES3版本的JS代码
var num;
console.log(str);
num = 100;
console.log(num);

如果变量的声明和赋值是同时进行的,TS可以自动对变量进行类型检测。

let c = false;
c = 123;//error

如果不需要写明类型就能自动判断,那么我们前面写明的类型限制会显得很鸡肋,反正写不写都一个样。

但是,我们常需要做的类型限制不仅仅只是变量,或者说对变量的限制需求没有那么高,真正高的是函数:

function sum(a,b){
    return a+b;
}

如果不做类型检测,若传入的是123以及"456",则不会报错,且输出为“123456”。若结果用到别的地方,则会导致一连串的错误。

function sum(a:number,b:number):number{
    return a+b;
}
sum("123",456);//类型“string”的参数不能赋给类型“number”的参数。
sum(123,456,789);//应有 2 个参数,但获得 3 个。
let result = sum(1,2);//悬浮result:let result: number

2. 基本类型

类型例子描述
number1, -33, 2.5任意数字
string‘hi’, “hi”, hi任意字符串
booleantrue、false布尔值true或false
字面量其本身限制变量的值就是该字面量的值
any*任意类型
unknown*类型安全的any
void空值(undefined)没有值(或undefined)
never没有值不能是任何值
object{name:‘孙悟空’}任意的JS对象
array[1,2,3]任意JS数组
tuple[4,5]元素,TS新增类型,固定长度数组
enumenum{A, B}枚举,TS中新增类型
  • 可以使用字面量进行类型声明
let a:10;//相当于常量
a = 10;//√
a = 11;//不能将类型“11”分配给类型“10”

也可以使用 | 连接多个类型(联合类型)

let b: "male" | "female";
b = "male";
b = "female";
b = "hello"; //不能将类型“"hllo"”分配给类型“"male" | "female"”。

let c: boolean | string;
c = true;
c = "hello";
  • any表示的是任意类型,相当于对该变量关闭了TS的类型检测。
// 显示any
let d:any;
d = 10;
d = "hello";
d = true;
// 隐式any
let dd;
dd = 10;
dd = "hello";
  • unknown表示未知类型(也可以赋值任意值,但是是类型安全的any):
let e:unknown;
e = 10;
e =  "hello";

区别:

let s:string;
s = d;//d是any,可以赋值给任意类型
s = e; //e是unkonwn,虽然上面赋值了“hello”,但是类型不匹配。
		//不能将类型“unknown”分配给类型“string”。

类型断言:告诉解析器的实际类型。

//(告诉编译器,它就是字符串)
s = e as string;
  • void:用来表示空,没有返回值的函数。
function fn():void{
    //return null;
    //return undefined;
    // no return 
}
  • never:表示永远不会返回结果。连undefined都不返回。
function fn2():never{
    throw new Error('报错了!')
}
  • object:表一个JS对象
let a:object;
a = {};
a = function(){};//万物皆对象,函数也是对象

{}可以用来指定对象包含哪些属性,属性名后接?,表示属性是可选的。

let b:{name:string,age?:number};
b = {name:'皮卡丘',age:2};
//但是不能额外新增其他的属性
b = {name:'孙悟空',skill:'七十二变'};//error
//不能将类型“{ name: string; skill: string; }”分配给类型“{ name: string; age?: number; }”。
//对象文字可以只指定已知属性,并且“skill”不在类型“{ name: string; age?: number; }”中。

[propName:String]:any可以表示任意类型的属性。propName可以是任意的内容。

let b:{name:string,[xx:string]:any};
b = {name:'孙悟空',skills:'七十二变'};//√
  • 函数结构的类型声明: (形参:类型,形参:类型)=>返回值
let d:(a:number,b:number)=>number;
  • 数组声明:类型[]Array<类型>
//字符串数组
let strArr:string[];
strArr = ['1','a','c'];
// 数字数组
let numArr:Array[number];
numArr = [1,2,50];

TS除了保留原有的JS类型之外,还额外新增了两种类型:tuple,enum

  • 元组tuple:固定长度的数组。语法:[类型,类型,类型]
let h:[string,string];
h = ['hello'];//error 
h = ['hello','123'];
h = ['hello',123];//error
h = ['hello','123','456'];//error
  • 枚举enum:

问题:下面的0和1,别人可能不知道1表示男还是女?

let i:{name:string,gender:0|1};
i={
    name:'孙悟空',
    gender:1 //'male'
}

使用枚举解决:

enum Gender {
    Male = 0,
    Female = 1
}
let i:{name:string,gender:Gender};
i={
    name:'皮卡丘',
    gender:Gender.Male
}
console.log(i.gender === Gender.Male);

&表示同时具有:

let j:{name:string}&{age:number}
j = {name:'皮卡丘',age:1};
let nonsene :{number & string}//毫无意义

type表示类型别名:遇到特别长的声明可以使用这个。

type myType = 1|2|3|4|5
let j:myType
let k:myType
j = 2;
k = 6;//error

三. 编译选项

总不能每次都是手动通过tsc xxx.ts进行编译成js文件吧?

  1. 编译器自动监视ts文件 -w:(watch)监视
tsc test.ts -w
  1. tsconfig.json:ts编译器的配置文件。文档:https://aka.ms/tsconfig.json

初始化:tsc -init

  • include:指定编译的文件目录
  • exclude:定义需要排除的文件
  • extends:定义被继承的配置文件
  • files:定义编译的文件列表
  • compilerOptions:编译器的选项
    • target:指定ts编译的目标版本。(如果不清楚可填的值,可以填一个错误的,看报错信息)
      • ‘es3’, ‘es5’, ‘es6’, ‘es2015’, ‘es2016’, ‘es2017’, ‘es2018’, ‘es2019’, ‘es2020’, ‘es2021’, ‘es2022’, ‘esnext’
    • module:指定要使用的模块化的规范。
      • ‘none’, ‘commonjs’, ‘amd’, ‘system’, ‘umd’, ‘es6’, ‘es2015’, ‘es2020’, ‘es2022’, ‘esnext’, ‘node12’, ‘nodenext’
    • lib:用来指定项目中要使用的库
      • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NoK3Ksdf-1647695725935)(C:\Users\艺\AppData\Roaming\Typora\typora-user-images\image-20220313150616510.png)]
    • outDir:指定编译后的文件所处目录。
      • “./dist”
    • outFile:将代码合并为一个文件。只有amd和system模式(module)支持该模式。不适合模块化。
    • allowJs:是否对JS文件进行编译,默认是false
      • true | false
    • checkJs:是否检查JS代码是否符合语法规范。默认是false。
      • true:若修改为true,则会在js文件里面出现语法检查。
    • removeComments:是否移除注释
    • noEmit:不生成编译后的文件。
    • noEmitOnError:当有错误的时候,不生成编译的文件。
    • 。。。

四. Webpack + TS

(一)基础配置

1. 配置依赖

cnpm i -D webpack webpack-cli typescript 
cnpm i -D html-webpack-plugin ts-loader
cnpm i -D webpack-dev-server
  • webpack脚手架:webpack,webpack-cli
    • ts-loader:加载TS文件内容
    • html-webpack-plugin:生成模板html,自动引入依赖
    • webpack-dev-server:即时更新
  • TS环境:typescript

2. webpack.config.js

新建webpack.config.js,配置如下:

const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
// const {CleanWebpackPlugin} = require('clean-webpack-plugin');
module.exports = {
    // 入口
    entry: "./src/index.ts",
    // 输出
    output:{
        path:path.resolve(__dirname,'dist'),
        filename:'bundle2.js',
        clean:true,
    },
    mode:'development',
    // 打包使用模块
    module:{
        //指定加载规则
        rules:[
            {
                test:/\.ts$/,
                use:'ts-loader',
                //排除文件
                exclude:/node-modules/
            }
        ]
    },
    plugins:[
        // new CleanWebpackPlugin(),
        new HTMLWebpackPlugin({
            // title:'LearningTs',
            template:'./src/index.html'
        }),
    ],
    // 用来设置引用模块
    resolve:{
        extensions:['.ts','.js']
    }
}

3. tsconfig.json

创建tsconfig.json文件,用于指定ts编译后的内容

{
  "compilerOptions": {
    "target": "es2015",
    "module": "es2015", 
    "esModuleInterop": true,     
    "forceConsistentCasingInFileNames": true,   
    "strict": false,
    "skipLibCheck": true
  }
}

4. 构建指令配置

在package.json中修改script配置,增加build指令以及start指令:

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

此时,通过npm run build即可看到最简单的构建产物。

(二)清除旧的打包产物

  • 方式一:引入插件
  1. 安装:cnpm i -D clean-webpack-plugin

  2. 引入config

    const {CleanWebpackPlugin} = require('clean-webpack-plugin');
    
  3. 注册plugin

    plugins:[ new CleanWebpackPlugin(), ]
    
  • 方式二:直接在output中增加clean:true的配置项。

五. class

0. 基础使用

回顾并在原本的js-class中体验ts-class的用法。

class Person{
    //定义实例对象
    name: string = '小智';
    
    //static:定义类属性(静态属性)
    static age: number = 18;
    
    //readonly 表示一个只读属性
    static readonly skill: string = "eat";
    
    //定义方法,前置static就是类方法
    sayHello(){
        console.log("Hello");
    }
}

1. 构造函数&this

我们通过constructor构造函数以及this指向当前对象的实例。

class 皮卡丘{
    name:string;
    power:number;
    kind:string;
    constructor(name:string,power:number,kind:string){
        this.name = name;
        this.power = power;
        this.kind = kind;
    }
    bark(){
        alert("皮卡皮卡");
    }
}
let pikaqiu = new 皮卡丘('YY的皮卡丘',100,'electricity');
pikaqiu.bark();

2. 继承

还可以通过extends实现继承。可以在类前面加sealed关键字禁止继承。扩展点:OCP原则。

//父类
class 宝可梦{
    name:string;//昵称
    power:number;//力量
    kind:string;//类别
    constructor(name:string,power:number,kind:string){
        this.name = name;
        this.power = power;
        this.kind = kind;
    }
    bark(){
        alert("宝可梦在叫~");
    }
}

//子类
class 比雕 extends 宝可梦{
    //可以不写,但是如果在子类中写了构造函数,则必须通过super调用父类的构造函数
    constructor(name:string,power:number){
   		super(name,power,'flight');     
    }
    fly(){
        console.log(`${this.name}在飞~`);
    }
    //方法重写
    bark(){
        console.log("渣渣~喳喳~");
    }
}

3. 抽象

  • 抽象类

    上面的宝可梦是一个抽象的概念,我们可以创建比雕,但是不能直接创建宝可梦。所以我们通过abstract关键字来声明这是一个抽象类。

  • 抽象方法

    不同的宝可梦叫声不一样,所以不能直接写出宝可梦的bark具体实现。需要声明它是抽象方法。

abstract class 宝可梦{
    //抽象方法只能定义在抽象类,且子类必须对其进行重写。
    abstract bark():void;
}

4. 接口

接口是抽象的最高境界,抽到只剩下灵魂了~~

  1. 接口只定义对象的结构,而不考虑实际值。

    • 所有的属性都不能有实际的值。

    • 所有的方法都是抽象方法。

  2. 定义类时,可以使类去实现一个接口。

type myType{
	name:string;
	sayHello(){
        //...
    }
}
interface myInterface{
    name: string;
    sayHello():void;
}    
class MyClass implements myInterface{
    name: string;
    sayHello(){
        console.log("大家好");
    }
}

5. 属性封装

TS可以在属性前添加属性的修饰符,确保数据更加得安全。

  • public:公有的,修饰的属性可以在任意位置访问修改默认值。(默认修饰符)
  • private:私有属性,只能在类的内部进行访问。通过getter和settter可以被外部访问。

问题:为什么需要设置私有属性,然后再设置getter和setter呢?这不是多此一举吗?

理解:当一个类的属性可以被任意访问的时候,容易埋下隐患。通过getter和setter可以判断修改的值是否有效。

情景:比如宝可梦的力量power需要为正数。后续进行战斗,对方宝可梦的体力基于己方宝可梦的力量值进行扣除。若某处直接将其设置为负数,则会给对方宝可梦增加体力。如果通过setter呢?

(function(){
    class 皮卡丘{
        public name:string;
        private power:number;
        constructor(name:string,power:number){
            this.name = name;
            this.power = power;
        }
        getPower(){
            return this.power;
        }
        setPower(newPower:number){
            if(newPower < 0 || newPower > 100 ) return 'error';
            this.power = newPower;
        }
        //当然,也有语法糖
        get name(){
            return this.name;
        }
        set name(value:string){
            //judge is Valid ,then 
            this.name = value;
        }
    }
})();

除了privatepublic之外,还有protected修饰符。仅限当前类以及子类访问。

class A{
    protected num : number;
    constructor(num:number){
        this.num = num;
    }
}
class B extends A{
    test(){
        console.log(this.num);
    }
}

我们可以直接将属性定义在构造函数中

class C{
    constructor(public name:string,private age:number){}
}
const c = new C ('xxx',18);

6. 泛型

一个多元方程中的未知数x,只有代入其他具体的值,才能推断出它来。

问题:如果不确定输入的类型,但是要限制输出的类型和输入的类型一样,咋办?

function fn(a:any):any{
    return a;
}

👆这样子OK吗?当然不行~

function fn<T>(a:T):T{
    return a;
}
fn(10);//自动判断 a是number
fn<string>("123");//手动指定类型

泛型:只有在函数调用的时候,才确定具体的类型。

//多举两个例子
// 泛型可以同时指定多个
function fn2<T,K>(a:T,b:K):T{
    return a;
}
// 下面指定泛型必须通过Inter实现类
interface Inter{
    length : number;
}
function fn3<T extends Inter>(a:T):number{
    return a.length;
}

有关TypeScript学习笔记(一)的更多相关文章

  1. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  2. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  3. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

  4. ruby - 我正在学习编程并选择了 Ruby。我应该升级到 Ruby 1.9 吗? - 2

    我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or

  5. ruby - 我如何学习 ruby​​ 的正则表达式? - 2

    如何学习ruby​​的正则表达式?(对于假人) 最佳答案 http://www.rubular.com/在Ruby中使用正则表达式时是一个很棒的工具,因为它可以立即将结果可视化。 关于ruby-我如何学习ruby​​的正则表达式?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/1881231/

  6. 深度学习12. CNN经典网络 VGG16 - 2

    深度学习12.CNN经典网络VGG16一、简介1.VGG来源2.VGG分类3.不同模型的参数数量4.3x3卷积核的好处5.关于学习率调度6.批归一化二、VGG16层分析1.层划分2.参数展开过程图解3.参数传递示例4.VGG16各层参数数量三、代码分析1.VGG16模型定义2.训练3.测试一、简介1.VGG来源VGG(VisualGeometryGroup)是一个视觉几何组在2014年提出的深度卷积神经网络架构。VGG在2014年ImageNet图像分类竞赛亚军,定位竞赛冠军;VGG网络采用连续的小卷积核(3x3)和池化层构建深度神经网络,网络深度可以达到16层或19层,其中VGG16和VGG

  7. 机器学习——时间序列ARIMA模型(四):自相关函数ACF和偏自相关函数PACF用于判断ARIMA模型中p、q参数取值 - 2

    文章目录1、自相关函数ACF2、偏自相关函数PACF3、ARIMA(p,d,q)的阶数判断4、代码实现1、引入所需依赖2、数据读取与处理3、一阶差分与绘图4、ACF5、PACF1、自相关函数ACF自相关函数反映了同一序列在不同时序的取值之间的相关性。公式:ACF(k)=ρk=Cov(yt,yt−k)Var(yt)ACF(k)=\rho_{k}=\frac{Cov(y_{t},y_{t-k})}{Var(y_{t})}ACF(k)=ρk​=Var(yt​)Cov(yt​,yt−k​)​其中分子用于求协方差矩阵,分母用于计算样本方差。求出的ACF值为[-1,1]。但对于一个平稳的AR模型,求出其滞

  8. Unity Shader 学习笔记(5)Shader变体、Shader属性定义技巧、自定义材质面板 - 2

    写在之前Shader变体、Shader属性定义技巧、自定义材质面板,这三个知识点任何一个单拿出来都是一套知识体系,不能一概而论,本文章目的在于将学习和实际工作中遇见的问题进行总结,类似于网络笔记之用,方便后续回顾查看,如有以偏概全、不祥不尽之处,还望海涵。1、Shader变体先看一段代码......Properties{ [KeywordEnum(on,off)]USL_USE_COL("IsUseColorMixTex?",int)=0 [Toggle(IS_RED_ON)]_IsRed("IsRed?",int)=0}......//中间省略,后续会有完整代码 #pragmamulti_c

  9. Tcl脚本入门笔记详解(一) - 2

    TCL脚本语言简介•TCL(ToolCommandLanguage)是一种解释执行的脚本语言(ScriptingLanguage),它提供了通用的编程能力:支持变量、过程和控制结构;同时TCL还拥有一个功能强大的固有的核心命令集。TCL经常被用于快速原型开发,脚本编程,GUI和测试等方面。•实际上包含了两个部分:一个语言和一个库。首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。由于TCL的解释器是用C\C++语言的过程库实现的,因此在某种意义上我们又可以把TCL看作C库,这个库中有丰富的用于扩展TCL命令的C\C++过程和函数,所以,Tcl是

  10. ruby-on-rails - 这个 C 和 PHP 程序员如何学习 Ruby 和 Rails? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我来自C、php和bash背景,很容易学习,因为它们都有相同的C结构,我可以将其与我已经知道的联系起来。然后2年前我学了Python并且学得很好,Python对我来说比Ruby更容易学。然后从去年开始,我一直在尝试学习Ruby,然后是Rails,我承认,直到现在我还是学不会,讽刺的是那些打着简单易学的烙印,但是对于我这样一个老练的程序员来说,我只是无法将它

随机推荐