TS 中的高级类型有很多,重点学习以下高级类型:
function id(value: number): number { return value }
function id(value: any): any { return value }
function id<Type>(value: Type): Type { return value }
function id<T>(value: T): T { return value }
<>
(尖括号),尖括号中添加类型变量,比如此处的 Typeconst num = id<number>(10)
const str = id<string>('a')
解释:
<>
(尖括号),尖括号中指定具体的类型,比如,此处的 number同样,如果传入类型 string,函数 id 参数和返回值的类型就都是 string
这样,通过泛型就做到了让 id 函数与多种不同的类型一起工作,实现了复用的同时保证了类型安全
// 省略 调用函数
let num = id(10)
let str = id('a')
解释:
<类型>
来简化泛型函数的调用推荐:使用这种简化的方式调用泛型函数,使代码更短,更易于阅读
说明:当编译器无法推断类型或者推断的类型不准确时,就需要显式地传入类型参数
function id<Type>(value: Type): Type {
console.log(value.length)
return value
}
id('a')
收缩类型
(缩窄类型取值范围)比如,将类型修改为 Type[]
(Type 类型的数组),因为只要是数组就一定存在 length 属性,因此就可以访问了
function id<Type>(value: Type[]): Type[] {
console.log(value.length)
return value
}
// 创建一个接口
interface ILength { length: number }
// Type extends ILength 添加泛型约束
// 解释:表示传入的 类型 必须满足 ILength 接口的要求才行,也就是得有一个 number 类型的 length 属性
function id<Type extends ILength>(value: Type): Type {
console.log(value.length)
return value
}
extends
关键字使用该接口,为泛型(类型变量)添加约束泛型的类型变量可以有多个,并且类型变量之间还可以约束(比如,第二个类型变量受第一个类型变量约束)
比如,创建一个函数来获取对象中属性的值:
function getProp<Type, Key extends keyof Type>(obj: Type, key: Key) {
return obj[key]
}
let person = { name: 'jack', age: 18 }
getProp(person, 'name')
,
逗号分隔。keyof Type
实际上获取的是 person 对象所有键的联合类型,也就是:'name' | 'age'
// Type extends object 表示: Type 应该是一个对象类型,如果不是 对象 类型,就会报错
// 如果要用到 对象 类型,应该用 object ,而不是 Object
function getProperty<Type extends object, Key extends keyof Type>(obj: Type, key: Key) {
return obj[key]
}
泛型接口:接口也可以配合泛型来使用,以增加其灵活性,增强其复用性
interface IdFunc<Type> {
id: (value: Type) => Type
ids: () => Type[]
}
let obj: IdFunc<number> = {
id(value) { return value },
ids() { return [1, 3, 5] }
}
<类型变量>
,那么,这个接口就变成了泛型接口。实际上,JS 中的数组在 TS 中就是一个泛型接口。
const strs = ['a', 'b', 'c']
// 鼠标放在 forEach 上查看类型
strs.forEach
const nums = [1, 3, 5]
// 鼠标放在 forEach 上查看类型
nums.forEach
Partial
Readonly
Pick
Omit
type Props = {
id: string
children: number[]
}
type PartialProps = Partial<Props>
type Props = {
id: string
children: number[]
}
type ReadonlyProps = Readonly<Props>
let props: ReadonlyProps = { id: '1', children: [] }
// 错误演示
props.id = '2'
interface Props {
id: string
title: string
children: number[]
}
type PickProps = Pick<Props, 'id' | 'title'>
Omit
K:是对象类型名称,T:是剔除K类型中的属性名称
绝大多数情况下,我们都可以在使用对象前就确定对象的结构,并为对象添加准确的类型。
使用场景:当无法确定对象中有哪些属性(或者说对象中可以出现任意多个属性),此时,就用到索引签名类型了。
interface AnyObject {
[key: string]: number
}
let obj: AnyObject = {
a: 1,
b: 2,
}
[key: string]
来约束该接口中允许出现的属性名称。表示只要是 string 类型的属性名称,都可以出现在对象中。key 只是一个占位符
,可以换成任意合法的变量名称。JS 中对象({})的键是 string 类型的
。interface MyArray<T> {
[n: number]: T
}
let arr: MyArray<number> = [1, 3, 5]
[n: number]
来作为索引签名类型。type PropKeys = 'x' | 'y' | 'z'
type Type1 = { x: number; y: number; z: number }
type PropKeys = 'x' | 'y' | 'z'
type Type2 = { [Key in PropKeys]: number }
Key in PropKeys
表示 Key 可以是 PropKeys 联合类型中的任意一个,类似于 forin(let k in obj)。映射类型除了根据联合类型创建新类型外,还可以根据对象类型来创建:
type Props = { a: number; b: string; c: boolean }
type Type3 = { [key in keyof Props]: number }
keyof Props
获取到对象类型 Props 中所有键的联合类型即,‘a’ | ‘b’ | ‘c’。Key in ...
就表示 Key 可以是 Props 中所有的键名称中的任意一个。type Partial<T> = {
[P in keyof T]?: T[P]
}
type Props = { a: number; b: string; c: boolean }
type PartialProps = Partial<Props>
keyof T
即 keyof Props 表示获取 Props 的所有键,也就是:‘a’ | ‘b’ | ‘c’。?
(问号),表示将这些属性变为可选
的,以此来实现 Partial 的功能。T[P] 表示获取 T 中每个键对应的类型
。比如,如果是 ‘a’ 则类型是 number;如果是 ‘b’ 则类型是 string。T[P]
语法,在 TS 中叫做索引访问类型
type Props = { a: number; b: string; c: boolean }
type TypeA = Props['a']
Props['a']
表示查询类型 Props 中属性 ‘a’ 对应的类型 number。所以,TypeA 的类型为 numbertype Props = { a: number; b: string; c: boolean }
type TypeA = Props['a' | 'b'] // string | number
type TypeA = Props[keyof Props] // string | number | boolean