关于typescript:连夜爆肝只为将它送到你的面前写给初级前端快速转TypeScript指南

6次阅读

共计 16369 个字符,预计需要花费 41 分钟才能阅读完成。

一、为什么要用 TypeScript

TypeScript能够让咱们开发中防止一些 类型 或者 一些不是咱们预期心愿的代码后果 谬误。xxx is not defined 咱们都晓得 JavaScript 谬误是在运行中才抛出的,然而 TypeScript 谬误间接是在编辑器里告知咱们的,这极大的晋升了开发效率,也不必花大量的工夫去写单测,同时也防止了大量的工夫排查Bug

二、TypeScript 优缺点

长处

  • 个别咱们在前后端联调时,都要去看接口文档上的字段类型,而 TypeScript 会主动帮咱们辨认以后的类型。节俭了咱们去看 文档 或者 network 工夫。这叫做类型推导(待会咱们会讲到)
  • 敌对地在编辑器里提醒谬误,防止代码在运行时类型隐式转换踩坑。

毛病

  • 有肯定的学习老本,TypeScript中有几种类型概念,interface 接口 class 类enum 枚举generics 泛型 等这些须要咱们花工夫学习。
  • 可能和一些插件库联合的不是很完满

三、TypeScript 运行流程及 JavaScript 代码运行流程

1. JavaScript 运行流程如下,依赖 NodeJs 环境和浏览器环境

  • JavaScript 代码转换为JavaScript-AST
  • AST 代码转换为字节码
  • 运算时计算字节码

2. TypeScript 运行流程,以下操作均为 TSC 操作,三步执行完持续同上操作,让浏览器解析

  • TypeScript 代码编译为 TypeScript-AST
  • 查看 AST 代码上类型查看
  • 类型查看后,编译为 JavaScript 代码
  • JavaScript代码转换为JavaScript-AST
  • AST 代码转换为字节码
  • 运算时计算字节码

四、TypeScript 和 JavaScript 区别

只有搞懂了二者的区别,咱们才能够更好的了解TypeScript

类型零碎个性 JavaScript TypeScript
类型是如何绑定? 动静 动态
是否存在类型隐式转换?
何时查看类型? 运行时 编译时
何时报告谬误 运行时 编译时

类型绑定

JavaScript

JavaScript动静绑定类型,只有运行程序能力晓得类型,在程序运行之前 JavaScript 对类型无所不知

TypeScript

TypeScript是在程序运行前(也就是编译时)就会晓得以后是什么类型。当然如果该变量没有定义类型,那么 TypeScript 会主动类型推导进去。

类型转换

JavaScript

比方在 JavaScript1 + true这样一个代码片段,JavaScript存在隐式转换,这时 true 会变成 number 类型 number(true) 和 1 相加。

TypeScript

TypeScript 中,1+true这样的代码会在 TypeScript 中报错,提醒 number 类型不能和 boolean 类型进行运算。

何时查看类型

JavaScript

JavaScript 中只有在程序运行时能力查看类型。类型也会存在隐式转换,很坑。

TypeScript

TypeScript 中,在编译时就会查看类型,如果和预期的类型不合乎间接会在编辑器里报错、爆红

何时报告谬误

JavaScript

JavaScript 只有在程序执行时能力抛出异样,JavaScript存在隐式转换,等咱们程序执行时能力真正的晓得代码类型是否是预期的类型,代码是不是无效。

TypeScript

TypeScript 中,当你在编辑器写代码时,如有谬误则会间接抛出异样,极大得进步了效率,也是不便。

五、TypeScript 总共围绕两种模式开展

显式注解类型

举个栗子

let name: string = "前端娱乐圈";

let age: number = 38;

let hobby: string[] = ["write code", "玩游戏"]

显式注解类型就是,申明变量时定义上类型(官网话语就是 申明时带上注解 ),让咱们一看就明确,哦~,这个name 是一个 string 类型。

推导类型

举个栗子

let name = "前端娱乐圈"; // 是一个 string 类型

let age = 38;  // 是一个 number 类型

let hobby = ["write code", "玩游戏"] // 是一个 string 数组类型

