TypeScript 速通教程

TS 速通教程

直接通过常见的写法来学习 TS 的基本使用。

三十的前端课:教程来源

1.why TS

为什么需要使用 TS?

看下面的三个场景:

  • 项目需要编写一个全局数组的排序方法
  • 你是公司的负责人,现在需要带领团队写一系列数组的相关方法
  • 你写了一个组件,该组件的事件必须具有一个特定的参数

这时候就会存在几个问题:

  • 项目其他成员怎么知道你这个方法是需要传入一个数组的?
  • 你的团队中的成员怎么知道这一系列方法的参数是什么?
  • 组件的参数的类型别人怎么知道?

通过以上的例子,我们就可以知道 TS 的目的就是为了通过类型约束来保证代码的健壮性。

2.基础环境搭建

TS 的运行环境只需要一个编译器,将 TS 编译为 JS 再执行。

可以通过 tsc 或者 ts-node 来运行。

npm install -g typescript

npm install -g ts-node

3.基础类型

基础类型有下面这些:

string number null undefined boolean
// 这是五个比较常见的基本类型
let a: string = 'hello'
let b: boolean = true
let c: number = 1
let d: null = null
let e: undefined = undefined

// 这里的 null 是不会报错,因为没有开启严格模式
// a = null
// 这里的 100 会报错,因为 number 不能赋值给 string
// a = 100

// 这里只能是这三个值,叫做字面量类型
let ENV: 'dev' | 'test' | 'prod' = 'dev'
let F: 1 | 2 | 3 = 1

// 或者 | -> 联合类型,即一个变量可以是多个类型中的一个
let a1: string | number = 'hello'
a1 = 100

// 不能将类型“String”分配给类型“string”。
//   “string”是基元,但“String”是包装器对象。如可能首选使用“string”。
// let f: string = new String('hello')

4.数组和对象

数组

// 数组有这两种定义方式,一种是类型+方括号,一种是泛型
let arr1: number[] = [1, 2, 3]
let arr2: Array<number> = [1, 2, 3]
// 空数组的定义方式
let arr3: [] = []
// 数组中是数字或者字符串的定义方式
let arr4: (number | string)[] = [1, 2, 3, '4']

// 元组的定义方式
// 元组和数组之间的区别是,元组长度是固定的,而数组长度是不固定的
let tuple: [number, string] = [1, '2']
// 某一个元素可以是undefined
let tuple1: [number, string, string?] = [1, '2']
let tuple2: [number, string, ...(string | number)[]] = [1, '2', '3', '4']

对象

// 对象的定义方式
let obj: {} = { name: 'lisi' }
let obj1: { name: string } = { name: 'lisi' }
let obj2: { name: string; age?: number } = { name: 'lisi' }
// 除了 name z之外,还可以有其他的属性,数量不确定,key是字符串,value是任意类型
let obj3: { name: string; [propName: string]: any } = { name: 'lisi', age: 18 }
let obj4: {
	a: {
		b: 1
	}
}
// 使用 ? 表示可选属性
// 我们如果后端没有返回 a 属性,那么 a 就是 undefined,如果再取 b 属性,就会报错
// 所以我们可以使用 ? 来表示 a 是可选的,如果 a 不存在,那么就不会取 b 属性,也不会报错
// es5 的解决方案是 obj4 && obj4.a && obj4.a.b
obj4?.a?.b

5.函数

// 函数的定义方式
function f1(a: number): number {
	return a + 1
}

let f2: (a: number) => number = function (a) {
	return a + 1
}

// 参数可选
function f3(a: number, b?: number): number {
	return a + b
}

// 参数默认值
function f4(a: number, b: number = 10): number {
	return a + b
}

// 剩余参数
function f5(a: number, ...rest: number[]): number {
	return a + rest.reduce((pre, cur) => pre + cur)
}

// this 指向, this 参数必须在参数列表的最前面,表示这个函数的调用者
function f6(this: Window, a: number): number {
	return a + 1
}

// 重载
function f7(a: number): number
function f7(a: string): string
function f7(a: any): any {
	return a
}

6.类

image.png

image.png

TS 中的 class

