[英]Infer function generic type U from return value of passed function
在大多数情况下,具有泛型类型的 function 可以从 arguments 推断出泛型类型。 但是,如果参数是 function 且泛型类型既是 arguments 的一部分又是返回值,则有时不会推断出泛型类型。
class 用于存储项目的简化示例,其中项目的某些属性是自动生成的(例如,自动生成 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
,则返回的创建者 function 将只需要name
和email
。
但是,在某些情况下,不会推断出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
属性的 hash 的id
):
const creator = new Store<Person>()
.itemCreator(item => ({id: hash(item.email)}))
所以,我的问题是,如果提供了generate
function 的参数,为什么推断U
会失败? TypeScript 只是使用第一个找到的U
实例还是什么原因? generate
function 返回U
,所以如果它看到{id: string}
被返回,有人可能会争辩说U
也出现在要generate
的参数的Omit
类型中这一事实应该无关紧要吗?
有没有办法解决这个问题?
@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
参数,所以我用默认值定义了额外的泛型。
在这里,在我的博客中,你可以找到更多有趣的回调类型
在这里您可以找到 Titian Cernicova Dragomir 对这种行为的解释
如果有参数,则检查器需要在检查主体之前确定 U,因为没有推理来源,它与未知有关。 然后它检查主体,但不返回 go 再次尝试使用
U = ret type
它只是检查返回的比较。 U = 未知
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.