本文介绍了泛型打字稿:来自keyof T值的泛型类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何从TSource和给定的属性名称(TSource的键)推断结果类型(TTarget)?

How can I infer the result type (TTarget) from TSource and the given property names (keyof TSource)?

我具有以下功能,可将定义的属性复制到新对象中:

I've the following function to copy defined properties to a new object:

export declare type PropertyNamesOnly<T> = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T];

CopyProps<TSource, TTarget>(source: TSource, ...props: PropertyNamesOnly<TSource>[]): TTarget {
    const result: any = {};
    for (const prop of props) {
      result[prop] = source[prop];
    }
    return result;
}

现在,我可以像这样使用它:

Now I can use it like that:

class Props { a: string = "a"; b: string = "b"; c: string = "c"; }
const props = new Props();

const copy = CopyProps<Props, Omit<Props, "b">>(props, "a", "c");

expect(copy.a).to.equal("a");
// copy has omitted property b
expect((copy as any).b).to.be.undefined;
expect(copy.c).to.equal("c");

但是我不想定义TSource和TTarget.我想要这个:

But I don't want to define TSource and TTarget. I want this:

CopyProps<TSource>(source: TSource, ...props: PropertyNamesOnly<TSource>[]): TypeFromProps<props> {
    const result: any = {};
    for (const prop of props) {
      result[prop] = source[prop];
    }
    return result;
}

// Then copy should contains only property a and c
const copy = CopyProps(props, "a", "c");

如何获取TypeFromProps类型?

How can I get the type TypeFromProps?

解决方案:

static PickProps<
  TSource,
  Props extends PropertyNamesOnly<TSource>,
  TTarget extends Pick<TSource, Props>>
  (source: TSource, ...props: Props[]): TTarget {
    const result: any = {};
    for (const prop of props) {
      result[prop] = source[prop];
    }
    return result;
  }

  static OmitProps<
    TSource,
    Props extends PropertyNamesOnly<TSource>,
    TTarget extends Omit<TSource, Props>>
    (source: TSource, ...props: Props[]): TTarget {
      const result: any = {};
      const keys = Object.keys(source).filter(k => props.some(p => p !== k)) as (keyof TSource)[];

      for (const key of keys) {
          result[key] = source[key];
      }
    }

推荐答案

为了实现这一目标,我们需要将属性类型提升为泛型.考虑:

In order to achieve the goal we need to lift the properties type into generic. Consider:

declare type PropertyNamesOnly<T> = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T];

function CopyProps<
  TSource,
  Props extends PropertyNamesOnly<TSource>,
  TTarget extends Pick<TSource, Props>>
(source: TSource, ...props: Props[]): TTarget {
    const result: any = {};
    for (const prop of props) {
      result[prop] = source[prop];
    }
    return result;
}

class Props { a: string = "a"; b: string = "b"; c: string = "c"; }
const props = new Props();

const copy = CopyProps(props, "a", "c"); // copy has a and c

// second check with function
const example2 = { a: 'a', b: () => { }, c: 1 };
const copy2 = CopyProps(example2, "a", "b"); // correct error as b is a function

const example3 = { a: 'a', b: () => { }, c: 1 };
const copy3 = CopyProps(example2, "a", "c"); // is ok has a and c

最重要的部分:

  • 道具扩展了PropertyNamesOnly< TSource> -我们说道具是 TSource 的键,但是没有具有函数类型值的键
  • TTarget扩展了Pick< TSource,Props> -我们说return将是 TSource 的对象,其中包含 Props
  • ... props:道具[] 我们声明我们的道具是通用类型,以便类型推断起作用
  • Props extends PropertyNamesOnly<TSource> - we say props are keys of our TSource but without keys which have function type of values
  • TTarget extends Pick<TSource, Props> - we say return will be object of TSource with picked props by Props
  • ...props: Props[] we declare our props are generic type in order to have type inference working

这篇关于泛型打字稿:来自keyof T值的泛型类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-13 05:35