// ts 中的 class, 相比 js 多了访问修饰符,只读属性,静态属性,抽象类,抽象方法,接口等等
class TsClass {
	public name: string = 'TsClass'
	static age: number = 18
	readonly d = 1
	protected e = 2 // 只能够在当前类和子类中访问
	private f1() {
		console.log('f1')
	}
}

let tsClass = new TsClass()
// tsClass.f1() // 报错,因为 f1 是私有的

// 读取静态属性
console.log(TsClass.age)

// 更改只读属性
// tsClass.d = 2 // 报错,因为 d 是只读的

编译为 JS:

// ts 中的 class, 相比 js 多了访问修饰符,只读属性,静态属性,抽象类,抽象方法,接口等等
var TsClass = /** @class */ (function () {
    function TsClass() {
        this.name = 'TsClass';
        this.d = 1;
        this.e = 2; // 只能够在当前类和子类中访问
    }
    TsClass.prototype.f1 = function () {
        console.log('f1');
    };
    TsClass.age = 18;
    return TsClass;
}());
var tsClass = new TsClass();
// tsClass.f1() // 报错,因为 f1 是私有的
// 读取静态属性
console.log(TsClass.age);
// 更改只读属性
// tsClass.d = 2 // 报错,因为 d 是只读的

类型注释

class TsClass {
	a: number
	b: string
	constructor() {
		this.a = 123
		this.b = '456'
	}
	f(p: number): number {
		return p + 1
	}
}

此外,ts 中的 class 还可以作为类型来标注对象。

7.特殊类型和高级类型

any 和 unkonwn

let value: unknown = 1
value = 'foo'
value = true
value = undefined
value = null
value = {}
value = []
value = () => {}

let value1: any = 1
value1 = 'foo'
value1 = true
value1 = undefined
value1 = null
value1 = {}
value1 = []
value1 = () => {}

// 任何类型的值都可以赋值给 unkonwn 和 any 类型,any 直接相当于放弃了类型检查,而 unknown 会在使用前进行类型检查,这是 unknown 和 any 的重要区别
// unknown 类型的值不能直接赋值给其他类型变量,需要先进行类型断言

// any
let value3: () => {} = value1

// unknown 需要先进行类型断言
let value4: () => {} = value as () => {}

never

永远不会出现

// never 表示永远不会返回结果
function test(): never {
	while (true) {}
}

function test2(a: string | number) {
	if (typeof a === 'string') {
		return a
	} else if (typeof a === 'number') {
		return a
	} else {
		return a // 这里的 a 的类型是 never
	}
}

联合类型与交叉类型

联合类型就是我们之前一直使用的 | 操作符号。

交叉类型是 & ,即两种类型必须同时满足。

// 交叉类型
class A {
	a: number
}

class B {
	b: string
}

let obj: A & B = {
	a: 1,
	b: '2'
}

8.接口与 type

type 是一个关键字,用来给一个类型命名,经常用来定义基础类型、联合类型、交叉类型。

interface 意思是接口,区别于 type,这是定义了一个可继承的接口。常用于类、对象的定义。

// 定义联合类型
type sOrn = string | number

let a: sOrn = 'a'
let b: sOrn = 'b'

// 定义交叉类型
type obj1 = {
	a: number
}
type obj2 = {
	b: string
}
type objAll = obj1 & obj2
let c: objAll = {
	a: 1,
	b: '2'
}

// 定义函数
type f = (a: string) => string

let f1: f = (a: string) => {
	return '1'
}

// 接口一般用来定义函数、对象、类
// 定义对象
interface obj3 {
	type: {
		a1: number
	}
	type2?: string
	[propsName: string]: any
}
function f2(a: obj3) {
	console.log(a.type.a1)
}
f2({ type: { a1: 1 } })

// 定义函数
interface f3 {
	(a: number, b: number): string
}
let f4: f3 = (a: number, b: number) => {
	return '1'
}

// 定义类
interface person {
	age: number
	eat(food: string): void
}
class Marry implements person {
	age: number
	eat(food) {
		console.log(food)
	}
	constructor(age: number) {
		this.age = age
	}
}

// 定义数组
interface arr {
	[index: number]: string
}
let arr1: arr = ['1', '2']

