从0到1学会 TypeScript (一)

TypeScript 学习笔记(一)


朋友们,本期内容是关于 TypeScript 的学习,如果您学习过 javaScript ,或 java等后端语言,我认为您学习的过程将会非常轻松!本期内容包括类型和编译选项后续会继续更新!本期参考 TypeScript 中文手册李立超老师的讲解视频,特别鸣谢❤️!



TypeScript 是什么?

@切图仔

  • TypeScript 是以 javascript 为基础构建的语言
  • TypeScriptjavascript超集扩展javascript 的语法,并添加了许多新的特性。
  • TypeScript 可以再任何支持 javascript 的平台中执行
  • TypeScript 扩展了 javascript 的语法,增加的功能包括类型推断、枚举、元组等等。

如果你已经学习了 javascript 就能够快速上手 typescript !


TypeScript 能直接代替 JavaScript 吗?具体用处?

  • TypeScript 后简称(ts)不能直接被 javascript 后简称(js) 解析器直接执行,ts 需要编译js方可执行后续操作。

在这里插入图片描述


  • js 是一门动态类型的语言,动态类型的自由特性容易导致错误,降低开发效率和时间工作成本。
  • 相较于 jS 而言,tS 拥有了静态类型,更加严格的语法,更强大的功能;TS 可以在代码执行前就完成代码的检查,减小了运行时异常的出现的几率;
  • tS 代码可以编译为任意版本的jS代码,可有效解决不同 jS 运行环境的兼容问题;
  • 同样的功能,tS 的代码量要大于jS,但由于 tS 的代码结构更加清晰,变量类型更加明确,在后期代码的维护中 tS 却远远胜于jS
  • 从技术上层面来说,ts就是具有静态类型的 jsts 支持 ES 的新特性,对数据类型进行判断等操作,有丰富的配置选项

TypeScript的开发环境搭建

  • 下载并安装 nodejs

    在终端使用 node -v 命令查找 nodejs 版本号。

    例如:

在这里插入图片描述

  • 安装好 nodejs 就可以使用 ts 编译器

npm < node包管理器 >

  • 安装 ts,使用命令 npm i -g typescript 命令,i表示 installg表示 global,使用 npm 全局安装 ts

  • 我使用的IDEvscode,您可以使用webstorm等其他编辑器,在终端使用 tsc 命令。
    在这里插入图片描述
    这样表示安装成功啦!同时可以使用常用命令(COMMON COMMANDS),比如tsc -v 查看 ts 的版本号。


