专栏首页小丞前端库TypeScript 超详细入门讲解

TypeScript 超详细入门讲解

📢 大家好,我是小丞同学,一名大二的前端爱好者 📢 这篇文章是学习 TypeScript 的学习笔记 📢 非常感谢你的阅读,不对的地方欢迎指正 🙏 📢 愿你忠于自己,热爱生活

1. 搭建环境

全局安装 typesctipt

npm i -g typescript

创建一个 TS 文件

console.log('Hello Ts');

通过命令转化 TS

tsc '文件名'

2. 基本类型

js 是动态类型语言,所以有很多时候都不会报错,但是会存在很多的问题

1. number

定义一个 number 类型的值

let a: number
a = 10
a = 'hello' //这一行代码会报错,因为 a 的变量类型是 number ,不能赋值字符串

但是编译还是会成功的

2. string

定义一个 string 类型的值

let b: string
b = 'hello'
b = 10 // b

3. boolean

声明完直接赋值

let c: boolean = true

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

let c = false
c = 123 // 报错

4. 字面量

限定取值范围为男和女

let d: '男' | "女"
d = '男'

5. any

任意类型,相当于对改变量关闭了类型检测,显示 any

使用 TS ,不建议使用 any

let e: any
e = 1
e = 'hello'

声明变量不指定类型,就会被设置为 any,隐式 any

6. unknown

unknown 表示未知类型,是一个类型安全的 any

unknown 类型的变量,不能直接赋值给其他变量

let f: unknown
f = 'hello'
f = 1
f = true

类型断言

当我们需要将 unknown 类型的变量赋值给其他类型的变量的时候,我们可以给他指定类型

c = f as boolean
// 第二种写法
c = <boolean>f

7. 函数返回类型

在括号后面跟上一个指定的类型

function sum(a: number, b: number): number {
    return a + b
}

void 表示空,表示没有返回值

never 表示永远不会返回值

8. object

// 指定对象包含的属性
let b: { name: string }
b = { name: '小丞' }

必须对象成员完全一致,如果对象中有可选属性,我们可以采用 ? 来处理

let b: { name: string, age?: string }
b = { name: '小丞' }

这样有没有 age 都可以

如果需要设置任意都可以,可以采用下面的方式

let b: { name: string, [propName: string]: any }

但是一定要有 name 成员

9. array

声明指定类型的数组

let e: string[]
e = ['a', 'b']

也可以用这种方法

let f: Array<number>

10. 元组

固定长度的数组

let h: [string, string]
h = ['hello', 'asd']
h = [123, 'saf'] // 错误

11. enum

enum Gender {
    Male,
    Female
}
// 指定枚举类型
let i: { sex: Gender }
// 设定值
i = {
    sex: Gender.Male
}

12. & 使用

这里表示 的意思,也可以用 |表示或噢

let j: { name: string } & { age: number }
j = { name: 'nan', age: 20 }

13. 类型的别名

type myType = 1 | 2 | 3 | 4 | 5

用来简化类型的书写

3. 编译选项

tsconfig.jsonts 的配置文件,可以根据这个信息来进行代码编译

include 表示需要编译的文件,** 表示任意文件夹,* 表示任意文件

"include": [
    "./src/**/*"
]

指定 src 下任意目录的任意文件

exclude 表示排除的文件,不需要编译的文件,一般不用,和 include 的用法一样

重头戏 compilerOptions

它是一个对象,里面有很多的配置

1. target

target 用来配置编译后的 js 版本

"compilerOptions": {
    "target": "ES3"
}

例如这里,我们指定编译版本为 ES3

ES6 语法就会降级为 ES3

2. module

需要使用的模块化方案

"module": "ES2015"

有以下可选值

'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015', 'es2020', 'esnext'.

3. lib

用来指定项目使用到的库

"compilerOptions": {
    "target": "ES3",
    "module": "ES6",
    "lib": ["DOM", "ES6"]
  }

4. outDir

指定编译后文件所在的目录

"compilerOptions": {
    "target": "ES3",
    "module": "ES6",
    "lib": ["DOM", "ES6"],
    "outDir": "./dist"
  }

5. outFile

把代码合并成一个文件

设置outFile 后,把所有全局作用域中的代码合并到一个文件

只有模块化规范为 amdsystem 时可以合并

"compilerOptions": {
    "target": "ES3",
    "module": "ES6",
    "lib": ["DOM", "ES6"],
    "outDir": "./dist",
    // "outFile": "./dist/app.js"
  }

6. allowJS

是否对 JS 文件进行编译,默认是 false

