胖蔡说技术
随便扯扯

TypeScript高级类型详解

当了解到Typescript的基础类型外,在开发过程中,为了应对多变的复杂场景,我们需要了解一下typescript的高级类型。所谓高级类型,是typescript为了保证语言的灵活性,所使用的一下语言特性。这些特性有助于我们应对复杂多变的开发场景。

一、交叉类型

将多个类型合并成一个类型,新的类型将具有所有类型的特性,所以交叉类型特别适用对象混入的场景。

interface Dog{
    run():void
}
interface Cat{
    jump():void
}
let pet:Dog & Cat={
    run(){},
    jump(){}
}

二、联合类型

声明的类型并不确定,可以为多个类型中的一个

let a:number| string='111';
 //限定变量的取值
let ba:'a' | 'b' | 'c';  //字符串的字面量联合类型
let ca:1|2|3 ;  //数字的联合类型

对象的联合类型

interface Dogs{
    run():void
}
interface Cats{
    jump():void
}
class dog implements Dogs{   //类实现接口
   run(){}
   eat(){}
}
class cat implements Cats{
    jump(){}
    eat(){}
}
enum Master {Boy,Girl};
 function getPet(master:Master){
    let pet=master===Master.Boy?new dog() : new cat();   
    //pet被推断为dog和cat的联合类型
    //如果一个对象是联合类型,在类型未确定的时候,他就只能访问所有类型的共有成员,所以能访问eat()
    pet.eat();
    pet.run();  //报错
    return pet;
}

三、索引类型

let obj = {
    a: 1,
    b: 2,
    c: 3
}
// 获取对象中的指定属性的值集合
function getValues(obj: any, keys: string[]) {
    return keys.map(key => obj[key])
}
// 抽取指定属性的值
console.log(getValues(obj, ['a','b']))  // [1, 2]
// 抽取obj中没有的属性:
console.log(getValues(obj, ['e','f']))  // [undefined, undefined]

虽然obj中并不包含e, f属性,但typescript编译器并未报错。此时使用typescript索引类型,对这种模式做类型约束。

keyof

keyof是索引类型查询操作符。

假设T是一个类型,那么keyof T产生的类型是T的属性名称字符串字面量类型构成的联合类型。

特别说明:T是数据类型,并非数据本身。

// 定义一个接口Obj含有属性a,b
interface obj {
    a: number
    b: string
}
// 定义变量key,类型为keyof Obj
let key: keyof obj

T是一个类型,T[K] 表示类型T中属性K的类型

interface obj {
  a: number
  b: string
}
// 定义变量key,类型为keyof Obj
let key: keyof obj

let value:obj['a']

所以上面的代码可以这样改造

function getValues<T, K extends keyof T>(obj: T, keys: K[]): T[K][] {
    return keys.map(key => obj[key])
}

let obj = {
    a: 1,
    b: 2,
    c: 3
}

// 抽取指定属性的值
console.log(getValues(obj, ['a','b']))  // [1, 2]
// 抽取obj中没有的属性:
console.log(getValues(obj, ['e','f']))  // [undefined, undefined]

四、映射类型

typescript 允许将一个类型映射成另外一个类型

Readonly

Readonly是 typescript 内置的泛型接口,可以将一个接口的所有属性映射为只读:

// 定义接口Obj
interface Obj {
    a: number
    b: string
    c: boolean
}
// 使用类型别名定义类型ReadonlyObj
type ReadonlyObj = Readonly<Obj>    // Readonly是TS内置的泛型接口

node_module/typescript/lib/lib.es5.d.ts 中可以看到 typescript 内部是如何实现 Readonly 的

type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};

从源码可以看出Readonly是一个可索引类型的泛型接口

1、索引签名为P in keyof T :

其中keyof T就是一个一个索引类型的查询操作符,表示类型T所有属性的联合类型

2、P in :

相当于执行了一个for in操作,会把变量P依次绑定到T的所有属性上

3、索引签名的返回值就是一个索引访问操作符 : T[P] 这里代表属性P所指定的类型

4、最后再加上Readonly就把所有的属性变成了只读,这就是Readonly的实现原理

Partial

将一个接口的所有属性映射为可选:

interface Obj {
  a: number
  b: string
  c: boolean
}
type PartialObj = Partial<Obj>

Record

Record会利用已有的类型,创建新属性的映射类型

interface Obj {
  a: number
  b: string
  c: boolean
}
type RecordObj = Record<'x' | 'y', Obj>

第一个参数是预定义的新属性,比如x,y

第二个参数就是已知类型

五、条件类型

条件类型是一种由条件表达式所决定的类型 。条件类型使类型具有了不唯一性,同样增加了语言的灵活性


T extends U ? X : Y
若类型T可被赋值给类型U,那么结果类型就是X类型,否则就是Y类型
// 条件类型
type TypeName<T> = 
    T extends string ? 'string' :
    T extends number ? 'number' :
    T extends boolean ? 'boolean' :
    T extends undefined ? 'undefined' :
    T extends Function ? 'Function' :
    'object'

// 定义类型T1为条件类型,传入参数string,指定t1为string类型
type T1 = TypeName<string>  // T1为 string
// 定义类型T2为条件类型,传入参数string[]
type T2 = TypeName<string[]>  // T2为 object
赞(0) 打赏
转载请附上原文出处链接:胖蔡说技术 » TypeScript高级类型详解
分享到: 更多 (0)

请小编喝杯咖啡~

支付宝扫一扫打赏

微信扫一扫打赏