说明
本文结构全部采用无序列表,是对 TS 基础知识的概览,发现这种结构阅读起来更顺畅,比那种分层次的减少了一层大脑加工。
正文
- 为什么使用 TypeScript
- 前提:JavaScript 是一门动态类型语言,许多低级错误(类型错误)无法在开发阶段发现,为了减少 bug 出现几率,需要给 JavaScript 加入类型定义方便在编写代码阶段发现错误。
- TypeScript 是什么?
- TypeScript 是 JavaScript 的超集,可以理解为加入了类型定义的 JavaScript 语言一个分支。
- 安装:
yarn global add typescript
// 安装完毕后内置了tsc命令(typescript compiler)
- 手动编译
// hello.ts
const fun = (name: string) => {
console.log(name)
}
// 编译成js文件
tsc hello.ts
- 一步到位自动编译并执行
yarn global add ts-node
ts-node class.ts
- 原始类型
- number、string、null、undefined、boolean、BigInt、Symbol
- 定义原始类型
- 注意:null 和 undefined 是所有类型的子类型
- 定义联合类型
let numberOrString: string | number = 123
numberOrString = 'abc' ✅
numberOrString = false 🚨
- 数组和元组
// * 定义数组的方法一
let arr: number[] = [1, 2, 3]
// * 元组是限定了数据类型和数据长度的数组
let user: [stirng, number] = ["abc", 123] // 数据类型对应,长度对应,不能多也不能少
-
对象/类
- 定义对象/类需要使用到
interface接口 interface接口- 两个常见用途:1、对对象的形状进行描述;2、对类的属性进行描述;
- 定义对象/类需要使用到
-
约束对象的形状(shape)
- 必须严格对应
interface Person {
readonly id: number
name: string
age?: number
}
let orime: Person = {
name: "orime",
age: 13,
}
-
函数类型定义的两种写法
- 函数声明写法
- 函数表达式写法
-
函数声明
function sum(x: number, y: number, z: number = 10): number {
if (x) {
return x + y + z
} else {
return x + y
}
}
- 函数表达式
const sum2: (x: number, y: number, z: number = 19) => number = sum
- 类型推断
let str = 'abc'
str = 123 🚨
- 类的作用
- 可以理解为一切实例的抽象模板
Tips:子类中使用 super 指向父类引用
-
类属性修饰符
- public:默认,实例或子类中都可以访问/修改
- readonly:只读,只能访问不能修改
- private:只能在定义类的代码块内访问(子类/实例都不能访问)
- protect:只有子类和自己能访问(实例不能访问)
- static:静态属性,只能类对象自己调用(当这个属性/方法和实例/子类没有太大关系的时候可以使用)
-
implement
- 当两个类有公共属性的时候,如果用子类继承父类的方式显得不太灵活
- 这时候可以将公共属性使用 interface 进行定义,再用 implement 进行实现
- 实现多个接口用逗号分隔
- 接口还能进行合并,比如
interface Battery extend Radio { ... }
-
Enum 枚举类型
- 使用
enum关键字进行定义 - 定义好了还能直接取值
- 直接取是取索引,从 0 开始
- 使用索引取取到的是字符串
- 使用
enum Direction {
Up = 10, // *
Down,
Left,
Right,
}
console.log(Direction.Up) // 10
console.log(Direction[12]) // Left
module.exports = {}
- enum 常见用法
- 不加常量枚举的编译结果
- 加常量枚举
- 泛型并不难,耐心看很简单
function echo<T>(arg: T): T {
return T
}
const res = echo("abc") // res -> string 类型
- 泛型就像是个形参变量(占位符),实参是
类型,使用的接收手动传入的或自动推导出的类型值
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]]
}
const result = swap(["abc", 123]) // result -> [number, string]
- 泛型约束
- 单一泛型描述的属性不够用的时候,可以使用
extends关键字扩展该泛型的属性
- 单一泛型描述的属性不够用的时候,可以使用
interface IWithLength {
length: number
}
function echoWithLength<T extends IWithLength>(arg: T): T {
console.log(arg.length)
return arg
}
const res = echoWithLength("abc") // 传入只要有length属性的值都可以
- 使用泛型约束类
class Queue<T> {
private data = []
push(item: T) {
this.data.push(item)
}
pop(): T {
return this.data.shift()
}
}
// * 约束了传入和弹出的item类型一致,相比any可获得更好的类型提示
const queue1 = new Queue<number>()
queue1.push(1)
queue1.push(3)
console.log(queue1.pop().toFixed(2))
- 泛型和接口
interface一起使用
interface KeyPair<T, U> {
key: T
value: U
}
const obj1: KeyPair<string, number> = {
key: "abc",
value: 13,
}
const obj2: KeyPair<number, string> = {
key: 12,
value: "34",
}
console.log(obj1, obj2)
export {}
- 定义数组的方式二:使用泛型
let arr: Array<number> = [1, 2, 3]
let arr1: number[] = [1, 2, 3]
- 使用泛型修饰一个函数
interface IPlus<T> {
(a: T, b: T): T
}
function plus(a: number, b: number): number {
return a + b
}
function connect(a: string, b: string): string {
return a + b
}
const plus1: IPlus<number> = plus
const connect1: IPlus<string> = connect
console.log(plus1(1, 2), connect1("a", "b")) // 3,ab
export {}
- 类型别名(type aliases)
- 在联合类型上应用较多
type NameResolver = () => string
type NameOrResolver = string | NameOrResolver
function getName(n: NameOrResolver) {
if (typeof n === "string") {
return n
} else {
return n()
}
}
- 类型断言(type assertion)告诉编译器你比他更了解当前数据类型,并要求其不再为此而报错
- 类型断言只能断言为联合类型中已存在的一种类型
function getLength(str: string | number): number {
// * 主流写法
// const s = str as String // ! 必须大写为 String
// if(s.length) return s.length
// else {
// const n = str as Number // ! 必须大写为 Number
// return n.toString().length
// }
// * 另一种写法 -> 不推荐
if ((<string>str).length) {
return (<string>str).length
} else {
return (<number>str).toString().length
}
}
console.log(getLength(123)) // 3
export {}
- 第三方库的声明文件
- 参考官方文档
- 项目中的声明文件一般是以
*.d.ts形式放到@types文件夹或另外指定的文件夹下
- 定义声明文件的方式一:
- declare var 声明全局变量
- declare function 声明全局方法
- declare class 声明全局类
- declare enum 声明全局枚举类型
- declare namespace 声明(含有子属性的)全局对象
- interface 和 type 声明全局类型
// JQuery.d.ts
declear const JQuery: (selector: string) => void
- 定义声明文件的方式二
- 比如 jQuery 是一个全局变量,它是一个对象,提供了一个 jQuery.ajax 方法可以调用,那么我们就应该使用 declare namespace jQuery 来声明这个拥有多个子属性的全局变量。
// src/jQuery.d.ts
declare namespace jQuery {
function ajax(url: string, settings?: any): void;
}
// src/index.ts
jQuery.ajax('/api/get_something');
- 注意,在 declare namespace 内部,我们直接使用 function ajax 来声明函数,而不是使用 declare function ajax。类似的,也可以使用 const, class, enum 等语句9:
// src/jQuery.d.ts
declare namespace jQuery {
function ajax(url: string, settings?: any): void;
const version: number;
class Event {
blur(eventType: EventType): void
}
enum EventType {
CustomClick
}
}
// src/index.ts
jQuery.ajax('/api/get_something');
console.log(jQuery.version);
const e = new jQuery.Event();
e.blur(jQuery.EventType.CustomClick);