Appearance
🌰 比如我们经常会碰到一些接口数据类型定义:
typescript
export type SubmitRequest = {
  personal: {
    title: string;
    previousAliases: {
      firstName: string;
      lastName: string;
    }[]
  },
  payment: {
    cardToken: string;
  }
}我们在应用中某个地方,需要使用 部分 数据类型,比如:
typescript
export function getPayment() {
  return {
    // 这里实际想要写的是 carToken 不小心写错为了 carTokens
    cardTokens: 'xxxaee' 
  }
}这里我们想要的是 {cardToken: string} 类型,即 SubmitRequest 类型中 payment 对应的类型,但是因为没有类型验证,我们这里可能不小心将其写为了 cardTokens。于是我们可能定义一个 Payment 类型:
typescript
type Payment = {
  cardToken: string
}
export function getPayment(): Payment {
  return {
    // ❌ 不能将类型 {cardTokens: string} 分配给 类型{cardToken: string}
    cardTokens: 'xxxaee' 
  }
}通过这种方式虽然可以解决这个问题,但是这里存在2个问题🤔:
- 有可能我们只需要在 getPayment这一个地方使用到Payment这个类型,只为了这一个地方用到的类型,而创建一个新的类型,可能会产生Type Noises(类型杂音)
- 这里的 Payment类型和SubmitRequest相关联的,如果SubmitRequest中的类型发生了变化,还要将Payment类型进行同步修改,这会造成重复
可以通过TypeScript Lookup Types 功能,直接从其它类型或Interface中派生出新的类型:😎
typescript
export function getPayment(): SubmitRequest['payment'] { 
  return {
    // ❌ 不能将类型 {cardTokens: string} 分配给 类型{cardToken: string}
    cardTokens: 'xxxaee' 
  }
}这里直接使用 SubmitRequest['payment'] lookup types方式生成一个新的类型🎉。
如果我们需要复用这个类型,我们可以将其赋值给另一个类型:
typescript
type Payment = SubmitRequest['payment']另外还可以对上面的 previousAliases 数组类型进行类型提取:
typescript
// 等价于 type Alias = {firstName: string; lastName: string;}
type Alias = SubmitRequest['personal']['previousAliases'][number] // better
// 或者
type Alias = SubmitRequest['personal']['previousAliases'][0]      // OKWARNING
针对UP主提出的 Type Noises,该视频评论区有人觉得,使用子类型(subtypes)的方式更加的合理,即额外的定义 Payment & Alias:
typescript
// 子类型
type Payment = {
  cardToken: string;
}
// 子类型
type Alias = {
  firstName: string;
  lastName: string;
}
// 组合成大的类型
export type SubmitRequest = {
  personal: {
    title: string;
    previousAliases: Alias[];
  },
  payment: Payment;
}而 Lookup types 功能,则 只在基类来自外部库的时候使用😎。
对于这种观点,UP表示很赞成。
我个人也觉得这一观点比较正确,但是知道Lookup types这一特性也很重要。
关于 Lookup 类型可参考:
视频地址:
2022年11月25日11:56:54