函数类型数组
接口(interface)缓存
类app
类成员访问修饰符(public/private/protected)函数
类与接口post
抽象类学习
泛型this
函数的输入和输出进行约束,及参数和返回值spa
// 参数的类型和返回值的类型 function func1(a: number, b: number): string { return 'func1' } // 参数类型和个数是固定的,不然报错 func1(100, 200)
// 普通函数 const func4 = function (a: number, b: number): string { return 'func2' } // 使用箭头函数 const func5: (a: number, b:number) => string = function(a, b) { return 'func2' }
可选参数必定要在必选参数后面,放在函数最后。rest
// 能够在b后面添加问号表示可选,也能够直接设置默认值,也能够不用传 function func2(a: number, b: number = 10, c?: number): string { return 'func1' } func1(100)
使用ES6
的rest
操做符code
function func3(a: number, b: number = 10, ...rest: number[]): string { return 'func1' } func1(100,200,300,400)
接口,是一种规范、契约,约定对象的结构。
接口是用来约束一个对象的结构,咱们要使用这个接口,就要遵循其所有的约定。
接口最直观的体现就是对象应该有哪些成员以及成员的类型都是什么样的?
// 定义一个接口,里面肯定要有两个成员,且都是字符串类型 interface Post { title: string // 结尾能够使用逗号分隔,也能够使用分号去分割,还能够省略 content: string }
// 使用的时候声明参数是Post类型,里面使用的时候不担忧没有值 function printPost (post: Post) { console.log(post.title) console.log(post.content) } // title和content任何一个没有传或者不是字符串都会报错 printPost({ title: 'this is a title', content:'this is a content' })
interface Post { title: string content: string subtitle?: string // 可选成员,无关紧要,string or undefined } // 下面不传subtitle不会报错 const hello: Post = { title: 'this is a title', content:'this is a content' }
readonly
关键词,一经定义不能修改interface Post { title: string content: string subtitle?: string readonly summary: string //只读成员,一经定义不能更改 } const hello: Post = { title: 'this is a title', content:'this is a content', summary: 'this is a summary' } hello.summary = 'hello' // 报错
由于不知道有哪些成员名称,因此Cache
里面使用[]
,指定键prop
的类型是string
,值的类型是number
interface Cache { [prop: string] : number } const cache: Cache = {} cache['hello'] = 1 cache['hi'] = 2
类用来描述一类具体事物的抽象特征。TypeScript
加强了class
的相关语法,访问修饰符以及抽象类的概念等...
下面看一下TypeScript
新增的内容:
目的是为了给属性和方法作类型标注
class Person { // 须要对类的属性进行声明,能够添加默认值,也能够不添加 // 二者有一个没有写,都会报错 name: string = 'init name' age: number constructor (name: string, age: number) { // 若是不加声明,这里直接使用会报错,由于在TypeScipt须要明确属性,而不是动态添加 this.name = name this.age = age } // 方法这些和以前是同样的,也要添加类型注解 sayHi (msg: string): void { console.log(`I am ${this.name}, ${msg}`) } run (): void { this.sayHi('I am happy!') } }
- | public | private | protected |
---|---|---|---|
内部访问 | 可 | 可 | 可 |
外部访问 | 可 | 不可 | 不可 |
子类访问 | 可 | 不可 | 可 |
class Person { // 默认是public,加不加效果同样,建议去加 public name: string = 'init name' // age属性是个私有属性,私有属性能够在函数内部经过this.age去访问 private age: number // 受保护的,外界成员不可访问,子类成员能够访问 protected gender: boolean constructor (name: string, age: number) { this.name = name this.age = age this.gender = true } sayHi (msg: string): void { console.log(`I am ${this.name}, ${msg}`) console.log(this.age) //本身内部访问私有属性是没有问题的 console.log(this.gender) //本身内部访问受保护属性是没有问题的 } }
const xm = new Person('xm', 18) console.log(xm.name) console.log(xm.age) // 报错,Property 'age' is private and only accessible within class 'Person' console.log(xm.gender) // 报错,Property 'gender' is protected and only accessible within class 'Person' and its subclasses.
//定义一个Student类继承Person class Student extends Person { constructor(name: string, age: number) { super(name, age) console.log(this.gender) console.log(this.age) // 报错,私有成员不能访问 console.log(this.name) } }
private
: 若是类的构造函数被私有化,那么不能被实例化和继承,这个时候只能在这个类的内部添加一个静态方法,经过静态方法添加实例。protected
: 若是类的构造函数被受保护,那么不能实例化,可是能够继承。class Student extends Person { private constructor(name: string, age: number) { super(name, age) console.log(this.gender) console.log(this.name) } // 能够定义一个方法内部实例化 static create (name: string, age: number) { return new Student(name, age) } } const xm = Student.create('xm', 18) console.log(xm.name)
在属性前添加修饰符readonly
,若是有访问修饰符,那么就跟在修饰符的后面.只读属性必须在声明时或构造函数里被初始化。
class Person { public name: string = 'init name' private age: number // 若是有访问修饰符,那么就跟在修饰符的后面 protected readonly gender: boolean constructor (name: string, age: number) { this.name = name this.age = age this.gender = true } sayHi (msg: string): void { console.log(`I am ${this.name}, ${msg}`) console.log(this.gender = false) // Cannot assign to 'gender' because it is a read-only property. } run (): void { this.sayHi('I am happy!') } } let xm = new Person('xm', 18) xm.gender = 'false' // 报错
类与类之间的公共特征通常会用接口去抽象
好比下面两个不一样的类,可是都有eat
和run
两个相同的方法,能够用接口约束两个类中公共的部分
class Person { eat (food: string): void { console.log(`优雅进餐:${food}`) } run (distance: number) { console.log(`直立行走:${distance}`) } } class Animal { eat (food: string): void { console.log(`不优雅进餐:${food}`) } run(distance: number) { console.log(`爬行:${distance}`) } }
// 能够定义一个接口实现一个能力,而后让一个类实现多个接口 interface Eat { eat (food: string): void } interface Run { run (distance: number): void }
// Person和Animal要实现接口,若是里面少了接口对应的方法,就会报错。 class Person implements Eat, Run{ eat (food: string): void { console.log(`优雅进餐:${food}`) } run (distance: number) { console.log(`直立行走:${distance}`) } } class Animal implements Eat, Run{ eat (food: string): void { console.log(`不优雅进餐:${food}`) } run(distance: number) { console.log(`爬行:${distance}`) } }
// 添加abstract关键词以后就成为了抽象类 abstract class Animal { eat (food: string): void { console.log(`不优雅进餐:${food}`) } // 抽象类中能够定义一些抽象方法,也须要关键词abstract abstract run (distance: number): void }
class Dog extends Animal { // 能够在VSCode环境点击Dog使用快速修复自动生成代码实现 // 这里实现了抽象类中的run抽象方法 run(distance: number): void { console.log('爬行', distance) } } // 子类实例化 const d = new Dog() d.eat('粮食') d.run(100)
咱们在定义函数、接口或者类的时候没有去指定类型,只有当使用的时候才去指定类型的一种特征。
其目的 就是为了极大程度复用咱们的代码
举个例子:
下面是传入长度和值,返回一个数组
// 参数长度是number类型,value是number类型,返回的是number类型的数组 function createArray (length: number, value: number): number[] { const arr = Array<number>(length).fill(value) return arr } // 下面传入参数能够得到三个值为100的数字类型的数组 const res = createArray(3, 100) // res => [100, 100, 100]
上面的代码有个缺陷是只能返回数字类型的数组,若是换成其余类型就会报错,如何进行修改?
T
做为名称,函数中不明确的类型都用T
去表明function createArray <T> (length: number, value: T): T[] { const arr = Array<T>(length).fill(value) return arr }
// 下面能够填充字符串类型或者数字类型均可以 const res = createArray<string>(3, 'foo') const res1 = createArray<number>(3, 100)
总结 就是泛型参数将定义时不能明确的参数用一个T
来代替,使用的时候指定T
的类型