首页 > 解决方案 > 根据 Typescript 中的输入转换器函数更改函数返回类型

问题描述

我想做的是创建一个简单的函数,它可以选择接受一个transformer方法作为输入并返回:

展示我的意思的一个小例子如下:

// 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

打字稿游乐场在这里

我试图遵循接口的简单map实现,Array<T>它正确地推断出提供的回调方法的返回类型,map但我无法让它工作。getPeople我在实施和使用中遇到错误。

有任何想法吗?

标签: typescriptcallbacktype-inferencereturn-typeconditional-types

解决方案


我试图简化并创建一个更通用的问题版本并将其发布在这里:Typescript method return type based on optional param property function

在@jcalz 非常慷慨的帮助和解释下,我还能够创建一个适用于我的原始帖子的版本。类型推断对于 Typescript来说是一件非常复杂的事情,并不是所有的事情都会像人们期望的那样自动推断出来。重要的结论是:

  • 类型推断不考虑通用约束
  • 类型推断不能部分工作。您可以在类型化函数使用中提供所有类型参数,或者不提供。您不能提供其中一个类型参数并让其他类型参数被推断出来。

话虽如此,这是适用于我原来问题的版本:

// 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

打字稿游乐场


推荐阅读