"compilerOptions": {
    "target": "ES3",
    "module": "ES6",
    "lib": ["DOM", "ES6"],
    "outDir": "./dist",
    // "outFile": "./dist/app.js"
    "allowJs": false
  }

7. checkJS

是否检查 JS 代码是否符合语法规范,默认 false

"checkJs": false

8. removeComments

是否移除注释,默认是 false

"removeComments": true

9. noEmit

不生成编译后的文件,默认是 false

只想用来检查语法的时候可以用

"noEmit": true

10. noEmitOnError

决定编译报错的时候是否编译,默认是 false

"noEmitOnError": true

11. alwaysStrict

用来设置编译后的文件是否使用严格模式,默认为false

"compilerOptions": {
    "target": "ES3",
    "module": "ES6",
    "lib": ["DOM", "ES6"],
    "outDir": "./dist",
    // "outFile": "./dist/app.js"
    "allowJs": false,
    "checkJs": false,
    "removeComments": true,
    "noEmit": true,
    "noEmitOnError": true,
    "alwaysStrict": true
  }

12. noImplicitAny

是否允许隐式的 any 类型

"noImplicitAny": true

13. noImplicitThis

是否允许隐式的 this

"noImplicitThis": true

14. strictNullChecks

检查是否存在空值

"strictNullChecks": true

可以用

a?.b

来改正

15. strict

开启所有的严格检查

"strict": true

全部配置

{
  "include": ["./src/**/*"],
//   "exclude": [],
  "compilerOptions": {
    "target": "ES3",
    "module": "ES6",
    "lib": ["DOM", "ES6"],
    "outDir": "./dist",
    // "outFile": "./dist/app.js"
    "allowJs": false,
    "checkJs": false,
    "removeComments": true,
    "noEmit": true,
    "noEmitOnError": true,
    "alwaysStrict": true,
    "noImplicitAny": true,
    "noImplicitThis": true,
    "strictNullChecks": true,
    "strict": true
  }
}

4. webpack 打包 TS

1. 安装依赖包

安装一些依赖包,webpack 两个包推荐全局安装

yarn add webpack webpack-cli typescript ts-loader

2. webpack 配置文件

创建一个 webpack.config.js 文件

const path = require("path");
// 所有配置信息都写在这里
module.exports = {
  // 指定入口文件
  entry: "./index.ts",
  output: {
    // 指定打包文件目录
    path: path.resolve(__dirname, "dist"),
    // 打包后文件的名字
    filename: "bundle.js",
  },
  //   指定使用的模块
  module: {
    rules: [
      {
        //   test 指定的是规则生效的文件
        test: /\.ts$/,
        use: "ts-loader",
        exclude: /node_modules/,
      },
    ],
  },
};

3. 修改配置文件

package.json 的配置文件中,添加 build 命令,启动 webpack 打包

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

4. 引入 html 插件

安装 html-webpack-plugin

yarn add html-webpack-plugin

引入插件

const HTMLWebpackPlugin = require("html-webpack-plugin")

配置插件

 plugins:[
      new HTMLWebpackPlugin()
  ]

后面的 webpack 没什么价值,之前学过了,在这里学浪费时间,建议学第 1 节就好了

面向对象建议直接跳到抽象类,浪费时间

5. 抽象类

当我们不需要这个类来创建对象的时候,我们就可以使用对象类

例如,我们在创建 Dog 类的时候,需要继承 Animal 类,但是我们并不需要 animal 类来创建东西,为了避免它被用来创建对象,因此我们可以使用抽象类 abstarct

abstract class Animal {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    sayHello() {
        console.log('动物在叫');
    }
}

这样我们就把 Animal 对象创建为了抽象类,那我们就不能使用它来创建对象了

const aaa = new Animal('sss') // 报错

我们可以在抽象类中添加抽象方法,没有方法体

// 定义抽象方法
abstract sayHello():void

只能定义在抽象类中,子类必须对抽象方法进行重写

6. 接口

接口时用来定义一个类结构,用来定义一个类中应该包含哪些属性和方法的

它和 type 有一点相似互通之处

我们可以采用 type 来描述一个对象类型

type myType = {
    name: string,
    age: number
}

我们也可以用接口来声明一个类型

interface myInterface {
    name: string,
    age: number
}

我们可以正常的调用它

const obj: myInterface = {
    name: 'sss',
    age: 111
}

在这一点上,interfacetype 的区别在于,type 只能声明一个,而 interface 可以声明多次,例如

interface myInterface {
    name: string,
    age: number
}
interface myInterface {
    sex: string
}

这样就以 2 个接口合并起来为准

接口可以用来在定义类的时候用来限制类的结构

接口中的所有属性都不能有实际的值,接口只定义对象的结构,而不考虑实际值,在接口中所有的方法都是抽象方法

