TypeScript是什么
TypeScript(简称:ts) 是JavaScript的超集(js有的ts都有)。
TypeScript = Type + JavaScript (在js基础之上,为js添加了类型支持)。
TypeScript是微软开发的开源编程语言,设计目标是开发大型应用。可以在任何运行JavaScript的地方运行。
TypeScript为什么要为JS添加类型支持?
js的类型系统存在“先天缺陷”,js代码中绝大部分错误都是类型错误
优势一:类型化思维方式,使得开发更加严谨,提前发现错误,减少改 Bug 时间。
优势二:类型系统提高了代码可读性,并使维护和重构代码更加容易。
优势三:补充了接口、枚举等开发大型应用时 JS 缺失的功能。
Vue 3 源码使用 TS 重写,释放出重要信号:TS 是趋势。
安装解析 TS 的工具包
typescript:就是用来解析 TS 的工具包。提供了 tsc 命令,实现了 TS -> JS 的转化。
简化执行TS的步骤
简化方式:使用 ts-node 包,“直接”在 Node.js 中执行 TS 代码。
安装命令:npm i –g ts-node
使用方式:ts-node hello.ts
类型注解
TypeScript 中的数据类型分为两大类:1 原始类型(基本数据类型) 2 对象类型(复杂数据类型)。
基本数据类型
常用的基本数据类型有 5 个:number / string / boolean / undefined / null。
新增 symbol
1 2 3 4 5 6
| let age: number = 18 let food: string = '糖葫芦' let isStudying: boolean = true let u: undefined = undefined let n: null = null let s:symbol = Symbol()
|
复杂数据类型
数组
1 2 3 4
| let names: string[] = ['迪丽热巴', '古力娜扎', '马尔扎'] let nums: number[] = [100, 200, 300] let numebrs: Array<number> = [1,2,3] let b: boolean[] = [true,false]
|
元组
元组类型是另一种类型的数组,它确切的知道包含多少个元素,以及特点索引对应的类型。
1
| let position:[number, string, number] = [11, 's', 22]
|
函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function add(num1: number, num2: number): number { return num1 + num2 }
const add = (num1: number, num2: number): number => { return num1 + num2 }
const add: (num1: number, num2: number) => number = (num1,num2) => { return num1 + num2 }
type fn = (num1: number, num2: number) => number const add: fn = (num1,num2) => { return num1 + num2 }
|
没有返回值的函数
1 2 3 4
| function greet(name:string): void { console.log('Hello',name); } greet('jack')
|
可选参数
1 2 3
| function mySlice(start?: number, end?: number): void { console.log('起始索引:', start, '结束索引:', end); }
|
对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| let person: { sayHi: () => void sing: (name: string) => void sum: (num1: number, num2: number) => number }
let person: { name: string; age: number; sayHi(): void; greet(name: string): void } = { name: 'jack', age: 19, sayHi() {}, greet(name) {} }
|
类型别名
type
1 2 3
| type CustomArray = (number | string)[] let arr1: CustomArray = [1,'x',5] let arr2: CustomArray = [1,'x',3]
|
字面量类型
使用模式:字面量类型配合联合类型一起使用
使用场景:用来表示一组明确的可选值列表
1 2 3 4
| function changeDirection(direction: 'up' | 'down' | 'left' | 'right'){ console.log(direction); } changeDirection("down")
|
any类型
任意值
联合类型
1 2
| let arr: (number|string)[] = [1,2,3,'s'] let arr1: number|string[] = ['s']
|
交叉类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| interface Person { name: string } interface Contact { phone: string }
type PersonDatail = Person & Contact let obj: PersonDatail = { name: 'jack', phone: '133...' }
interface A { fn: (value: number) => string } interface B { fn: (value: string) => string } type C = A & B
let c: C = { fn:function(value){ console.log(value); return value + '' } }
let c:C
c.fn('a')
|
索引签名类型
使用场景:当无法确定对象中有哪些属性(或者说对象中可以出现任意多个属性),此时,就用到索引签名类型了。
使用 [key: string] 来约束该接口中允许出现的属性名称。表示只要是string类型的属性名称,都可以出现在对象中。
key只是一个占位符,可以换成任意合法的变量名称。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| interface AnyObject { [key: string]: number } let obj: AnyObject = { a: 1, abc: 124, abcde: 12345 }
interface MyArray<T> { [n: number]: T } let arr: MyArray<number> = [1, 2, 3]
|
映射类型
映射类型:基于旧类型创建新类型(对象类型),减少重复、提升开发效率。
Key in PropKeys 表示 Key 可以是 PropKeys 联合类型中的任意一个,类似于 forin(letk in obj)。
keyof of Props 表示获取到对象类型Props中所有键的联合类型即,’a’| ‘b’ | ‘c’
注意:映射类型只能在类型别名中使用,不能在接口中使用。
1 2 3 4 5 6
| type PropsKeys = 'x' | 'y' | 'z' type Type1 = { x:number; y: number; z: number } type Type2 = { [Key in PropsKeys]: number }
type Props = { a: number; b: string; c: boolean } type Type3 = { [key in keyof Props]: number }
|
索引查询(访问)类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| type Props = { a: number; b: string; c: boolean } type TypeA = Props['a'] type MyPartial<T> = { [P in keyof T]?: T[P] }
type PartialProps = MyPartial<Props>
type Props = { a: number b: string c: boolean } type TypeA = Props['a' | 'b'] type TypeB = Props[keyof Props]
|
接口
直接在对象名称后面写类型注解的坏处:
1 代码结构不简洁
2 无法复用类型注解。
接口:为对象的类型注解命名,并为你的代码建立契约来约束对象的结构。 语法:
1 2 3 4 5 6 7 8 9
| interface IUser { name: string age: number }
let p1: IUser = { name: 'jack', age: 18 }
|
接口继承和复用
1 2 3 4 5 6 7 8
| interface Point2D { x:number; y: number} interface Point3D extends Point2D { z:number}
let person: Point3D = { x:1, y:2, z:3 }
|
和type类型别名的区别
相同点:都可以给对象指定类型
不同点:
interface 接口只能给对象指定类型
type类型别名,可以为任意类型指定别名
类型推论
在 TS 中,某些没有明确指出类型的地方,类型推论会帮助提供类型。
换句话说:由于类型推论的存在,这些地方,类型注解可以省略不写!
发生类型推论的2种常见场景:1 声明变量并初始化时 2 决定函数返回值时。
注意:这两种情况下,类型注解可以省略不写! 推荐:能省略类型注解的地方,就省略(偷懒、充分利用TS类型推论的能力,提升开发效率)。
类型断言
当类型包含过大要缩小范围
1 2 3 4 5 6
| const aLink = document.getElementById('link') aLink.href
const aLink = <HTMLAnchorElement>document.getElementById('link') const aLink = document.getElementById('link') as HTMLAnchorElement aLink.href
|
枚举
枚举是TS为数不多的非JavaScript类型级扩展(不仅仅是类型)的特性之一。
因为:其他类型仅仅被当做类型,而枚举不仅用作类型,还提供值(枚举成员都是有值的)。
也就是说,其他的类型会在编译为JS代码时自动移除。但是,枚举类型会被编译为JS代码!
一般情况下,推荐使用字面量类型+联合类型组合的方式,因为相比枚举,这种方式更加直观、简洁、高效。
1 2 3 4 5 6 7 8 9 10 11 12 13
| enum Direction { Up = 'UP', Down = 'Down', Left = 'Left', Right = 'Right' }
function changeDirection(direction:Direction){ console.log(direction); }
changeDirection(Direction.Up)
|
类型查询
typeof
1 2 3 4 5
| let p = { x: 1, y :2 } function formatPoint(point: typeof p){ console.log(point); } formatPoint({x: 1, y: 3})
|
class
TS中的 class,不仅提供了class的语法功能,也作为一种类型存在。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| class Person { age: number gender = '男'
constructor(age: number, gender: string){ this.age = age this.gender = gender } } const p = new Person(1,'s') console.log(p.age, p.gender);
class Point { x = 1 y = 2
scale(n: number): void { this.x *= n this.y *= n } }
const p = new Point() p.scale(10) console.log(p.x, p.y);
|
继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Animal { move() { console.log('走两步'); } }
class Dog extends Animal { name = '二哈' bark() { console.log('旺旺!'); } }
const d = new Dog() d.bark() d.move()
|
实现接口
1 2 3 4 5 6 7 8 9
| interface Singable { sing(): void } class Person implements Singable { sing() { console.log('你是我的小啊小苹果'); } }
|
成员可见性
public(公有的)
默认的可见性,表示公有的、公开的,公有成员可以被任何地方访问
protected(受保护的)
在子类的方法内部可以通过 this 来访问父类中受保护的成员,但是,对实例不可见!
private (私有的)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class Animal { public move() { console.log('走两步'); } protected move1() { console.log('走两步'); } private move2() { console.log('走两步'); } run(){ this.move() this.move1() this.move2() } }
const a = new Animal() a.move() a.move1() a.move2()
class Dog extends Animal { name = '二哈' bark() { console.log('旺旺!'); this.move() this.move1() this.move2() } }
const d = new Dog() d.move() d.move1() d.move2()
|
只读
使用 readonly **关键字修饰该属性是只读的,注意只能修饰属性不能修饰方法**。
接口或者表示的对象类型,也可以使用readonly
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Person { readonly age: number = 18 constructor(age: number){ this.age = age } }
interface IPerson { readonly name: string } let obj1: IPerson = { name:'jack' } let obj2: {readonly name: string} = { name:'jack' }
|
泛型(类型变量)
保证类型安全的同时,可以让函数与多种不同的类型一起工作
创建泛型函数
语法:在函数名称的后面添加**<>(尖括号),尖括号中添加类型变量**,比如此处的Type。
类型变量 Type,是一种特殊类型的变量,它处理类型而不是值。
1 2 3 4
| function id<Type>(value: Type): Type { console.log(value); return value }
|
调用泛型函数
1 2 3 4
| const num = id<number>(10) const num = id<string>('10')
let num = id(10)
|
泛型约束
指定更加具体的类型
1 2 3 4
| function id<Type>(value: Type[]): Type[] { console.log(value.length); return value }
|
添加约束
通过 extends 关键字使用接口,为泛型添加约束
该约束表示:传入的类型必须具有 length 属性
1 2 3 4 5 6
| interface ILength { length: number } function id<Type extends ILength>(value: Type): Type { console.log(value.length); return value } let num = id('s')
|
keyof 对象键名的联合类型
keyof 关键字接收一个对象类型,生成其键名称(可能是字符串或数字)的联合类型。
本示例中 keyof Type 实际上获取的是 person 对象所有键的联合类型,也就是: ‘name’l| ‘age’。
1 2 3 4 5 6 7 8 9 10
| function getProp<Type, Key extends keyof Type>(obj: Type, key: Key) { console.log(obj[key]); return obj[key] }
let person = { name: 'jack', age: 18 } getProp(person, 'age') getProp([0], 0) getProp(18, 'toFixed') getProp('18', 0)
|
泛型接口
1 2 3 4 5 6 7 8 9 10 11 12 13
| interface IdFunc<Type> { id: (vale: Type) => Type ids: () => Type[] }
let obj: IdFunc<number> = { id(value) { return value }, ids() { return [1, 3, 5] } }
|
泛型类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class GenericNumber<NumType> { defaultValue: NumType add: (x: NumType, y: NumType) => NumType
} const myNum = new GenericNumber<number>() myNum.defaultValue = 10
class GenericNumber<NumType> { defaultValue: NumType add: (x: NumType, y: NumType) => NumType constructor(value: NumType){ this.defaultValue = value } } const myNum = new GenericNumber(1)
|
泛型工具类型
Partial
创建所有属性为可选的新类型
1 2 3 4 5
| interface Props { id: string children: number[] } type PartialProps = Partial<Props>
|
Readonly< Type >
创建所有属性为只读的新类型
1 2 3 4 5 6 7
| interface Props { id: string children: number[] } type ReadonlyProps = Readonly<Props> let props: ReadonlyProps = { id: '1', children: []} props.id = 11
|
Pick<Type, keys>
从Type中选择一组属性来构造新类型
1 2 3 4 5 6 7
| interface Props { id: string title: string children: number[] }
type PickProps = Pick<Props, 'id' | 'children'>
|
Record<key,Type>
构建一个对象类型,属性为keys 属性类型为Type
1 2 3 4 5 6
| type RecordObj = Record<'a' | 'b' | 'c', string[]> let obj: RecordObj = { a:['1'], b:['2'], c:['3'], }
|
类型声明文件
类型声明文件类型声明文件:用来为已存在的JS库提供类型信息。
1 2 3 4
| import {count,add} from './utils.js' console.log(count); console.log(add(1,2));
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| let count = 10 let songName = '22' let position = { x: 0, y: 0 }
function add(x,y){ return x + y }
function changeDirection(direction){ return direction }
const fomartPoint = point => { console.log('当前坐标:',point); }
module.exports = { count, songName, position, add, changeDirection, fomartPoint }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| declare let count: number declare let songName: string interface Point { x: number y: number } declare let position: Point
declare function add(x: number,y: number): number
declare function changeDirection(direction:'up'|'down'|'left'|'right'): void
type FomartPoint = (point: Point) => void
declare const fomartPoint: FomartPoint
export { count, songName, position, add, changeDirection, fomartPoint }
|