[英]TypeScript: pass the ReturnType of a nested function in an object that uses Interface
我想创建一个结构,其中有一个这样的接口:
interface PageData {
data: (this: Page) => object;
methods: (this: Page) => { [methodName: string]: () => any };
main: (this: Page) => void;
}
以及使用此数据创建新实例的类:
class Page {
name: string;
data: object;
methods: object;
constructor(name: string, data: PageData) {
this.name = name;
this.data = data.data.call(this);
this.methods = data.methods.call(this);
data.main.call(this);
}
}
现在我如何将数据和方法函数的 ReturnType 传递给 Page.data 和 Page.methods? 我搜索了 ReturnType、Generics 等,此时我很困惑。 也许它甚至不可能? 我想要这个接口,所以我可以在很多文件中使用它。 我的文件夹结构类似于:
src/ src/main.ts src/Page.ts src/pages/demo.ts
在 demo.ts 中,我想导出一个带有 PageData 接口的对象:
export default {
data: function() {
return {
customName: this.name + "demo"
}
},
methods: function() {
return {
doSomething: () => this.data.customName.repeat(2)
}
},
main: function() {
console.log(this.data.customName);
console.log(this.methods.doSomething());
}
} as PageData
在 main.ts 中,我会使用 require 获取数据。 像new Page("demo", require("src/pages/demo.ts"))
。
我试图找到任何与我正在尝试做的事情相似的例子,但我找不到任何东西。 我发现的唯一问题是如何获取函数的 ReturnType,而不是使用接口的对象中的函数。
在这个完整的例子中,存在三个错误:
第Property 'customName' does not exist on type 'object'.
行: Property 'customName' does not exist on type 'object'.
第 32 行: Property 'doSomething' does not exist on type 'object'.
interface PageData {
data: (this: Page) => object;
methods: (this: Page) => { [methodName: string]: () => any };
main: (this: Page) => void;
}
class Page {
name: string;
data: object;
methods: object;
constructor(name: string, data: PageData) {
this.name = name;
this.data = data.data.call(this);
this.methods = data.methods.call(this);
data.main.call(this);
}
}
export default {
data: function() {
return {
customName: this.name + "demo"
}
},
methods: function() {
return {
doSomething: () => this.data.customName.repeat(2)
}
},
main: function() {
console.log(this.data.customName);
console.log(this.methods.doSomething());
}
} as PageData
我的建议是在Page
对象的data
和methods
属性的类型中使您的PageData
和Page
类型通用,如下所示:
interface PageData<D extends object, M extends Record<keyof M, () => any>> {
data: (this: Page<D, M>) => D;
methods: (this: Page<D, M>) => M;
main: (this: Page<D, M>) => void;
}
class Page<D extends object, M extends Record<keyof M, () => any>> {
name: string;
data: D;
methods: M;
constructor(name: string, data: PageData<D, M>) {
this.name = name;
this.data = data.data.call(this);
this.methods = data.methods.call(this);
data.main.call(this);
}
}
(注意:鉴于您的示例PageData
显式使用箭头函数属性而不是它的methods
属性中的methods
,我不会打扰ThisType<T>
实用程序类型,因为它们没有自己的this
上下文需要担心关于。)
然后是PageData
对象并解决这些错误的问题。
我假设您不想手动注释this
参数的所有属性,而是希望编译器推断出适当的this
类型。 不幸的是,这可能无法通过单个对象一次性完成(请参阅相关的 GitHub 评论); 编译器需要同时构建和推断类型,这不是很好。 能够按顺序做事更好。 因此,如果在您的示例中, data
属性并不真正依赖于任何东西, methods
属性依赖于data
,而main
属性依赖于data
和methods
,那么您可以考虑为PageData
对象制作一个构建器依次创建它们:
const pageDataBuilder = {
data: <D extends object>(data: (this: Page<any, any>) => D) => ({
methods: <M extends Record<keyof M, () => any>>(methods: (this: Page<D, any>) => M) => ({
main: (main: (this: Page<D, M>) => void) => ({
data, methods, main
})
})
})
};
以下是您如何使用它:
const data = pageDataBuilder.data(
function () {
return {
customName: this.name + "demo"
}
}).methods(function () {
return {
doSomething: () => this.data.customName.repeat(2)
}
}).main(function () {
console.log(this.data.customName);
console.log(this.methods.doSomething());
});
编译没有错误,然后就可以了:
const page = new Page("demo", data);
page.data.customName; // string
在我看来很好。 希望有所帮助; 祝你好运!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.