例如这里,我们限制了一个类,有 name还有一个 sayHello 的函数

interface myInterface {
    name: string,
    sayHello(): void
}

我们写一个类来实现这个接口

我们需要采用 implements 指定我们要实现的接口是哪一个

class Myclass implements myInterface {
    name: string
    constructor(name: string) {
        this.name = name
    }
    sayHello() {
        console.log('好~ ');
    }
}`

在接口中定义一个标准,指定我们需要去实现一个类 ,在我们创建类的时候需要指定它需要实现的接口,使用 implements

7. 属性的封装

现在属性是在对象中设置的,属性可以任意的被修改,这样会

导致对象中的数据变得非常不安全

我们可以在属性前添加属性的修饰符

  1. public 修饰的属性可以在任意位置访问
  2. private 定义为私有属性,私有属性只能在类内部访问
    • 通过类中添加方法使得私有属性可以被外部访问
  3. protected 受包含的属性,只能在当前类和当前类的子类中访问
// 定义私有变量
private name: String
// 定义操作的方法
setName(value: string) {
    this.name = value
}
// 修改 name 的值
per.setName('猪猪')

这样我们如果不需要修改时,我们可以把修改 name 的方法隐藏起来,如果需要限制修改的值,我们可以添加 if 判断

我们也可以采用 gettersetter 来设置存取器

get name() {
    return this._name
}

这样我们就可以直接使用 per.name 来获取值

当我们需要设置值的时候,我们可以采用 set 方法

set name(value) {
    this._name = value
}

我们可以直接将属性定义在 构造函数 中,相当于一个语法糖,简化书写

constructor(public name: string, public age: number) {}

等价于

name: string,
age: number
constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
}

8. 泛型

在定义函数或类时,如果遇到类型不明确时就可以使用泛型

首先我们需要在函数名后面,添加一个 <k> ,用来定义一个泛型 ,这里的 k 是自己随意取的,可以理解为是一个 k 类型,只有函数执行的时候,我们才知道它具体是什么类型

function fn<k>(a: k): k {
    return a
}

我们可以直接条用具有泛型的函数

fn(10)

像这里我们传入了一个数字 10 ,它会自动推断出这次的函数调用中泛型的类型为 number

但是不是每一次都能自动推断出类型的,因此我们可以使用 类型断言

提前告知我们此次传入的数据类型

fn<string>('hello')

我们也可以指定多个泛型,建议用大写字母

function fn<k, t>(a: k, b: t): k {
    return a
}
fn<string, number>('hello', 1)

指定泛型必须为某一个类

interface Inter {
    length: number
}
function fn<T extends Inter > (a:T):number {
    return a.length
}

在这里,我们设置了泛型 T 必须是 inter 的实现类,也就是必须有 length 属性

在类中使用泛型

class MyClass<T> {
    name: T
    constructor(name: T) {
        this.name = name
    }
}

学会用 TS 的思维去写代码,面向对象

9. 联合类型

可以设置多个预先类型

let myNumber: string | number
myNumber = 'six'
myNumber = 6

当多个变量有相同类型时,例如 youNumber 变量也需要 string 或者 number 的类型,我们再写一遍上面的代码会显得代码冗余,我们可以建立一个新的类型

type xNumber = string | number

这样我们再需要这种联合类型时,就可以直接使用

let myNumber: xNumber

这就像是接口 interface 一样,在很多情况下这两个是可以互换的

10. Utility Types

1. Partial

当我们需要使用一种类型时,但又想里面的参数都是可选时

我们可以采用 partial

type Person = {
    name: string,
    age: number
}
const myName: Partial<Person> = {age: 20}

全部可选

实现 Partial 原理

type Partial<T> = {
    [P in keyof T]?: T[P];
}

怎么理解呢?

首先 T 会接收到一个对象,也就是上面我们传入的 Person ,从此 T 表示 Person 对象,keyin T 的作用是,将 T 中的 key 值取出来,因此这里得到的是 nameage 的一个联合类型。

再采用 P in XXX 遍历 对象中的所有键,因此左边就是键值了,右边的 T[P] 得到的就是对应 P 对应的 value 值了,?: 符表示可选类型

2. Omit

删除指定类型中的某个类型,这些操作不影响原类型噢

例如我们定义了一个 Person 类型

type Person = {
    name: string,
    age: number
}

但我们在某个情况使用的时候,需要必须传递 agename 值可选

我们可以采用 Omit ,第二个参数表示要删除的类型

const myName: Omit<Person,'name'> = {age: 20}

实现原理

keyof T 键名的联合类型,K 要删除的类型,通过 Exclude 来排除 K ,再通过 Pick 取出剩下的类型

Pick<T, Exclude<keyof T, K>>

3. Pick

从联合类型中挑选几个类型

type Person = {
    name: string,
    age: number
}
const myName: Pick<Person, 'age'> = { age: 20 }

4. Exclude

从联合类型中删除几个类型

type Person = {
    name: string,
    age: number
}
const myName: Exclude<Person, 'age'> = { age: 20 } // 报错

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • RocketMQ入门篇-Rocket超详细讲解

    NameSrv:一个几乎无状态节点的注册中心,比zookeeper更轻量级,更好用,可集群部署,节点之间无任务信息同步,负责维护Producer和Consume...

    用户7386338
  • logback日志入门超级详细讲解

    日志:就是能够准确无误地把系统在运行状态中所发生的情况描述出来(连接超时、用户操作、异常抛出等等); 日志框架:就是集成能够将日志信息统一规范后输出的工具包。

    呆呆
  • 超详细的RabbitMQ入门

    消息指的是两个应用间传递的数据。数据的类型有很多种形式,可能只包含文本字符串,也可能包含嵌入对象。

    java技术爱好者
  • 超详细的redis入门

    Redis是一个完全开源免费的、遵守BSD协议的、高性能的key-value存储系统。它既可基于内存作为高性能缓存,也可将数据持久化到磁盘,是目前最热门...

    前端迷
  • 超详细的Sentinel入门

    Sentinel定位是分布式系统的流量防卫兵。目前互联网应用基本上都使用微服务,微服务的稳定性是一个很重要的问题,而限流、熔断降级是微服务保持稳定的一个重要的手...

    java技术爱好者
  • SpringSecurity超详细入门介绍

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明...

    用户4919348
  • 超强、超详细Redis入门教程 转

    1.redis是什么 2.redis的作者何许人也 3.谁在使用redis 4.学会安装redis 5.学会启动redis 6.使用redis客户端 ...

    wuweixiang
  • 超详细!webpack入门教程(一)

    前端构建工具就是把开发环境的代码转化成运行环境代码。一般来说,开发环境的代码是为了更好的阅读,而运行环境的代码则是为了能够更快地执行。因此开发环境和运行环境的代...

    前端林子
  • 超详细讲解Sqoop2部署过程

    摘要:超详细讲解Sqoop2部署过程,1.下载Sqoop2,增加Sqoop2变量,修改Sqoop2配置文件,默认已经安装好了hadoop。另外提供Sqoop2自...

    王小雷
  • ansible超详细讲解,值得收藏

    如果做过运维或者网站开发的朋友,一定接触过服务部署,那么一般的服务部署流程是什么呢?找一台Linux机器,安装好运行环境所需要的软件,然后把服务部...

    星星在线
  • Python 爬虫超详细讲解(零基础入门,老年人都看的懂)

    网络爬虫(又被称为网页蜘蛛,网络机器人)就是模拟浏览器发送网络请求,接收请求响应,一种按照一定的规则,自动地抓取互联网信息的程序。 原则上,只要是浏览器(客户端...

    Python小二
  • DFS(小白式超详细讲解以及代码讲解)

    根剧搜索路径的方向,通常有两条遍历图的路径: 深度优先搜索(DFS)和广度优先搜索(BFS)。 对于有向图和无向图都适用。

    杨鹏伟
  • TypeScript入门教程(一)

    本文是TypeScript的入门文章,将分别从下面四点对TypeScript进行介绍:

    前端林子
  • vuex入门,详细的讲解(小知识积累) 原

    1.vuex入门,详细的讲解:https://segmentfault.com/a/1190000011716027

    晓歌
  • 超详细讲解Sqoop2应用与实践

    摘要:超详细讲解Sqoop2应用与实践,从hdfs上的数据导入到postgreSQL中,再从postgreSQL数据库导入到hdfs上。详细讲解创建link和创...

    王小雷
  • nginx配置文件nginx.conf超详细讲解

    #nginx进程,一般设置为和cpu核数一样 worker_processes 4;                         #错误日志存放目录 er...

    互联网金融打杂
  • Java 反射 -超详细讲解(附源码)

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态...

    kirin
  • TypeScript 入门教程

    本文转载自https://ts.xcatliu.com/,作者是:xcatliu,文档对应的Github托管地址为:typescript-tutorial

    ccf19881030
  • 零基础入门C语言超详细的字符串详解

      strncmp(p, p1, n) 比较指定长度字符串 strchr(p, c) 在字符串中查找指定字符 strrchr(p, c) 在字符串中反向查找 s...

    用户6754675

扫码关注云+社区

领取腾讯云代金券