【问题标题】:Typescript - How to get a subset of properties from an object into a variable based on an interfaceTypescript - 如何将对象的属性子集获取到基于接口的变量中
【发布时间】:2020-04-04 11:53:24
【问题描述】:

我有一个接收两种类型交集的函数:

interface A {
  propA: string;
}
interface B {
  propB: number;
  propC: boolean;
}
function C(props: A & B) {
}

现在,在函数体内,我想从每个接口获取仅包含属性子集的对象;所以我想知道 Typescript 是否有任何实用程序来实现这一点:

function C(props: A & B) {
  const a = fancyPicker<A>(props);
  const b = fancyPicker<B>(props);
  console.log(a);
  // prints "{ propA: "some string" }"
  console.log(b);
  // prints "{ propB: 42, propC: false }" 
}

【问题讨论】:

  • fancyPicker 不是类型系统的特性,而是Object.assign 的运行时包装器。您可以使用 keyofObject.keys 来执行此操作。
  • 但是keyof 什么?如果我通过道具成功,我会得到所有,A&B。
  • @JuanDelaCruz 这能回答你的问题吗? stackoverflow.com/questions/50839597/…
  • A &amp; B 是两种类型的intersection,而不是union
  • 不,正如您所写的那样,您的要求是不可能的。考虑fancyPicker&lt;A&gt;(props)fancyPicker&lt;B&gt;(props) 都将编译为相同的JavaScript 代码:fancyPicker(props)

标签: reactjs typescript


【解决方案1】:

您正在寻找一个迭代一组已知属性名称的函数 - 这不能在纯 TypeScript 中完成,因为 TypeScript 使用类型擦除,因此运行时脚本不知道属性名称集是什么是。

但是使用称为自定义转换器的 TypeScript 编译时扩展,specifically ts-transformer-keys TypeScript 编译器将发出可以使用的属性名称列表。

这里有一些可行的方法,但并不完美,因为它不使用每个属性的类型 - 它只匹配名称:

import { keys } from 'ts-transformer-keys'; // <-- This module is where the magic happens.

type IndexableObject = {
    [key: string]: any
};
/*
* The `IndexableObject` above is a hack. Note it allows `any` property type. Ideally it'd be something like this instead, but using `keyof` in a type indexer is not yet supported: https://github.com/microsoft/TypeScript/pull/26797
*

type IndexableObject<TOther> = {
    [key: TKey extends keyof TOther]: PropertyType<TOther,TKey>
};

*/

function fancyPicker<TSubset extends object>(superset: IndexableObject): Partial<TSubset> {

    const subsetPropertyNames = keys<TSubset>();

    const ret: Partial<TSubset> = {
    };

    for (const subsetPropertyName of subsetPropertyNames) {
        const propName: string = subsetPropertyName as string; // <-- This is also a hack because property keys/names are actually `string | number | symbol` - but this function assumes they're all named properties.
        if (propName in superset) {
            const value = superset[propName];
            ret[subsetPropertyName] = value;
        }
    }

    return ret;
}

用法(使用您的示例):

interface A {
  propA: string;
}

interface B {
  propB: number;
  propC: boolean;
}

type ABIntersection = A & B;
type ABUnion        = A | B;

function C(props: ABIntersection) {
  const a = fancyPicker<A>(props);
  const b = fancyPicker<B>(props);
  console.log(a);
  // prints "{ propA: "some string" }"
  console.log(b);
  // prints "{ propB: 42, propC: false }" 
}

const testValue = { propA: "some string", propB: 42, propC: false, propD: "never see this" };
C(testValue);

【讨论】:

  • 不幸的是,我无法访问 webpack 配置,因此 ts-transformer-keys 无法使用。尽管如此,还是非常感谢您。
猜你喜欢
  • 2021-07-10
  • 2020-01-12
  • 2020-08-08
相关资源
最近更新 更多