[英]Return inferred generic type
I want to return the inferred type from a function on a class, but the return type is of the extended generic type, not the actual result of the function.我想从类上的函数返回推断类型,但返回类型是扩展泛型类型,而不是函数的实际结果。 I want to instead return the inferred type of the function.我想返回函数的推断类型。
I tried a few things surrounding wrapping and unwrapping, but was unable to get those to work.我尝试了一些围绕包装和展开的方法,但无法让它们正常工作。
Problem : newDocumentSet
is of type IDocumentSet<DocumentTypes, IContact, never>
, not the type returned in the create functions extend parameter问题: newDocumentSet
的类型是IDocumentSet<DocumentTypes, IContact, never>
,而不是创建函数扩展参数中返回的类型
Notes : I would like the create function to return the extended instance, not the interface of IDocumentSet
.注意:我希望 create 函数返回扩展实例,而不是IDocumentSet
的接口。 It seems like this bit (create<TExtension extends IDocumentSet<TDocumentType, TEntity, TExtraExclusions>>) is screwing it up, I am just not sure how to enforce a return type that extends IDocumentSet<TDocumentType, TEntity, TExtraExclusions>
yet returns the extended type not IDocumentSet<TDocumentType, TEntity, TExtraExclusions>
.似乎这个位 (create<TExtension extends IDocumentSet<TDocumentType, TEntity, TExtraExclusions>>) 搞砸了,我只是不确定如何强制执行扩展IDocumentSet<TDocumentType, TEntity, TExtraExclusions>
的返回类型但返回扩展类型不是IDocumentSet<TDocumentType, TEntity, TExtraExclusions>
。
Goal : I want to create the ability to return the extended class from the create function, not the interface.目标:我想创建从创建函数返回扩展类的能力,而不是接口。
Example is below and here in this fiddle示例在下面,在这个小提琴中
I also found this post about wrapping and unwrapping, but was unable to get it to work for my needs我还发现了这篇关于包装和展开的帖子,但无法满足我的需要
This example is from a larger code base, code surrounding TExtraExclusions
has been omitted to keep this example smaller, yet the generics remain.此示例来自更大的代码库,已省略围绕TExtraExclusions
的代码以使此示例更小,但仍保留泛型。
export interface IDocumentSetBase<TDocumentType extends string> {
get DocumentType(): TDocumentType;
empty(): Promise<void>;
}
interface IDocumentSet<TDocumentType extends string, TEntity extends IDbRecord<TDocumentType>, TExtraExclusions extends (keyof TEntity) = never> extends IDocumentSetBase<TDocumentType> {
info(): boolean
}
interface IDbRecord<TDocumentType> extends IDbAdditionRecord<TDocumentType> {
readonly _id: string;
readonly _rev: string;
}
interface IDbAdditionRecord<T> {
readonly DocumentType: T;
}
export class DocumentSet<TDocumentType extends string, TEntity extends IDbRecord<TDocumentType>, TExtraExclusions extends (keyof TEntity) = never> implements IDocumentSet<TDocumentType, TEntity, TExtraExclusions> {
private _documentType: TDocumentType;
get DocumentType() { return this._documentType; }
constructor(documentType: TDocumentType) {
this._documentType = documentType;
}
info() {
return true;
}
async empty() {
}
}
class Builder<TDocumentType extends string, TEntity extends IDbRecord<TDocumentType>, TExtraExclusions extends (keyof TEntity) = never> {
private _documentType: TDocumentType;
constructor(documentType: TDocumentType) {
this._documentType = documentType;
}
create<TExtension extends IDocumentSet<TDocumentType, TEntity, TExtraExclusions>>(extend: (Instance: typeof DocumentSet<TDocumentType, TEntity, TExtraExclusions>, documentType: TDocumentType) => TExtension = w => (w as any) as TExtension) {
const result = extend(DocumentSet<TDocumentType, TEntity, TExtraExclusions>, this._documentType);
return result;
}
}
enum DocumentTypes {
Contacts = "Contacts"
}
interface IContact extends IDbRecord<DocumentTypes> {
firstName: string;
lastName: string;
address: string;
phone: string;
}
const builder = new Builder<DocumentTypes, IContact>(DocumentTypes.Contacts);
const newDocumentSet = builder.create((Instance, documentType) => {
return new class extends Instance {
constructor() {
super(documentType)
}
test() {
return "some value";
}
}
});
In your shorter example, you are using the instantiation expression typeof DocumentSet<TDocumentType, TEntity>
to refer to the type of a generic class constructor whose generic type parameters have been specified with the arguments TDocumentType, TEntity
.在您较短的示例中,您使用实例化表达式typeof DocumentSet<TDocumentType, TEntity>
来引用泛型类构造函数的类型,其泛型类型参数已使用参数TDocumentType, TEntity
指定。 That is, a type essentially the same as new() => DocumentSet<TDocumentType, TEntity>
(using a construct signature ).也就是说,与new() => DocumentSet<TDocumentType, TEntity>
基本相同的类型(使用构造签名)。
If you replace the instantiation expression with the equivalent type:如果将实例化表达式替换为等效类型:
create<TExtension extends IDocumentSet<TDocumentType, TEntity>>(
extend: (Instance: new () => DocumentSet<TDocumentType, TEntity>
) => TExtension = w => (w as any) as TExtension) {
return extend(DocumentSet);
}
Then you get the expected inference when you call extend()
:然后,当您调用extend()
时,您会得到预期的推断:
myNewSet.someNewFunction(); // okay
I'm not sure why it doesn't work the way you wrote it.我不确定为什么它不像你写的那样工作。 Instantiation expressions are new (they were introduced in TypeScript 4.7 which is the latest release version), so I can't tell if this inference failure is a language bug, or a design limitation, or the intentional behavior.实例化表达式是新的(它们是在最新版本的 TypeScript 4.7 中引入的),所以我无法判断这种推理失败是语言错误、设计限制还是故意行为。 If it matters, someone might want to open an issue in GitHub asking about it.如果这很重要,有人可能想在 GitHub 中打开一个问题来询问它。 If that happens and we get an answer, we can update this post.如果发生这种情况并且我们得到了答案,我们可以更新这篇文章。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.