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