推导类型就是去掉显示注解,零碎主动会辨认以后值是一个什么类型的。

六、装置 TypeScript && 运行

typescript

全局装置 typescript 环境。

npm i -g typescript

可是这只是装置了 typescript,那咱们怎么运行.ts 文件呢,装置完 typescript 咱们就能够执行 tsc 命令。

如:咱们的文件叫做 index.ts,间接在命令行执行tsc index.ts 即可。而后就能够看到在目录下编译进去一个 index.js,这就是tsc 编译完的后果。

index.ts

const userName: string = "前端娱乐圈" 

运行 tsc index.ts,你能够看见在index.ts 的同级下又生成一个index.js,如下就是编译的后果文件index.js

var userName = "前端娱乐圈"

下面咱们晓得了运行 tsc 命令就能够编译生成一个文件,有的小伙伴感觉这样太麻烦了,每次运行只是编译进去一个文件还不是运行,还得用 node index.js 才能够运行。不急咱们接着往下看

ts-node

咱们来看一下这个插件 ts-node,这个插件能够间接运行.ts 文件,并且也不会编译进去 .js 文件。

npm i ts-node

// 运行 ts-node index.ts

讲到这里咱们理解了 为什么要用 TypeScript和它的 优缺点 以及它的 运行工作形式

那么接下来步入 TypeScript 基础知识的陆地啦~,follow me。

感觉有帮忙的小伙伴能够关注一下:前端娱乐圈 公众号,谢谢啦~,每天更新一篇小技巧

七、基础知识

1. 根底动态类型

TypeScript 中根底类型跟咱们 JavScript 中根底类型是一样的。只是有各别是 Ts 外面新出的。

1. number

const count: number = 18; // 显示注解一个 number 类型

const count1 = 18; // 不显示注解,ts 会主动推导进去类型

2. string

const str: string = "前端娱乐圈"; // 显示注解一个 string 类型

const str1 = "蛙人"; // 不显示注解,ts 会主动推导进去类型

3. boolean

const status: string = false; // 显示注解一个 string 类型

const status1 = true; // 不显示注解,ts 会主动推导进去类型

4. null

const value: null = null;

const value: null = undefined; // 这一点 null 类型能够赋值 undefined 跟在 js 中是一样的,null == undefined

5. undefined

const value: undefined = undefined;

const value: undefined = null; // 这一点 null 类型能够赋值 undefined 跟在 js 中是一样的,null == undefined

6. void

预计到这有一些小伙伴可能对 void 这个比拟生疏,认为只有 TypeScript 才有的。其实不是哈,在咱们 JavaScript 就曾经存在 void 关键字啦,它的意思就是有效的,有的小伙伴可能看见过早些我的项目外面 <a href="javascript: void(0)"> 这是管制 a 标签的跳转默认行为。你不管怎么执行 void 办法它都是返回undefined

那么在咱们 TypeScriptvoid类型是什么呢。它也是代表有效的,个别只用在 函数 上,通知他人这个 函数 没有返回值。

function fn(): void {} // 正确

