【问题标题】:Type safe iteration over type properties类型属性上的类型安全迭代
【发布时间】:2021-10-29 09:54:20
【问题描述】:

我需要对SomeType 类型属性有一个迭代器。 Object(instance) 不行,因为它返回 string[] 而不是 Array<keyof SomeType>。下面的函数解决了问题

export function keysof<T>(obj: Partial<Record<keyof T, any>>): Array<keyof T> {
    return Object.keys(obj) as Array<keyof T>;
}

我真正不喜欢这里的是obj 参数似乎是多余的,因为类型应该足以获取它的属性。我希望能够执行以下操作

export function keysof<T>(): Array<keyof T> {
    return Object.keys(T) as Array<keyof T>;
}

但显然这会抛出 'T' only refers to a type, but is being used as a value here 编译错误。

是否可以避免将SomeType 实例传递给函数?

【问题讨论】:

  • 为了调用Object.keys,你应该有一个对象。因此,您 have 将此对象作为参数传递给 keysof 函数。泛型类型T 在编译后被删除。这意味着您正在尝试这样做:Object.keys()。您对此有何期待?
  • seem to be redundant - 这不是真的。 obj 参数是 required
  • @captain-yossarian 好点。当我说冗余时,我的意思是我们只使用obj 的类型,因此我们实际上将类型传递了两次。但是,是的,你是对的,T 只存在于 ts 编译之前,所以看起来不可能删除这个“冗余”
  • “我们实际上将类型传递了两次”是什么意思?两次在哪里?你的意思是declare function f&lt;T&gt;(x: T): void; 提到T 两次?如果是这样,请注意x =&gt; x * 3 两次提到x,但您不会称其为“冗余”,当然也不能用x =&gt; * 3 替换它。还是你的意思是别的?
  • @jcalz 早上好:D

标签: typescript


【解决方案1】:

为了调用Object.keys,你应该有一个对象。

因此,您必须将此对象作为参数传递给keysof 函数,如下所示:

const keysof=<T,>(obj: T) => Object.keys(obj) as Array<keyof T>;

泛型类型 T 在编译后被删除。

表示如果你想去掉obj参数,只留下T,像这样:

const keysof = <T,>() => Object.keys() as Array<keyof T>;

你最终会得到这个:

const keysof = () => Object.keys();

因此,您只能摆脱显式返回类型,如下所示:

export function keysof<T>(obj:T) {
    return Object.keys(obj) as Array<keyof T>;
}

我认为您应该注意Array&lt;keyof T&gt; 的缺点。因为它允许您在数组中使用重复项。考虑这个例子:

const obj = { age: 42, name: 'John' }

const keys: Array<keyof typeof obj> = ['age', 'age', 'age'] // no compilation error

这是你想要的吗?我不这么认为。因为Object.keys 不能在结果数组中产生重复。

还有另一种方法。它也有自己的缺点:)

// credits goes to https://twitter.com/WrocTypeScript/status/1306296710407352321
type TupleUnion<U extends string, R extends any[] = []> = {
  [S in U]: Exclude<U, S> extends never ? [...R, S] : TupleUnion<Exclude<U, S>, [...R, S]>;
}[U];


const obj = { age: 42, name: 'John' }

const keys: TupleUnion<keyof typeof obj> = ['age', 'age', 'age'] // error

如您所料,上述代码会导致编译错误。 但是您也可以在您的 PC/笔记本电脑上烧一些水,因为它会消耗 CPU 资源。它也有自己的递归限制。

Here你可以找到TupleUnion类型实用程序的逐步解释

TL;TR

TupleUnion - 产生所有可能的Object.keys 结果的排列

【讨论】:

    猜你喜欢
    • 2013-10-29
    • 2020-07-09
    • 2013-07-10
    • 1970-01-01
    • 2011-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-16
    相关资源
    最近更新 更多