Mal*_*ter 18 typescript typescript-generics
用于打字Object.entries
的打字稿提供具有返回类型[string, T][]
,但是我正在寻找一个泛型类型Entries<O>
来表示这个功能,保持键和值之间的关系的返回值。
例如。当有一个对象类型时
type Obj = {
a: number,
b: string,
c: number
}
Run Code Online (Sandbox Code Playgroud)
我正在寻找一种类型Entries<O>
,当提供时会产生以下类型之一(或类似的东西)Obj
:
(["a", number] | ["b", string] | ["c", number])[]
[["a", number], ["b", string], ["c", number]]
(["a" | "c", number] | ["b", string])[]
Run Code Online (Sandbox Code Playgroud)
这对于 Object.entries 的所有用例(请参阅此处)并不正确,这对我的特定情况来说是没有问题的。
尝试和失败的解决方案:
type Entries<O> = [keyof O, O[keyof O]][]
不适合这个工作,因为它不仅保留了可能键和值而不是这些作为之间的关系Entries<Obj>
是["a" | "b" | "c", number | string]
。
type Entry<O, K extends keyof O> = [K, O[K]]
type Entries<O> = Entry<O, keyof O>[]
Run Code Online (Sandbox Code Playgroud)
这里的定义Entry
按预期工作,例如。Entry<Obj, "a">
是["a", number]
但它在第二行中的应用程序具有keyof O
相同的结果作为第一个尝试为第二类型可变引线一次。
kay*_*ya3 24
这是一个解决方案,但在使用它作为;的返回类型时要小心Object.entries
。这样做并不总是安全的(见下文)。
当您想将每个键与依赖于该键类型的东西配对时,请使用映射类型:
type Entries<T> = {
[K in keyof T]: [K, T[K]];
}[keyof T][];
type Test = Entries<Obj>;
// (["a", number] | ["b", string] | ["c", number])[]
Run Code Online (Sandbox Code Playgroud)
第二个版本具有包含属性而不是联合的元组类型,构造起来要困难得多;可以将联合转换为元组,但您基本上不应该这样做。
第三个版本易于管理,但比第一个版本复杂一些:您需要PickByValue
从这个答案中获取。
type Entries3<T> = {
[K in keyof T]: [keyof PickByValue<T, T[K]>, T[K]]
}[keyof T][];
type Test3 = Entries3<Obj>;
// (["a" | "c", number] | ["b", string])[]
Run Code Online (Sandbox Code Playgroud)
我想我还应该解释为什么 Typescript没有给Object.entries
. 当你有一个像type Obj = {a: number, b: string, c: number}
这样的类型时,它只能保证一个值具有这些属性;它不保证该值不也有其他属性。例如,该值{a: 1, b: 'foo', c: 2, d: false}
可分配给类型Obj
(不考虑对象文字的额外属性检查)。
在这种情况下,Object.entries
将返回一个包含元素的数组['d', false]
。类型Entries<Obj>
说这不可能发生,但实际上它可能发生;soEntries<T>
不是一般的声音返回类型Object.entries
。只有Object.entries
当您自己知道这些值不会有多余的属性时,才应该使用上述解决方案;Typescript 不会为你检查这个。
Pet*_*nas 23
目前,已经引入了一个名为type-fest的非常好的实用程序库,以Entries
. 你可以像这样使用它:
import { Entries } from 'type-fest';
Object.entries(obj) as Entries<typeof obj>;
Run Code Online (Sandbox Code Playgroud)
编辑:如果您希望 Object.entries 默认具有此类型:
declare global {
interface ObjectConstructor {
entries<T extends object>(o: T): Entries<T>
}
}
Run Code Online (Sandbox Code Playgroud)
Rob*_*ell 15
我坚信这篇文章的答案应该是本页上两个答案的组合:
type Entries<T> = {
[K in keyof T]: [K, T[K]];
}[keyof T][];
Run Code Online (Sandbox Code Playgroud)
来自@kaya3
和
const getEntries = <T extends object>(obj: T) => Object.entries(obj) as Entries<T>;
Run Code Online (Sandbox Code Playgroud)
来自@minlare
谢谢你们两位的精彩回答。
// utils/objectEntries.ts
export { objectEntries }
// /sf/ask/4209937231/#75337277
type ValueOf<T> = T[keyof T]
type Entries<T> = [keyof T, ValueOf<T>][]
// Same as `Object.entries()` but with type inference
function objectEntries<T extends object>(obj: T): Entries<T> {
return Object.entries(obj) as Entries<T>
}
Run Code Online (Sandbox Code Playgroud)
根据 Peter Cardenas 的回答,我还创建了一个辅助函数
const getEntries = <T extends object>(obj: T) => Object.entries(obj) as Entries<T>;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
11344 次 |
最近记录: |