function testFn(): void {return 1; // 报错,不承受返回值存在}

function fn1(): void { return undefined} // 显示返回 undefined 类型,也是能够的

function fn2(): void { return null} // 显示返回 null 类型也能够,因为 null == undefined

7. never

never一个永远不会有值的类型 或者也能够说 一个永远也执行不完的类型 ,代表用于不会有值,undefinednull 也算做是值。个别这个类型就不会用到,也不必。大家晓得这个类型就行。

const test: never = null; // 谬误
const test1: never = undefined // 谬误

function Person(): never { // 正确,因为死循环了,始终执行不完
    while(true) {}}

function Person(): never { // 正确,因为递归,永远没有进口
    Person()}

function Person(): never { // 正确 代码报错了,执行不上来
    throw new Error()}

8. any

any这个类型代表 任何的 任意的 。心愿大家在我的项目中,不要大片定义any 类型。尽管它真的好使,那这样咱们写 TypeScript 就没有任何意义了。

let value: any = ""; // 正确
value = null // 正确
value = {} // 正确
value = undefined // 正确

9. unknown

unknown类型是咱们 TypeScript 中第二个 any 类型,也是承受任意的类型的值。它的英文翻译过去就是 未知的,咱们来看一下栗子

let value: unknown = ""     
value = 1;
value = "fdsfs"
value = null
value = {}

那当初必定有小伙伴纳闷,诶,那它 unknown 相当于是 any 类型,那二者的区别是什么。咱们来看一下

let valueAny: any = "";
let valueUnknown: unknown = "";

valueAny = "蛙人";
valueUnknown = "前端娱乐圈"

let status: null = false;
status = valueAny; // 正确
status = valueUnknown // 报错,不能将 unknown 类型调配给 null 类型

咱们来看一下下面的,为什么 any 类型就能被赋值胜利,而 unknown 类型不行呢,从它俩的意义来上看,还是有点区别的,any任何的,任意的、unknown未知的。所以你给 unknown 类型赋值任何类型都没关系,因为它原本就是未知类型嘛。然而你如果把它的 unknown 类型去被赋值一个 null 类型,这时人家 null 这边不干了,我不承受 unknown 类型。

说白了一句话,他人不承受 unknown 类型,而 unknown 类型承受他人,哈哈哈哈。

2. 对象动态类型

说起对象类型,咱们必定都能想到对象蕴含 {} 数组 函数

1. object && {}

其实这俩意思一样,{}object示意非原始类型,也就是除 numberstringbooleansymbolnullundefined之外的类型。

const list: object = {} // 空对象

const list1: object = null; // null 对象

const list: object = [] // 数组对象

const list: {} = {}
list.name = 1 // 报错 不可更改外面的字段,然而能够读取
list.toString()

2. 数组

const list: [] = []; // 定义一个数组类型

const list1: number[] = [1,2] // 定义一个数组,外面值必须是 number

const list2: object[] = [null, {}, []] // 定义一个数组外面必须是对象类型的

const list3: Array<number> = [1,2,3] // 泛型定义数组必须是 number 类型,泛型咱们待会讲到

3. 类

// 类
class ClassPerson = {name: "前端娱乐圈"}

const person: ClassPerson = new Person();
person.xxx = 123; // 这行代码报错,因为以后类中不存在该 xxx 属性

4. 函数

// 函数
const fn: () => string = () => "前端娱乐圈" // 定义一个变量必须是函数类型的,返回值必须是 string 类型

3. 函数类型注解

这里说一下函数显示注解和函数参数不会类型推导问题。

1. 函数返回类型为 number

function fn(a, b): number {return a + b;}
fn(1, 2)

2. 函数 void

显示注解为 void 类型,函数没有返回值。

function fn(): void {console.log(1)
}

3. 函数不会主动类型推导

能够看到上面的函数类型,不会主动类型推导,咱们实参尽管传入的 1 和 2,然而形参方面是能够承受任意类型值的,所以零碎也辨认不进去你传递的什么,所以这里得须要咱们显示定义注解类型。

function testFnQ(a, b) {return a + b}
testFnQ(1,2)

咱们来革新一下。

function testFnQ(a:number, b:number) {return a + b}
testFnQ(1,2)

咱们再来看一下参数对象显示注解类型,也是在 : 号前面赋值每个字段类型即可。

function testFnQ(obj : {num: number}) {return obj.num}
testFnQ({num: 18})

4. 元组 Tuple

元组用于示意一个已知数组的数量和类型的数组,定义数组中每一个值的类型,个别不常常应用。

const arr: [string, number] = ["前端娱乐圈", 1]

const arr: [string, string] = ["前端娱乐圈", 1] // 报错

5. 枚举 Enum

Enum枚举类型,能够设置默认值,如果不设置则为索引。

enum color {
    RED,
    BLUE = "blue",
    GREEN = "green"
}

// color["RED"] 0
// color["BLUE"] blue

像下面的 colorRED 没 有设置值,那么它的值则为 0,如果BLUE 也不设置的话那么它的值则是1,它们这里是递增。如果设置值则是返回设置的值

留神这里还有一个问题,间接来上代码

通过下面学习咱们晓得了 enum 能够递增值,也能够设置默认值。然而有一点得留神一下,enum没有 json 对象那样灵便,enum不能在任意字段上设置默认值。

比方上面栗子,RED没有设置值,而后 BLUE 设置了默认值,然而 GREEN 又没有设置,这时这个 GREEN 会报错。因为你第二个 BLUE 设置完默认值,第三又不设置,这时代码都不晓得该咋递增了,所以报错。还有一种计划就是你给 BLUE 能够设置一个数字值,这时第三个 GREEN 不设置也会跟着递增,因为都是 number 类型。

// 报错
enum color {
    RED,
    BLUE = "blue",
    GREEN
}

// good
enum color {
    RED,       // 0
    BLUE = 4,  // 4
    GREEN      // 5
}

比方 enum 枚举类型还能够反差,通过 valuekey值。像咱们 json 对象就是不反对这种写法的。

enum color {
    RED,       // 0
    BLUE = 4,  // 4
    GREEN      // 5
}

console.log(color[4]) // BLUE
console.log(color[0]) // RED

5. 接口 Interface

接口 interface 是什么,接口 interface 就是不便咱们定义一处代码,多处复用。接口外面也存在一些修饰符。上面咱们来认识一下它们吧。

1. 接口怎么复用

比方在讲到这之前,咱们不晓得 接口 这货色,可能须要给对象定义一个类型的话,你可能会这样做。

const testObj: {name: string, age: number} = {name: "前端娱乐圈", age: 18}

const testObj1: {name: string, age: number} = {name: "蛙人", age: 18}

咱们用接口来革新一下。

interface Types {
    name: string, 
    age: number
}

const testObj: Types = {name: "前端娱乐圈", age: 18}

const testObj1: Types = {name: "蛙人", age: 18}

能够看到应用 interface 关键字定义一个接口,而后赋值给这两个变量,实现复用。

2. readonly 修饰符

readonly类型,只可读状态,不可更改。

interface Types {
    readonly name: string, 
    readonly age: number
}

const testObj: Types = {name: "前端娱乐圈", age: 18}

const testObj1: Types = {name: "蛙人", age: 18}

testObj.name = "张三" // 无奈更改 name 属性,因为它是只读属性
testObj1.name = "李四" // 无奈更改 name 属性,因为它是只读属性

3. ? 可选修饰符

可选修饰符以 ? 定义,为什么须要可选修饰符呢,因为如果咱们不写 可选修饰符 ,那interface 外面的属性都是必填的。

interface Types {
    readonly name: string, 
    readonly age: number,
    sex?: string
}

const testObj: Types = {name: "前端娱乐圈", age: 18}

4. extends 继承

咱们的 interface 也是能够继承的,跟 ES6Class 类一样,应用 extends 关键字。

interface Types {
    readonly name: string, 
    readonly age: number,
    sex?: string
}

interface ChildrenType extends Types { // 这 ChildrenType 接口就曾经继承了父级 Types 接口
    hobby: []}
    
const testObj: ChildrenType = {name: "前端娱乐圈", age: 18,hobby: ["code", "羽毛球"] }

5. propName 扩大

interface 外面这个性能就很弱小,它能够写入不在 interface 外面的属性。

interface Types {
    readonly name: string, 
    readonly age: number,
    sex?: string,
}

const testObj: Types = {name: "前端娱乐圈", age: 19, hobby: [] } 

下面这个 testObj 这行代码会爆红,因为 hobby 属性不存在 interface 接口中,那么咱们不存在的接口中的,还不让人家写了?。这时候能够应用 自定义 就是下面的propName

interface Types {
    readonly name: string, 
    readonly age: number,
    sex?: string,
    [propName: string]: any // propName 字段必须是 string 类型 or number 类型。值是 any 类型,也就是任意的
}

const testObj: Types = {name: "前端娱乐圈", age: 19, hobby: [] } 

在运行下面代码,就能够看到不爆红了~

6. Type

咱们再来看一下 Type,这个是申明类型别名使的,别名类型只能定义是: 根底动态类型 对象动态类型 元组 联结类型

留神:type 别名不能够定义 interface

type Types = string;

type TypeUnite = string | number

const name: typeUnite = "前端娱乐圈"
const age: typeUnite = 18

1. 那么 type 类型别名和 interface 接口有什么区别呢

1. type 不反对 interface 申明
type Types = number
type Types = string // 报错,类型别名 type 不容许呈现反复名字

interface Types1 {name: string}

interface Types1 {age: number}

// interface 接口能够呈现反复类型名称,如果反复呈现则是,合并起来也就是变成 {name:string, age: number}

第一个 Types 类型别名 type 不容许呈现反复名字,interface 接口能够呈现反复类型名称,如果反复呈现则是,合并起来也就是变 {name:string, age: number}

再来看一下 interface 另一种状况

interface Types1 {name: string}

interface Types1 {name: number}

能够看到下面两个同名称的 interface 接口,外面的属性也是同名称,然而类型不一样。这第二个的 Types1 就会爆红,提醒:后续申明的接口,必须跟后面申明的同名属性类型必须保持一致 ,把后续申明的name 它类型换成 string 即可。

2. type 反对表达式 interface 不反对
const count: number = 123
type testType = typeof count

const count: number = 123

interface testType {[name: typeof count]: any // 报错
}

能够看到下面 type 反对表达式,而 interface 不反对

3. type 反对类型映射,interface 不反对
type keys = "name" | "age"  
type KeysObj = {[propName in keys]: string
}

const PersonObj: KeysObj = { // 失常运行
    name: "蛙人",
    age: "18"
} 

interface testType {[propName in keys]: string // 报错
}

7. 联结类型

联结类型 |示意,说白了就是满足其中的一个 类型 就能够。

const statusTest: string | number = "前端娱乐圈"

const flag: boolean | number = true

再来看一下栗子。咱们用函数参数应用 联结类型 看看会产生什么

function testStatusFn(params: number | string) {console.log(params.toFixed()) // 报错
}

testStatusFn(1)

下面咱们说过了,函数参数类型不能类型主动推导,更何况当初用上 联结类型,零碎更懵逼了,不能辨认以后实参的类型。所以拜访以后类型上的办法报错。

接下来带大家看一些 类型爱护 ,听着挺高级,其实这些大家都见过。别忘了记得关注: 前端娱乐圈 公众号哦,嘻嘻

1. typeof

function testStatusFn(params: number | string) {console.log(params.toFixed()) // 报错
}
testStatusFn(1)

革新后

// 失常
function testStatusFn(params: string | number) {if (typeof params == "string") {console.log(params.split)
    }

    if (typeof params == "number") {console.log(params.toFixed)
    }
}

testStatusFn(1)

2. in

// 报错
interface frontEnd {name: string}

interface backEnd {age: string}

function testStatusFn(params: frontEnd | backEnd) {console.log(params.name)
}

testStatusFn({name: "蛙人"})

革新后

// 失常
function testStatusFn(params: frontEnd | backEnd) {if ("name" in params) {console.log(params.name)
    }

    if ("age" in params) {console.log(params.age)
    }
}

testStatusFn({name: "蛙人"})

3. as 断言

// 报错
interface frontEnd {name: string}

interface backEnd {age: string}

function testStatusFn(params: frontEnd | backEnd) {console.log(params.name)
}

testStatusFn({name: "蛙人"})

革新后

// 失常
function testStatusFn(params: frontEnd | backEnd) {if ("name" in params) {const res = (params as frontEnd).name
        console.log(res)
    }
    
    
    if ("age" in params) {const res = (params as backEnd).age
        console.log(res)
    }
}

testStatusFn({age: 118})

8. 穿插类型

穿插类型 就是跟联结类型相同,它用 & 示意,穿插类型 就是两个类型必须存在。这里还用下面的 联结类型 的栗子来看下。

interface frontEnd {name: string}

interface backEnd {age: number}

function testStatusFn(params: frontEnd & backEnd) {}

testStatusFn({age: 118, name: "前端娱乐圈"})

这里咱们能够看到实参必须传入两个 接口 (interface) 全副的属性值才能够。联结类型 是传入其中类型就能够。

留神:咱们的接口 interface 呈现同名属性

interface frontEnd {name: string}

interface backEnd {name: number}

function testStatusFn(params: frontEnd & backEnd) {console.log(params)
}

testStatusFn({name: "前端"})

下面咱们两个接口类型中都呈现了同名属性,然而类型不一样,这时类型就会变为never

<img src=”https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/51e337707b6641e590bbb0139fabacdb~tplv-k3u1fbpfcp-watermark.image” width=”90%”>

9. 泛型

泛型是 TypeScript 中最难了解的了,这里我尽量用通俗易懂的形式讲明确。

function test(a: string | number, b: string | number) {console.log(a, b)
}
test(1, "前端娱乐圈")

比方下面栗子,函数参数 注解类型 定义 stringnumber,调用函数实参传入也没什么问题,然而有个需要,就是实参咱们 必须传入同样的类型 (传入两个number 类型)。尽管下面这种 联结类型 也能够实现,然而如果咱们要在加一个 boolean 类型,那么 联结类型 还得在追加一个boolean,那这样代码太冗余了。

这时就须要用到 泛型 了,泛型 是专门针对不确定的类型应用,并且灵便。泛型的应用大部分都是应用 <T>,当然也能够轻易应用,如:<Test><Custom> 都能够。

function test<T>(a: T, b: T) {console.log(a, b)
}
test<number>(1, "前端娱乐圈") // 调用前面跟着尖括号这就是泛型的类型,这时报错,因为在调用的应用类型是 number,所以只能传入雷同类型的

test<boolean>(true, false) 

test<string>("前端娱乐圈", "蛙人")

下面这应用 泛型 就解决了咱们方才说的传入同一个类型参数问题,然而 泛型 也能够应用不同的参数,能够把调用类型定义为<any>

function test<T>(a: T, b: T) {console.log(a, b)
}

test<any>(1, "前端娱乐圈")

然而下面这种又有一种问题,它能够传入对象,然而如果咱们只心愿传入 number 类型和 string 类型。那么咱们 泛型 也给咱们提供了 束缚 类型。泛型 应用 extends 进行了 类型束缚 ,只能抉择stringnumber 类型。

function test<T extends number | string, Y extends number | string>(a: T, b: Y) {console.log(a, b)
}

test<number, string>(18, "前端娱乐圈")

test<string, number>("前端娱乐圈", 18)

这时,传入泛型时应用 逗号分隔,来定义每一个类型心愿是什么。记住,只有咱们不确定的类型,能够应用泛型。

10. 模块

TypeScript也反对 importexport这里大多数小伙伴都晓得,这里都不多讲啦。

// 导入

import xxx, {xxx} from "./xxx"

// 导出

export default {}

export const name = "前端娱乐圈"

如有不明确的小伙伴,能够看我以前文章 聊聊什么是 CommonJs 和 Es Module 及它们的区别

11. Class 类

以下这三个修饰符是在 TypeScript 类中能力应用,在 JavaScript 类中是不反对的。

1. public

public的公共属性,就是不论在 的外部还是内部,都能够拜访该 属性 办法 。默认定义的 属性 办法 都是public

class Person {
    name = "前端娱乐圈";
    public age = 18;
}
const res = new Person();
console.log(res.name, res.age) // 前端娱乐圈 18

下面能够看到打印后果都能显示进去,name属性没有定义 public 公共属性,所以 外面定义的 属性 办法 默认都是 public 定义。

2. private

private的公有属性,只有在以后 外面能力拜访,以后 就是 {} 外面区域内。在 {} 里面是不能拜访 private 定义的 属性 办法

class Person {
    private name = "前端娱乐圈";
    private age = 18;
}
const res = new Person();
console.log(res.name, res.age) // 这俩行会爆红,以后属性为公有属性,只能在类外部拜访

class Scholl extends Person {getData() {return this.username + "," + this.age}
}
const temp = new Scholl()
console.log(temp.getData()) // 爆红~,尽管继承了 Person 类,然而 private 定义是只能在以后类拜访,子类也不能拜访。

3. protected

protected的爱护属性,只有在 以后类 子类 能够拜访。也就是说用 protected 属性定义的 子类 也能够拜访。

class Person {
    protected username = "前端娱乐圈";
    protected age = 18;
}
const res = new Person();
console.log(res.name, res.age) // 这俩行会爆红,以后属性为公有属性,只能在类外部拜访

class Scholl extends Person {getData() {return this.username + "," + this.age}
}
const temp = new Scholl()
console.log(temp.getData()) // 前端娱乐圈,18。能够失常拜访父类的属性

4. implements

implements关键字只能在 class 中应用,顾名思义,实现一个新的类,从父级或者从接口实现所有的属性和办法,如果在 PersonAll 类外面不写进去接口外面已有的属性和办法则会报错。

interface frontEnd {
    name: string,
    fn: () => void}

class PersonAll implements frontEnd {
    name: "前端娱乐圈";
    
    fn() {}
}

5. 抽象类

抽象类应用 abstract 关键字定义。abstract形象办法不能实例化,如果,抽象类外面办法是形象的,那么自身的类也必须是形象的,形象办法不能写函数体。父类外面有形象办法,那么子类也必须要从新该办法。

// 抽象类
abstract class Boss {
    name = "秦";
    call() {} // 形象办法不能写函数体
}

class A extends Boss {call() {console.log(this.name);
        console.log("A")
    }
}

class B extends Boss {call() {console.log("B")
    }
}

new A().call()

该抽象类应用场景,比方 A 需要或者 B 需要正好须要一个公共属性,而后自身还有一些本人的逻辑,就能够应用抽象类,抽象类只能在 TypeScript 中应用。

12. 命名空间 namespace

咱们学到当初能够看到,不晓得小伙伴们发现没有,我的项目中文件是不是不能有反复的变量(不论你是不是一样的文件还是其它文件),否则就间接爆红了。命名空间一个最明确的目标就是解决重名问题。

命名空间应用 namespace 关键字来定义,来看栗子吧。

index.ts

namespace SomeNameSpaceName {const q = {}

    export interface obj {name: string}
}

下面这样,就定义好了一个命名空间,能够看到变量 q 没有写 export 关键字,这证实它是外部的变量,就算别的 .ts 文件援用它,它也不会裸露进来。而 interface 这个 obj 接口是能够被全局拜访的。

咱们在别的页面拜访以后命名空间

1. reference 引入

/// <reference path="./index.ts" />
namespace SomeNameSpaceName { 
    export class person implements obj {name: "前端娱乐圈"}
}

2. import

export interface valueData {name: string}
import {valueData} from "./xxx.ts"

这时应用命名空间之后齐全能够解决不同文件重名爆红问题。

13. tsConfig.json

这个 tsconfig 文件,是咱们编译 ts 文件,如何将 ts 文件编译成咱们的 js 文件。tsc -init这个命令会生成该文件进去哈。执行完该命令,咱们能够看到根目录下会生成一个 tsconfig.json 文件,外面有一堆属性。

那么咱们怎么将 ts 文件编译成 js 文件呢,间接执行 tsc 命令能够将根目录下所有的 .ts 文件全副编译成 .js 文件输入到我的项目下。

更多配置文档,请参考官网

{// include: ["*.ts"] // 执行目录下所有的 ts 文件转换成 js 文件
    // include: ["index.ts"] // 只将我的项目下 index.ts 文件转换为 js 文件
    // files: ["index.ts"] // 跟 include 一样,只执行以后数组值外面的文件, 以后 files 必须写相对路径
    // exclude: ["index.ts"] // exclude 就是除了 index.ts 不执行,其它都执行
    
    compilerOptions: {
        removeComments: true, // 去掉编译完 js 文件的正文
        outDir: "./build", // 最终输入的 js 文件目录
        rootDir: "./src", // ts 入口文件查找
    }
}

八、实用类型

最初来说一下实用类型,TypeScript规范库自带了一些实用类型。这些实用类都是不便接口 Interface 应用。这里只列举几个罕用的,更多实用类型官网

1. Exclude

从一个类型中排除另一个类型,只能是 联结类型 ,从TypesTest 类型中排除 UtilityLast 类型。

实用于:并集类型

interface UtilityFirst {name: string}

interface UtilityLast {age: number}

type TypesTest = UtilityFirst | UtilityLast;

const ObjJson: Exclude<TypesTest, UtilityLast> = {name: "前端娱乐圈"}

2. Extract

Extract正好跟下面那个相同,这是抉择某一个可赋值的 联结类型 ,从TypesTest 类型中只抉择 UtilityLast 类型。

实用于:并集类型

interface UtilityFirst {name: string}

interface UtilityLast {age: number}

type TypesTest = UtilityFirst | UtilityLast;

const ObjJson: Extract<TypesTest, UtilityLast> = {age: 1}

3. Readonly

把数组或对象的所有属性值转换为只读的。这里只演示一下对象栗子,数组同样的写法。

实用于:对象、数组

interface UtilityFirst {name: string}

const ObjJson: Readonly<UtilityFirst> = {name: "前端娱乐圈"}
ObjJson.name = "蛙人" // 报错 只读状态

4. Partial

把对象的所有属性设置为可选的。咱们晓得 interface 只有不设置 ? 修饰符,那么对象都是必选的。这个实用类能够将属性全副转换为可选的。

实用于:对象

interface UtilityFirst {name: string}

const ObjJson: Partial<UtilityFirst> = {}

5. Pick

Pick选择对象类型中的局部 key 值,提取进去。第一个参数 目标值 ,第二个参数 联结key

实用于:对象

interface UtilityFirst {
    name: string,
    age: number,
    hobby: []}

const ObjJson: Pick<UtilityFirst, "name" | "age"> = {
    name: "前端娱乐圈",
    age: 18
}

6. Omit

Omit选择对象类型中的局部 key 值,过滤掉。第一个参数 目标值 ,第二个参数 联结key

实用于:对象

interface UtilityFirst {
    name: string,
    age: number,
    hobby: string[]}

const ObjJson: Omit<UtilityFirst, "name" | "age"> = {hobby: ["code", "羽毛球"]
}

7. Required

Required把对象所有可选属性转换成必选属性。

实用于:对象

interface UtilityFirst {
    name?: string,
    age?: number,
    hobby?: string[]}

const ObjJson: Required<UtilityFirst> = {
    name: "蛙人",
    age: 18,
    hobby: ["code"]
}

8. Record

创立一个对象后果集,第一个参数则是 key 值,第二个参数则是 value 值。规定咱们只能创立这外面字段值。

实用于:对象

type IndexList = 0 | 1 | 2

const ObjJson: Record<IndexList, "前端娱乐圈"> = {
    0: "前端娱乐圈",
    1: "前端娱乐圈",
    2: "前端娱乐圈"
}

九、闲聊

给在 北京通州 租房小伙伴们提个醒,最近被这狗 B 小房地产公司坑了,租房到期成心不退押金,大家在 通州 找房的小伙伴们留神一下,千万别碰见这家狗中介公司,这家公司注册一堆公司名,北京珺奇地产 北京珺邺地产 等,打着二十一世纪旗号成心骗人。你们必定问我为啥找这么小公司租房,特马的这里还得吐槽一下这个 某居客App,我第一次用这个 App 租房,没想到这外面都是一堆相似于这种的小中介公司,真的很恶心。租房还得找大公司,靠谱安心。

感激

谢谢你读完本篇文章,心愿对你能有所帮忙,如有问题欢送各位斧正。
我是蛙人,如果感觉写得能够的话,请点个赞吧❤。
感兴趣的小伙伴能够退出 [前端娱乐圈交换群] 欢送大家一起来交换探讨
写作不易,「点赞」+「在看」+「转发」谢谢反对❤
下篇更新 TypeScript 实战,欢送关注

参考资料

  • https://www.cnblogs.com/mengf…
  • 了不起的 TypeScript 入门教程
  • TypeScript 编程实体书
  • TypeScript 中文网
正文完
 0