type 和 interface 之间有什么区别?

一般我们用 type 定义一些比较简单的类型,interface 一般用来定义类和对象和函数。

此外,还有以下的区别:

image.png

10.泛型和断言

泛型

可以看成一个公用的方法,到时候需要根据传入的不同类型的参数来做出对应的操作。

function find<T = number>(arg: T[], target: T): T {
	let _result
	arg.forEach(item => {
		if (item === target) {
			_result = item
		}
	})
	return _result
}

find<number>([1, 2, 3], 3)

// 定义多个泛型
function objExtends<T, U>(a: T, b: U): T & U {
	// let res = {} as T & U
	// res = Object.assign(a, b)
	// return res
	// 或者直接下面这么写
	return Object.assign(a, b)
}

// 接口中使用泛型
interface inter1<T> {
	a1: T
	a2: number
}
let obj: inter1<string> = {
	a1: '1',
	a2: 2
}

// 泛型类
class TestClass<T> {
	a: T
	constructor(a: T) {
		this.a = a
	}
}
// new TestClass<number>(1)
// 或者直接这么写,ts会自动推断类型
new TestClass(1)

// 泛型约束
function find1<T extends number | string>(arg: T[], target: T): T {
	let _result
	arg.forEach(item => {
		if (item === target) {
			_result = item
		}
	})
	return _result
}
find1([1, 2, 3], 3)

断言

很多时候我们已经确定这个变量是什么类型了,但是 ts 的推断是无法推断出来的,这时候就需要我们使用断言,直接确定这个变量的类型。

interface obj {
	a: number
	b: number
}

// let obj1 = {}
// 这里如果赋值的话,会报错,因为这个对象没有定义属性
// obj1.a = 1

let obj1 = {} as obj
obj1.a = 1

11.ts 的类型推导机制

类型推断

如果你没有定义类型,ts 会自己跟你的上下文推断。

类型兼容性

interface inter1 {
	a: number
	b: number
}

let obj1 = {
	a: 1,
	b: 2
}

// 这里就是类型保护,obj1 的结构和 inter1 一样,所以可以赋值
let obj2: inter1 = obj1

如果结构不同,则会报错:

image.png

函数的类型保护机制:

let f1 = function (a: number, b: number) {}
let f2 = function (c: number, d: number) {}
f1 = f2 // 可以赋值,因为函数的结构一样

let f3 = function (a: number, b: number) {}
let f4 = function (a: number, b: number, c: number) {}
// f3 = f4 // 不可以赋值,因为函数的结构不一样

let f5 = function (a: number, b: number, c: number) {}
let f6 = function (a: number, b: number) {}
f5 = f6 // 可以赋值 ,被赋值的函数的参数是被赋值的函数的参数的子集

类的类型保护机制:

class class1 {
	a: number
	static c: string
	constructor(a: number, b) {
		this.a = a
	}
}

class class2 {
	a: number
	static d: number
	constructor(a: number, b, c, d) {
		this.a = a
	}
}

let instance1: class1
let instance2: class2
instance1 = instance2! // 可以赋值

12.枚举和 symbol

symbol

const symbol: symbol = Symbol('test')

枚举

一组按顺序递增的数据。

// 枚举
enum list {
	a = 1,
	b,
	c,
	d
}

enum list1 {
	a = 'hello',
	b = 'world'
}

13.工程化编译和 tsconfig

工程化

image.png

在使用构建工具的时候,构建工具会使用功能 loader 将 ts 转为 js,在 webpack 中可以理解为 ts-loader,其实本质上还是调用 TypeScript 的 tsc 命令。

tsconfig

{
	"compilerOptions":{}, // 编译的标准
	"files":[], // 编译那些文件
	"include":[], // 编译那些路径下的内容
	"exclude":[], // 那些路径下的内容不需要编译
	"extends":[], // 配置文件是可以继承另外一个配置文件的
	"typeAcquisition":{} // 制定声明文件
}

image.png

image.png

image.png

14.vue 和 react 实战 ts

这部分是最终的目的,就是在开发项目过程中使用 ts。

直接看视频:教程来源

  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

城南顾北

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值