interface接口
- 对对象形状(shape)进行描述:属性、方法进行描述
- 对class进行抽象:面向对象语言中,对class进行抽象,具体功能要类自己去实现
- duck typing(鸭子类型):某个东西长得像鸭子,能像鸭子一样走路游泳嘎嘎叫,就可以被看做是鸭子,主要关注对象怎么被使用,而不是类型本身
新鲜度的问题,其实就是你如果直接用字面量,那么这个字面量每次都是新的,不是引用,而是新的内存,如果你用一个变量,相当于是一个指针/引用,没有新鲜度,所以不会报错。
注意可选属性的作用,可以用在这里。
函数 + 类型推断
枚举:
默认从零开始
默认从0开始,如果我人为不从0开始呢
编译出如下结果
如果这么搞:
编译结果如下:
字符串枚举
编译如下:
常量枚举:
多了个const,但是我们看看编译后的代码:太简洁了。直接把值翻译成结果,提升了性能。
枚举的值有两种类型:一种是常量值,一种是计算值 ,只有常量值可以进行常量枚举。
泛型:Generics
function echo(arg) {
console.log(arg)
}
const res = echo(123)
// 上面没法控制res的类型啊,等于是参数是any,返回是any,
// 而且两个any可以不一样,不过后面的版本TS自动修复了这个问题
function echo<T>(arg: T): T{
console.log(arg)
return arg
}
const n: number = 12
const res = echo(n)
function echo<T>(arg: T): T{
console.log(arg)
return arg
}
// const n: number = 12
// const res = echo(n)
// 其实可以类型推断
const res = echo(12)
上图中,res[1]已经变为'string'了,具有String类型的所有方法。
约束泛型
前面讲的比较简单,都是参数和返回值的一些简单用法,那么泛型使用的地方还很多,比如用到类上。实现如下场景:进入队列、离开队列。
但是,我们如果某天不是用number类型了,而是使用string类型。那么我们还有修改很多代码。这是不合理的,现在我们约束push什么类型,pop出来就什么类型,保持一致。创建一个泛型类。
const queue2 = new Queue<string>()
queue2.push('hello')
console.log(queue2.pop().length)
上面的类可以用泛型描述,那么interface也可以用泛型描述
interface KeyPair<T, U> {
key: T
value: U
}
let kp1: KeyPair<number, string> = { key: 100, value: 'hello' }
let kp2: KeyPair<string, number> = { key: 'test', value: 211 }
interface KeyPair<T, U> {
key: T
value: U
}
let kp1: KeyPair<number, string> = { key: 100, value: 'hello' }
let kp2: KeyPair<string, number> = { key: 'test', value: 211 }
// 下面就是我们很眼熟的操作了
let arr: number[] = [1, 2, 3]
let brr: Array<number> = [1, 2, 3]
还可以用interface来描述函数的type
function plus(a: number, b: number): number {
return a + b
}
function connect(a: string, b: string): string {
return a + b
}
// 我们可以用interface来描述这个函数的类型
interface IPlus {
(a: number, b: number): number // 描述了一个函数类型
}
// 更进一步,加个参数
interface IPlus1<T> {
(a: T, b: T): T
}
const b: IPlus1<number> = plus
const c: IPlus1<string> = connect
上面就很灵活了。
类型别名
// 类型别名 type aliases 给类型起个别名
function sum(x: number, y: number): number {
return x + y
}
// 假设有个sum2等于sum,虽然直接下面写法就可以了,可以直接推断出来
const sum2 = sum
// 但是,如果要手动显示写sum2的类型,就要写半天麻烦
const sum3: (x: number, y: number) => number = sum
// 为了解决这个问题,就有了类型别名,用关键字type
type PlusType = (x: number, y: number) => number
const sum4: PlusType = sum
// 再看一个场景:参数n可能是字符串类型,直接返回,也可能是函数,返回函数的执行结果。类型别名
type NameResolver = () => string
type NameOrResolver = string | NameResolver
function getName(n: NameOrResolver): string {
if (typeof n === 'string') {
return n
} else {
return n()
}
}
类型断言 type assertion
当ts不确定一个联合类型的变量,到底是哪个类型的时候,我们只能访问此联合类型的共用的属性和方法,有时候在还不确定类型的时候,就要访问其中一个类型的属性和方法。
联合类型,只能访问共同部分,上面string | number 的联合体,string有length,number没有,你就贸然用input.length,很可能纠错了,所以ts直接阻止了这么做。
这个时候采用类型断言。
function getLength(input: string | number): number {
const str = input as String
if (str.length) {
return str.length
} else {
const number = input as Number
return number.toString.length
}
}
function getLength1(input: string | number): number {
// 在要断言的变量前添加一个尖括号,语法要记住
if((<string>input).length) {
return (<string>input).length
} else {
return input.toString().length
}
}
// 类型断言不是类型转换,你要是把它断言成联合类型中不存在的类型,那也是不行的
// 比如 input是 string | number,你要是把它断言成boolean那肯定不行