简体   繁体   English

根据Typescript中的输入转换器函数更改函数返回类型

[英]Change function return type based on input tranformer function in Typescript

What I am trying to do is create a simple function that would optionally accept a transformer method as input and return:我想要做的是创建一个简单的函数,它可以选择接受一个transformer方法作为输入并返回:

  • either the original result (if no transformer provided)原始结果(如果没有提供transformer
  • or the transformed result based on the transformer 's return type.或基于transformer返回类型的转换结果。

A small example to showcase what I mean is the following:展示我的意思的一个小例子如下:

// our basic example interface
interface Person {
  name: string;
  age: number
};

// the transformer fn type
type TransformerFn = <T>(person: Person) => T;

// method options contaning the optional transformer method param
interface mapperOpts {
  paramA?: number
  transformer?: TransformerFn
}

// Conditional type for returning the result based on providing transformer in options or not
type OriginalOrTransformedPerson<T extends Partial<mapperOpts>> = T extends { transformer: TransformerFn } ? 
  ReturnType<T['transformer']> :
  Person;

// test class interface
interface PeopleGetter {
  getPeople<T extends Partial<mapperOpts>>(people: Person[], opts: T): OriginalOrTransformedPerson<T>
}

class Test implements PeopleGetter {
  getPeople(people: Person[], opts: Partial<mapperOpts>) {
    if (opts.transformer) {
      return people.map(opts.transformer);
    } else {
      return people;
    }
  }
}

const people: Person[] = [{ name: 'john', age: 20 }];

const test = new Test();
const original = test.getPeople(people); // here we should have `Person[]`
const transformedResult = test.getPeople(people, { transformer: (person: Person) => person.name }); // here I would like to have the return type of 'string[]' based on transformer method

Typescript playground here打字稿操场在这里

I tried to follow the plain map implementation of Array<T> interface which properly infers the return type of the provided callback method in map but I could not get it to work.我试图遵循Array<T>接口的普通map实现,它正确推断了map提供的回调方法的返回类型,但我无法让它工作。 I get errors in getPeople implementation and usage.我在getPeople实现和使用中遇到错误。

Any ideas?有任何想法吗?

I tried to simplify and create a more generic version of the problem and posted it here: Typescript method return type based on optional param property function我试图简化并创建一个更通用的问题版本并将其发布在这里: Typescript method return type based on optional param property function

With the really generous help and explanation of @jcalz I was able to also create a version that works for my original post here.在@jcalz 非常慷慨的帮助和解释下,我还能够创建一个适用于我的原始帖子的版本。 The thing it that Type Inference is a really complicated matter for Typescript and not everything is automatically inferred as someone would expect to.类型推断对于 Typescript 来说是一件非常复杂的事情,并不是所有的事情都会像人们期望的那样自动推断出来。 Important conclusions are:重要的结论是:

  • Type inference does not take into account Generic Constraints类型推断不考虑通用约束
  • Type inference cannot work partially.类型推断不能部分工作。 You would either provide all the type parameters in a typed function use, or none.您要么提供类型化函数使用中的所有类型参数,要么不提供。 You cannot provide one of the type arguments and let the others be inferred.您不能提供类型参数之一并让其他类型参数被推断出来。

Having said that, here is the version that works for my original question:话虽如此,这是适用于我的原始问题的版本:

// our basic example interface
interface Person {
  name: string;
  age: number
};

// the transformer fn type
type TransformerFn<T = any> = (person: Person) => T;

// method options contaning the optional transformer method param
interface mapperOpts<T = any> {
  paramA?: number
  transformer?: TransformerFn<T>
}

// Conditional type for returning the result based on providing transformer in options or not
type OriginalOrTransformedPerson<T> = T extends { transformer: TransformerFn<infer R> } ? 
  R :
  Person;

// test class interface
interface PeopleGetter {
  getPeople<T extends Partial<mapperOpts>>(people: Person[], opts: T): OriginalOrTransformedPerson<T>[]
}

class Test implements PeopleGetter {
  getPeople<T extends Partial<mapperOpts>>(people: Person[], opts?: T): OriginalOrTransformedPerson<T>[] {
    if (opts?.transformer) {
      return people.map(opts.transformer);
    } else {
      return people as OriginalOrTransformedPerson<T>[];
    }
  }
}

const people: Person[] = [{ name: 'john', age: 20 }];

const test = new Test();
const original = test.getPeople(people); // here we should have `Person[]`
const transformedResult = test.getPeople(people, { transformer: (person: Person) => person.name }); // here I would like to have the return type of 'string[]' based on transformer method

Typescript Playground 打字稿游乐场

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM