typescript类型体操--提取对象中指定类型的属性

#导读

今天有群友提问说如何用typescript类型推断返回对象里类型是number的属性,本文就要研究一下这个类型的思路。

分析

其实是要实现这样一个类型:

ts 复制代码
type FilterKey<Obj extends Record<string, any>,T>
​
const student ={
    age:12,
    class:'6(1)',
    name:'Lihua',
    seat:23
}
​
type Result= FilterKey<typeof student, number> // [age,seat]

首先keyof关键字 可以在类型推断里取到对象的属性。

而使用in关键字实现遍历,且遍历后得到一个新的类型。

由于需要指定某个属性T作为约束条件,那就需要使用extends关键字。

在这里已经可以看到,属性为number经过重映射后其value为本身,否则为never。我们应该处理就是过滤出新对象里value不是value的key。

上面已知道keyof可以取出属性值作为元组返回,我们在上面的结果后加上它。

这里大概就是按[]内的Union类型以此取对应的值,再组成新的Union类型,其实和对象取值差不多。应该返回的是"age"|never|never|"seat"

但是联合类型里的never会被干掉,因为never表示不存在的意思(绝不啊,绝对不会存在的类型,也就是压根不存在)。

(PS:随便帮大家区分never、unknown、null。null是空,啥也没有;unknown是不知道是 number、string等中的哪一个,但肯定是其中一个;never就是不存在,不会有。)

这几乎是我们需要的结果了,接下来我们需要将Union类型转为Tuple类型:

ts 复制代码
type UnionToIntersection<U> =(U extends any? (a:(k:U)=>void)=>void : never) extends (a: infer I ) => void ? I :never
type UnionLast<U> = UnionToIntersection<U> extends (a: infer I)=>void ? I :never;
type UnionToTuple<U> = [U] extends [never] ? [] : [...UnionToTuple<Exclude<U, UnionLast<U>>>,UnionLast<U>]

最终结果:

ts 复制代码
type FilterKey<Obj extends Record<string, any>,T>={
    [K in keyof Obj]: Obj[K] extends T ? K:never
}[keyof Obj]

所有的代码如下自取:

ts 复制代码
const student ={
    age:12,
    class:'6(1)',
    name:'Lihua',
    seat:23
}
​
type UnionToIntersection<U> =(U extends any? (a:(k:U)=>void)=>void : never) extends (a: infer I ) => void ? I :never
type UnionLast<U> = UnionToIntersection<U> extends (a: infer I)=>void ? I :never;
type UnionToTuple<U> = [U] extends [never] ? [] : [...UnionToTuple<Exclude<U, UnionLast<U>>>,UnionLast<U>]
​
type FilterKey<Obj extends Record<string, any>,T>={
    [K in keyof Obj]: Obj[K] extends T ? K:never
}[keyof Obj]
​
type FilterKey2<Obj extends Record<string, any>,T> =UnionToTuple<FilterKey<Obj, T>>
​
type Result= FilterKey<typeof student, number>
​
type Result2 = FilterKey2<typeof student, number >

补充

如果T传入的属性是多个的话(假设以元组的形式传入),那么就不适合了,为此,利用类型推断可以递归的特性,可以得到:

ts 复制代码
type MultiFilterKey<Obj extends Record<string, any>,T> = T extends [infer First,...infer Rest] ?[
      ...FilterKey2<Obj, First>,...MultiFilterKey<Obj, Rest>
    ]
:FilterKey2<Obj, T>

小结

我们先是实现了对象类型的重新构造,利用extends约束区分了需要的部分属性,并巧妙地利用never和任意类型联合得到这一任意类型本身的特性,"过滤"得出我们需要的结果。

相关推荐
晓说前端34 分钟前
TypeScript 核心语法进阶 —— 字面量类型与类型推论
前端·typescript
布兰妮甜4 小时前
从 0 搭建企业级 Vue3/Vite 脚手架(规范、eslint、husky、打包、环境变量全流程)
typescript·vue3·vite·脚手架·前端工程化
东方小月5 小时前
从0开发一个 Coding Agent(一):前言
前端·人工智能·typescript
gis开发之家1 天前
《Vue3 从入门到大神35篇》Vue3 源码详解(五):effect 依赖收集原理——track 与 trigger 是如何工作的?
javascript·typescript·前端框架·vue3·vue3源码
退休倒计时1 天前
【每日一题】LeetCode 131. 分割回文串 TypeScript
算法·leetcode·typescript
橘子星2 天前
在浏览器里跑大模型!用 WebGPU 零成本部署 DeepSeek-R1
前端·typescript
bonechips2 天前
React + WebGPU:在浏览器里跑一个 DeepSeek 推理模型
react.js·typescript
触底反弹3 天前
🔥 React 零基础入门(上):环境搭建 + JSX 深度解析
前端·react.js·typescript
谷哥的小弟3 天前
TypeScript对象类型
javascript·typescript
大家的林语冰3 天前
🫡 见证历史,TypeScript 7 重写成功,VS Code 原地起飞,GitHub 第一语言联手 Go 破而后立!
前端·javascript·typescript