创建第一个 ts 文件

  • 命名为 01-hello.ts
  • 内容为 console.log('Hello Ts');
  • 上述谈到,ts 需要编译为 js :在当前文件所在目录下开启终端(如vscode 开启终端快捷键 Ctrl + `)并使用命令 tsc .\01-hello.ts ,对 ts 文件进行编译。
  • 然后在当前文件会生成 01-hello.js (就目前两文件内容一致)

typeScript 与 javaScript 不同点

  • 扩展了 types
  • 类型。我们知道编程语言分为两类分别为静态类型或动态类型,使用静态类型的语言中,变量的类型在编译时必须是已知的。
  • 比如声明一个变量,编译器应该知道(或可推断) 该变量是数值、字符串或布尔值;而在动态类型的语言中,只有在运行程序时才知道变量的类型。ts 可以支持静态类型,而 js 不支持。

基本类型

// 声明一个变量 同时指定它的类型为 number
let a;
// a 的类型设置为 number 以后再使用 a 的值类型 只能是 number
a = 10;
//a = 'hello';//报错 

我们知道在 js 代码是没有问题,但同时伴随着许多安全隐患,比如代码中 a 第一次赋值为 number 类型 ,在第二次赋值变为 String 类型。

但需求是 a 一直是 Number类型 ,而不是途中修改为其他类型,这很容易出现报错和错误难以发现的情况。再比如 'undefined' is not a function


类型声明

  • tsjs 添加了静态类型

  • 类型声明是 TS 非常重要的一个特征。

  • 通过类型声明可以指定 TS变量(参数、形参)的类型。

  • 指定类型后,当为变量赋值时,TS 编译器会自动检查值是否符合类型声明,符合则赋值,否则报错。简而言之,类型声明给变量设置了类型,使得变量只能存储某种类型的值。

  • 指定类型后,当为变量赋值时,TS 编译器会自动检查值是否符合类型声明,符合则赋值,否则报错。简而言之,类型声明给变量设置了类型,使得变量只能存储某种类型的值


  • 语法:
let 变量: 类型;

let 变量: 类型 =;

function fn(参数: 类型, 参数: 类型): 类型{
    ...
}
//声明完变量直接赋值
let c: boolean = true;
//let d: boolean = 123;//报错

let d = false;
//d = 123;//报错
//没有声明类型 依然报错

自动类型判断

  • TS 拥有自动的类型判断机制。

  • 当对变量的声明和赋值是同时进行的,TS 编译器会自动判断变量的类型,如果你的变量的声明和赋值时同时进行的,可以省略掉类型声明

  • 代码块中没有给 d 声明类型,但还是报错了。

函数类型声明

  • Js 中的函数是不考虑参数的类型和个数,十分便利,但是同样伴随着安全隐患。
  • 我们尽量在编写代码时发现错误,而不是真正运行时才发现。
//js
function add(a, b) {
    return a + b;
}
add(1, 2);//3
add(1, '2');//12
//---------------------水平分割线-------------------------
//ts
//number 数字数值类型
function sum(a: number, b: number) {
    return a + b;
}
sum(1, 2);//3
//sum(1, '2');//报错
//sum(1, 2, 3);//报错


sum(1,'2') 报错原因是类型 “string” 的参数不能赋给类型“number”的参数,

sum(1, 2, 3) 报错原因是应该只有 2 个参数,但现在获得 3 个参数。

function add1(a: number, b: number): number {
    return a + b;
    //return a + 'b';//报错
}
let res = sum(1, 2);//3
//函数返回值是 number
//let res: number

类型(types):

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

类型很多,但不难理解,我们已经学了number,我们逐个掌握!

//string
let a: string;
a = '10';// "" 或 ''  模板字符串 `${a}` 都可以
//let a: '10';
//也可以直接使用字面量进行类型声明
let b: 10;
b = 10;
//a = 11;//报错
//有点像 const 很少用 了解一下

|联合类型,可以使用**|**来连接多个类型

let b: 'male' | "female";
b = 'male';
b = 'female';
// b = 'undefined';//报错
// 类型“"undefined"”不可分配给类型“"male" | "female"”

let c: boolean | string;
c = true;
c = 'true';

any 表示任意类型

  • 一个变量设置类型为 any ,相当于对该变量关闭了 TS 类型校验,不建议使用。
  • 注意:let e ,声明了变量 e,其隐式具有 any 类型。
let d: any;
//let e;//变量 "d1" 隐式具有 "any" 类型,但可以从用法中推断出更好的类型
d = 10;
d = '10';
d = true;

unknown 表示未知类型

  • 相当于类型安全的any
let e: unknown;
e = 10;
e = '10';
e = true;
//看上去跟 any 相似

anyunknown 区别

  • unknown 类型变量不能直接赋值给其他变量
let d: any;
d = '10';

let s: string;
s = d;

let e:unknown;
e = 10;
e = true;
e = 'true';
//s = e;//报错
  • d 的类型为 any,可以赋值给任何变量,不会报错,但是有很大的问题。
  • s = e 报错,原因是不能将类型“unknown”分配给类型“string” ,也就是不能将未知赋值给已知。
  • 如果不想报错,需要对 e 进行类型判断
if (typeof e === 'string') {
    s = e;
}//有些麻烦,但是避免出现问题 
//所以类型断言它的作用来了

类型断言

  • 简单来说,就是告诉解析器变量的实际类型。
  • 有些情况下,变量的类型对于我们来说是很明确,但是 TS 编译器却并不清楚,此时就可以通过类型断言来告诉编译器变量的类型,断言有两种形式。语法: 变量 as 类型 或者 <类型>变量
let s: string;
let e: unknown;
s = e as string;
s = <string>e;//类似 java 中的泛型

函数

// js 普通函数声明
function fn() {

}

//没有返回值
function fn(): void
// 函数返回值为空值(没有值)

/*
function fn(num) {
    if (num > 0) {
        return true;
    } else {
        return 123;
    }
}
*/
  • 第10行-第16行注释的函数,报错原因是参数 "num" 隐式具有"any"类型,但可以从用法中推断出更好的类型,所以我们在要尽可能的避免隐式 any 的出现,也就是说需要确定变量的类型。
function fn(num: boolean | number) {
    if (num > 0) {
        return true;
    } else {
        return 123;
    }
}

never 表示永远不会返回结果

TypeScript never 类型

  • 返回“从不”的函数,不能具有可访问的终结点。
  • never 是没有值 ,不能是任何值
function fn(): never {
    //报错
}
//如果要使用never的话需要 抛出异常
function fn(): never {
    throw new Error('报错');
}

object 表示任意的对象

  • {} 用来指定对象中可以包含哪些属性;
  • 语法 :{属性名:属性值,…};
  • 在属性名后边加上, 表示属性为可选;
let a: object;
a = {};
a = function(){ };
a = [];
//“万物皆对象” java的朋友都出来吧!
let b: { name: string };
//注意区分  let b = { name: string };
//一个声明 一个赋值
//b = {};//报错
b = { name: 'zhangsan' };
//b = { name: 'zhangsan', age: 20 };//报错
  • b = {} 报错原因是类型 "{}" 中缺少属性 "name",但类型"{ name: string; }"中需要该属性。
  • b = { name: 'zhangsan', age: 20 } 报错原因是不能将类型“{ name: string; age: number; }”分配给类型“{ name: string; }”,也就是说“age”属性不在类型“{ name: string; }”中,ts 中,对象可以只指定已知属性,不能指定未知属性。
let c: { name: string, age?: number };
c = { name: 'zhangsan' };
c = { name: 'zhangsan', age: 20 };

如果想要多个不定参数呢?

let d: { name: string, [propName: string]: any };
// d 要求有 name 属性 string 类型
// 可有其他属性 可有可无
  • propName 就是变量名,其表示任意字符串的属性名
  • [propName: string]: any 表示任意类型的属性
d = { name: 'yyc' };
d = { name: 'yyc', age: 18, gender: 'male' };
> 设置函数结构的类型声明
>
>  语法 (形参:类型,形参:类型...)  => 返回值
// e 要求是一个函数 有固定的几个参数 和 参数类型
let e: (a: number, b: number) => number;
e = function (n1: number, n2: number): number {
    return n1 + n2;
}

// e = function (n1: number, n2: number,n3): number {
//     return n1 + n2;
// }
// 报错
> 设置数组结构的类型声明
>
>   语法:`类型 [ ]`  或  ` Array<类型>`
let f: string[];
// 声明 f 字符串数组
f = ['1', '2', 'a'];
// f = ['1', '2', 'a', 1];//报错 不能将类型“number”分配给类型“string”。

// g 数值数组
let g: number[];

//有点像泛型
let h: Array<number>;
h = [1, 2, 3];
//h = [1, 2, 3,'1'];
//let h: Array<any>;//尽量少用

ts 增加 js 没有的类型

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

语法:[类型,类型,...]

let i: [string, string];
i = ['1', '2'];
// i = ['1', '2', '3'];//源具有 3 个元素,但目标仅允许 2 个
// i = ['1'];//源具有 1 个元素,但目标需要 2 个
// i = ['1', 2];//不能将类型“number”分配给类型“string”

enum 枚举

  • 可以理解枚举就是一个字典,使用起来方便
let j: { name: string, gender: 0 | 1 };
j = {
    name: 'zhangsan',
    gender: 1,
}
console.log(j.gender === 1);//true
//gender 0 和 1 在这里没有意义 是男是女不清楚

//使用枚举
enum Gender {
    Male = 0,
    Female = 1,
}
let k: { name: string, gender: Gender };
k = {
    name: 'yyc',
    gender: Gender.Male,//很清楚知道是男
}
console.log(k.gender === Gender.Male);//true

& 表示 与,且,同时关系

//let l: string | number;
//let l: string & number;//没有意义
let l: { name: string } & { age: number };
//l = { name: 'yyc' };//报错
//类型 "{ name: string; }" 中缺少属性 "age",但类型 "{ age: number; }" 中需要该属性
l = { name: 'yyc', age: 20 };

type 作用:给类型起一个别名,支持基本类型、联合类型、元组等类型

//类型的别名 方便
//let m: 1 | 2 | 3 | 4;
//let n: 1 | 2 | 3 | 4;
//麻烦
type myType = string;
let m: myType;

type Type = 1 | 2 | 3 | 4;
let n: Type;
let z: Type;

编译选项

  • 我们知道 ts 不能直接运行,需要使用命令tsc xxx.ts 编译成 xxx.js,但每次写好 ts 文件都要重新手动调用上述命令,很麻烦,不方便。

自动编译文件

  • 编译文件时,使用 -w (watch)指令后,TS 编译器会自动监视文件的变化,并在文件发生变化时对文件进行重新编译
  • 使用命令 tsc xxx.ts -w

在这里插入图片描述

  • 现在,每次修改完 ts 文件就能够自动编译文件,但是只能监视一个ts 文件,需求是想要编译多个文件呢?笨方法:一个文件开一个终端窗口, 100个文件开100个终端窗口 ,不适合日常开发。
  • 将所有文件进行编译,需要配置文件

tsconfig.json 概述

  • 如果一个目录下存在一个tsconfig.json文件,那么它意味着这个目录是TypeScript项目的根目录。
  • tsconfig.json文件中指定了用来编译这个项目的根文件和编译选项。

配置文件 tsconfig.json

  • 在当前文件的根目录下创建**tsconfig.json 并输入{ }**
  • 此时如果在终端窗口直接使用 tsc 指令,则可以自动将当前项目下的所有 ts 文件编译为 js 文件。
  • tsconfig.json 是一个JSON 文件,可以写注释,是 ts 编译器的配置文件, 只需tsc命令即可完成对整个项目的编译。

配置选项

include

  • include 用来指定哪些 ts 文件需要被编译
  • 路径:*表示任意文件,** 表示任意目录
{
    "include":[
        "src/**/*"
        //编译src目录下的的任何ts文件
    ]
}

exclude

  • include正好相反,用于指定不需要被编译的文件目录,定义需要排除在外的目录。
  • 默认值:["node_modules", "bower_components", "jspm_packages"]
  • 有的文件不需要编译 ,文件路径写 exclude内部
{
    "exclude":[
        "./src/hello/**/*"
    ]
}
  • 上述示例中,srchello 目录下的文件都不会被编译。

extends

  • 定义被继承的配置文件
  • 比如还有一个 xxx.json 想放入 tsconfig.json 就可以用 extends 配置选项,相当于引入外部文件
  • 下述示例中,当前配置文件中会自动包含 config 目录下 base.json 中的所有配置信息。
{
	"extends": "./configs/base"
}

files

  • 指定被编译文件的列表,只有需要编译的文件时才会使用到
  • 下述示例中,列表中的文件都会被 TS 编译器所编译
{
	//一般情况下 比较小的项目才会使用 一般不会用
    "core.ts",
    "sys.ts",
    "types.ts",
    "scanner.ts",
    "parser.ts",
    "utilities.ts",
    "binder.ts",
    "checker.ts",
    "tsc.ts",
}

compilerOptions

  • 编译选项是配置文件中非常重要也比较复杂的配置选项

  • compilerOptions 中包含多个选项,用来完成对编译的配置


  • 子选项

    target

    • 设置 ts 代码编译的目标版本
    • 可选值:ES3(默认)、ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext
    {
        "compilerOptions":{
            "target":"es2015"
        }
    }
    

    图示:m1.ts 文件

在这里插入图片描述

  • target为默认值(ES3

在这里插入图片描述

  • targetES2015

在这里插入图片描述


module

  • 设置编译后代码使用的模块化系统
  • 可选值: CommonJS、UMD、AMD、System、ES2020、ESNext、None
{
    "compilerOptions":{
        "module": "CommonJS",
    }
}
  • module 设置为 System

在这里插入图片描述


lib

  • 指定代码运行时所包含的库(宿主环境)
  • 可选值:ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext、DOM、WebWorker、ScriptHost
{
    "compilerOptions":{
        "lib": ["dom"],
    }
}

outDir

  • 指定编译后文件所在目录
  • 默认情况下,编译后的 js 文件会和 ts文件位于相同的目录,设置outDir后可以改变编译后文件的位置
  • 下述示例,设置后编译后的 js 文件将会生成到 dist 目录
{
    "compilerOptions":{
        "outDir": "./dist",
    }
}

outFile

  • 将所有的文件编译为一个 js文件
  • 默认会将所有的编写在全局作用域中的代码合并为一个 js文件,如果module 制定了 None、System 或 AMD则会将模块一起合并到文件之中
  • outfile 仅支持 "amd""system" 模块,也就是module需要设置,下述示例,编译后的文件合并到 dist 目录下 app.js
{
    "compilerOptions":{
        "outFile": "./dist/app.js",
    }
}

rootDir

  • 指定代码的根目录,默认情况下编译后文件的目录结构会以最长的公共目录为根目录,通过 rootDir 可以手动指定根目录

allowJs

  • 表示是否对 js 文件进行编译,默认值为 false

checkJs

  • 表示是否检查 js 代码是否符合语法规范,默认值为 false
// m2.js
let hh = 10;
hh = "hello"; //报错
// tsconfig.json 设置了 checkJs 为 true
// 不能将类型“string”分配给类型“number”

removeComments

  • 表示是否移除注释,默认值为 false
  • 图示 app.ts 中书写的注释

在这里插入图片描述

  • removeComments 为默认值 app.js

在这里插入图片描述

  • 设置 removeCommentstrue app.js

在这里插入图片描述


noEmit

  • 不对代码进行编译,默认值为 false
  • 不生成编译后的文件,比如用于查看编译是否通过,检查有无语法错误等

sourceMap

  • 是否生成 sourceMap,默认值为 false

严格检查 (“use strict”)

strict

  • 启用所有的严格检查,默认值为 true,设置后相当于开启了所有的严格检查(如下)

alwaysStrict

  • 总是以严格模式对代码进行编译
  • 用来设置编译后的文件是否使用严格模式,默认值为 false

noEmitOnError

  • 有错误不生成编译后的文件,默认值为 false

noImplicitAny

  • 不允许隐式any 类型
function fn(a, b) {
    return a + b;
}
//报错 有隐式 any

noImplicitThis

  • 不允许有不明确类型的 this
function fn2() {
    console.log(this);//this 不明确
    //"this" 隐式具有类型 "any",因为它没有类型注释
}
//报错
//调用方式不明确 比如 严格模式 非严格模式 方法 函数调用等
//可以手动指定 this:window any...

function fn2(this:window) {
    console.log(this);
}

strictNullChecks

  • 严格的检查空值

【后面的了解为主】

strictBindCallApply

  • 严格检查 bind、call和apply 的参数列表

strictFunctionTypes

  • 严格检查函数的类型

strictPropertyInitialization

  • 严格检查属性是否初始化

额外检查

noFallthroughCasesInSwitch

  • 检查 switch语句包含正确的break

noImplicitReturns

  • 检查函数没有隐式的返回值

noUnusedLocals

  • 检查未使用的局部变量

noUnusedParameters

  • 检查未使用的参数

allowUnreachableCode

  • 检查不可达代码
  • 可选值:true,忽略不可达代码,false,不可达代码将引起错误

tsconfig.json 源码文件 供大家学习参考

{
    /* include 用来指定哪些 ts 文件需要被编译 
        路径: * 任意文件 ** 任意目录
    */
    "include": [
        "./src/**/*"
        // 在配置文件“e:/Secret/javascript第二轮/ts/code2/tsconfig.json”中找不到任何输入。指定的 "include" 路径为“[
        //     "./src/**/*"
        // ]”,"exclude" 路径为“[]”
    ],
    /* 
    有些文件不需要编译  文件路径写这里
    不需要被编译的文件目录
    是有默认值 ["node_modules","bower_components","jspm_package"]
    */
    "exclude": [
        "./src/exclude/**/*"
    ],
    /*   "extends": [] 
        定义被继承的配置文件
        比如还有一个 xxx.json 想放入 tsconfig.json 就可以用 extends 相当于引入外部文件


        "files":[]
        指定被编译的文件的列表 只有需要编译的文件时才会使用到
        一般情况下 比较小的项目才会使用 一般不会用
   */
    /* 
        编译器选项
        学习其子选项

    */
    "compilerOptions": {
        //target 用来指定 ts 被编译为 ES 版本
        // "target": "ES3"
        "target": "es2015",
        // es3 es5 es6 es2015 es2016-2020 esnext
        // ES3 app.ts --> app.js  let a = 10 ; ==> var a = 10;
        //js 本来没有模块化... es2015 commonJS
        "module": "CommonJS",
        // "lib": [
        //     ""
        // ],
        /* 
            lib 用来指定项目要使用的库 一般不需要动
            "lib": ["dom"],
        */
        "outDir": "./dist",
        /* 
            outDir 指定编译后文件所在目录
        */
        // outFile 将代码合并到一个文件
        //"outFile": "./dist/app.js",
        //outfile 仅支持 "amd" 和 "system" 模块
        //编译后的文件合并到 app.js
        //设置 outFile 后 所有全局作用域中的代码会合并到同一个文件
        "allowJs": true,
        // 是否对 js 文件进行编译 默认 false
        "checkJs": true,
        // 是否检查 js 代码 是否 符合语法规范 默认 false
        // m2.js
        //let hh = 10;
        //hh = "hello"; 报错
        //tsconfig.json 设置了 checkJs 为 true
        //不能将类型“string”分配给类型“number”
        //"removeComments": true,
        //是否移除注释
        "noEmit": false,
        //不生成编译后的文件 比如说试错 看看编译是否通过 有无语法错误 用的比较少
        "noEmitOnError": true,
        //有错误不生成编译后的文件
        //严格模式 use strict js 文件下加
        //用来设置编译后的文件是否使用严格模式 默认为false
        "alwaysStrict": true,
        // 不允许隐式的any类型
        "noImplicitAny": true,
        //function fn(a, b) {
        //     return a + b;
        // }报错 这里有隐式any
        "noImplicitThis": true,
        //不允许不明确类型的this
        // function fn2() {
        //     console.log(this);//this 不明确
        //     //"this" 隐式具有类型 "any",因为它没有类型注释
        // }
        //调用方式不明确 比如 严格模式 非严格模式 方法 函数调用等
        // 可以手动指定 this:window any...
        "strictNullChecks": true,
        //严格的检查空值
        "strict": false,
        //所有严格检查的总开关 如果为true 所有严格检查 都为 true
        //开发一般设为true 不需要的单独设置为 false 让代码严谨 出错率低
    },
}

第一期TypeScript学习内容就这么多啦,如果内容不错的话,望您能关注🤞点赞👍收藏❤️一键三连!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值