从传递函数的返回值推断函数泛型类型U函数、推断、返回值、类型

2023-09-03 13:34:00 作者:# 安好可以有多好

在大多数情况下,具有泛型类型的函数可以从参数中推断泛型类型。但是,如果参数是泛型类型既是参数的一部分又是返回值的函数,则有时不会推断该泛型类型。

简化的示例,有一个用于存储项目的类,其中项目的一些属性是自动生成的(例如,ID是自动生成的数据库):

/**
 * Stores items of type T
 */
class Store<T> {

  /**
   * Return a function that creates items from supplied partial items merged with
   * attributes U auto-generated by a generator function
   */
  itemCreator<U>(
    generate: (item: Omit<T, keyof U>) => U
  ): (item: Omit<T, keyof U>) => Omit<T, keyof U> & U {
    return item => ({...item, ...generate(item)});
  }
}

type Person = {
  id: string;
  name: string;
  email: string;
  age?: number;
};

因此,如果您创建一个Store<Person>并提供一个生成器来自动生成id,则返回的创建者函数只需要nameemail

javaScript中值传递和引用传递 把引用类型的参数作为函数的返回值

但是,在某些情况下,不会推断U

工作:

const create = new Store<Person>()
  .itemCreator(() => ({id: 'ID', extra: 42}));
// U is {id: string, extra: number}, `create` only needs to provide `name` and `email` :)
const person = create({name: 'John', email: 'john.doe@foo.com'}); // creates person with extra

不起作用:

const create = new Store<Person>()
  .itemCreator(item => ({id: 'ID', extra: 42}));
// U is now unknown, meaning the `create` function must provide complete `Person` objects :(
const person = create({name: 'John', email: 'john.doe@foo.com'}); // does not compile

使用显式<U>

const create = new Store<Person>()
  .itemCreator<{id: string, extra: number}>((item) => ({id: 'ID', extra: 42}));
const person = create({name: 'John', email: 'john.doe@foo.com'}); // creates person with extra

现在,将部分项传递给生成器的原因是,某些自动生成的属性可能依赖于其他属性(例如,作为email属性的散列生成的id):

const creator = new Store<Person>()
  .itemCreator(item => ({id: hash(item.email)}))
因此,我的问题是,如果提供了generate函数的参数,为什么U推理失败?TypeScrip是否只是使用找到的第一个U实例,或者原因是什么?generate函数返回U,因此如果它看到返回{id: string},您可能会认为U也存在于参数到generateOmit类型中是不相关的?

有没有办法解决这个问题?

推荐答案

@jhh,@linda paiste您认为下一步解决方案是什么?:


class Store<T> {

    itemCreator<U>(
        generate: <P = Omit<T, keyof U>>(item: P) => U
    ): (item: Omit<T, keyof U>) => Omit<T, keyof U> & U {
        return item => ({ ...item, ...generate(item) });
    }
}

type Person = {
    id: string;
    name: string;
    email: string;
    age?: number;
};


const create = new Store<Person>()
    .itemCreator(item => {
        const x = item // Omit<Person, "id" | "extra">
        return ({ id: 'ID', extra: 42 })
    });
const person = create({ name: 'John', email: 'john.doe@foo.com' });


看起来TS很难推断item参数,所以我用默认值定义了额外的泛型。

Here,在我的博客中,您可以找到更有趣的回调类型

Here您可以找到Titian CerNicova Dragomir对此行为的解释

如果有参数,检查器需要在检查正文之前确定U,因为没有来源可以推断它与UNKNOWN匹配。然后它检查正文,但不会返回使用U = ret type重试,它只检查返回的指南针。U=未知

 
精彩推荐