首页 > 其他分享 >TypeScript:带属性关联的泛型对象解构问题研究

TypeScript:带属性关联的泛型对象解构问题研究

时间:2022-12-13 21:55:35浏览次数:75  
标签:TypeScript ts 解构 key 泛型 foo type payload 属性

TypeScript:带属性关联的泛型对象解构问题研究

简介: ## 背景 ### 利用泛型进行属性关联 大家在业务中一定很熟悉这样的场景,针对某个action,传递一个指定类型的payload。 有了ts之后,我们会期望用泛型将action和payload的对应关系约束起来。 例如下面这段demo ``` typescript type Payloads = { people: { name: string, age: number };

背景

利用泛型进行属性关联

大家在业务中一定很熟悉这样的场景,针对某个action,传递一个指定类型的payload。
有了ts之后,我们会期望用泛型将action和payload的对应关系约束起来。
例如下面这段demo

type Payloads = {
  people: { name: string, age: number };
  machine: { id: string, price: number };
}
type Keys = keyof Payloads;

type Foo<T extends Keys, P> = {
  key: T;
  payload: P;
  info: string;
};
type AllFoos = { [K in Keys]: Foo<K, Payloads[K]> };
type AnyFoo = AllFoos[Keys];

11cb5d912244cc3374892f9e3991b021.png
这里我首先定义了action和payload结构关联的map,然后创建类型ALLFoos,利用泛型对象将action的key和对应的payload结构关联起来。最后输出的AnyFoo类型就是所有有效Foo类型的联合类型。

现在我就可以利用ts的类型检查,确保key和payload的关系约束了。

const makeFoo = (key: Keys): AnyFoo => {
  if (key === 'people') {
    return {
      key,
      payload: { name: 'xinyuehtx', age: 18 },
      info: '帅'
    }
  } else {
    return {
      key,
      payload: { id: '终结者', price: 998 },
      info: '莫得感情'
    }
  }
}

如果我们将“终结者”的属性名称改成“name”,ts就会帮我们报错
image.png

属性关联类型解构

那么现在问题来了,假如我要新增一个对外开放的API,要从Foo这个类型中去掉info属性,但是又不能改变Foo现有的结构。这个需求常见于内部方法对外开放时,去除一些隐私信息。毕竟面对第三方,˙终结者不希望别人知道他是一个莫得感情的机器,我也不希望别人发现我很帅。

第一时间我想到的方案如下,建立一个Bar类型,定义如Foo,但是去掉了info属性。
然后从foo对象中选取特定属性进行赋值。

type Bar<T extends Keys, P> = {
  key: T;
  payload: P;
};

type AllBars = { [K in Keys]: Bar<K, Payloads[K]> };
type AnyBar = AllBars[Keys];

const makeBarFromFoo = (foo: AnyFoo): AnyBar => ({
  key: foo.key,
  payload: foo.payload,
})

image.png
但是这里ts报错了。为什么呢?在这里,ts能够识别foo.key是一个'people'|'machine'的联合类型,foo.payload也是对应payload结构的联合类型,但是他们之间的关联丢失了。
ts不能消除people对应{id,price}的可能性。

解决方案

  • 通过as强转:
    这个是最偷懒的方案,直接跳过检查,通过人工约束。可行,但是非到万不得已不要用
  • 在实现代码中判断payload属性
const makeBarFromFoo = (foo: AnyFoo): AnyBar => {
  if (foo.key === 'people' && foo.payload.name && foo.payload.age) {
    return {
      key: foo.key,
      payload: foo.payload,
    }
  }
  //...剩余代码
}

这种方法对于小范围情况还可以,但是对于大量类型处理就会有点力不从心了

  • 终极方案rest解构
    这里我们的本质需求是从一个对象中获取关联的两个属性,且确保关联不丢失。这个需求换种思路,就是从指定对象中去除一些属性,返回剩余的。这个正好就是rest解构的场景。

所以就是如下的代码

const makeBarFromFoo = (foo: AnyFoo): AnyBar => {
  const { info, ...rest } = foo;
  return rest
}

image.png
ts识别也正常,没有报错


参考链接:

JavaScript 前端开发 API 网络架构 typescript对象 typescript组件 typescript属性 typescript变量声明 typescript变量 开发者社区 > 开发与运维 > 文章

标签:TypeScript,ts,解构,key,泛型,foo,type,payload,属性
From: https://www.cnblogs.com/sexintercourse/p/16980754.html

相关文章