TypeScript:带有自定义方法的工厂 - 第三步
Posted
技术标签:
【中文标题】TypeScript:带有自定义方法的工厂 - 第三步【英文标题】:TypeScript: factory with custom methods - 3rd step 【发布时间】:2022-01-23 22:22:14 【问题描述】:我在一家工厂工作;我最终需要添加自定义方法,感谢this answer 和this answer,我们能够使其几乎按预期工作。
几乎是因为它只适用于没有任何必需参数的方法;如果我们尝试添加具有至少一个必需参数的方法,则会出现编译错误。
我尝试在 method
参数和 M
类型的声明中添加一个 rest 参数数组(见下文),但它仅在调用方法时有帮助。
(this: E & S, ...args: unknonwn[]) => unknown
type Base = id: string
type Factory<E> = new () => E;
function factory<E extends Base>(name: string): Factory<E>;
function factory<E extends Base, M extends Record<string, <S extends M>(this: E & S, ...args: unknown[]) => unknown>>(
name: string, methods: M & Record<string, ((this: E & M, ...args: unknown[]) => void)>
): Factory<E & M>;
function factory<E extends Base, M extends Record<string, <S extends M>(this: E & S) => unknown>>(
name: string, methods?: M
): Factory<E>
const ret = function (this: Base)
this.id = "0"
;
Object.defineProperty(ret, "name", value: name );
if (methods) for (const method in methods) Object.defineProperty(ret.prototype, method, value: methods[method] );
return ret as unknown as Factory<E>;
const T1 = factory("T1");
const t1 = new T1();
console.log(t1, t1.id);
const T2 = factory(
"T2",
foo: function (repeat: boolean)
const ret = ! repeat;
if(repeat) this.foo(ret);
return ret;
,
);
const t2 = new T2();
console.log(t2, t2.id, t2.foo(true));
这是一个playground 进行实验。
【问题讨论】:
将unknown[]
替换为any[]
。见example。别担心,any
提供不安全行为时并非如此。这意味着您的函数可以返回任何参数并期望任何参数。让我知道它是否有帮助
不仅仅是“它有帮助”,我会说“它解决了”!返回类型也可以是void
(至少在我到目前为止所做的测试中)。如果您介意更改答案中的评论,我可以接受
【参考方案1】:
请考虑这个代表您的用例的示例:
const foo = (fn: (a: unknown) => unknown) => fn
foo((arg: number) => arg) // error
错误:
Type 'unknown' is not assignable to type 'number'
请看unknown docs:
任何东西都可以分配给
unknown
,但unknown
不能分配给任何东西,除了它自己和任何没有类型断言或基于控制流的缩小。
那么,如果Anything is assignable to
unknown`` 为什么会出现错误?
看这个:
const bar = (a: unknown) => a
bar(42) // ok
这里好像出了点问题。不它不是。这是因为contravariance
。在第一个示例中,参数a
处于逆变位置。这意味着继承的箭头指向相反的方向。请参阅this 答案和一些简单的示例和this 答案。
您需要做的就是将unknown
更改为any
。不用担心,它不会给您的代码带来不安全性。其实你对methods
没有任何具体的限制。
解决方案:
type Base = id: string
type Factory<E> = new () => E;
function factory<E extends Base>(name: string): Factory<E>;
function factory<E extends Base, M extends Record<string, <S extends M>(this: E & S, ...args: any[]) => any>>(
name: string, methods: M & Record<string, ((this: E & M, ...args: any[]) => void)>
): Factory<E & M>;
function factory<E extends Base, M extends Record<string, <S extends M>(this: E & S, ...args: any[]) => any>>(
name: string, methods?: M
): Factory<E>
const ret = function (this: Base)
this.id = "0"
;
Object.defineProperty(ret, "name", value: name );
if (methods) for (const method in methods) Object.defineProperty(ret.prototype, method, value: methods[method] );
return ret as unknown as Factory<E>;
const T1 = factory("T1");
const t1 = new T1();
console.log(t1, t1.id);
const T2 = factory(
"T2",
foo: function (repeat: boolean)
const ret = !repeat;
if (repeat)
this.foo(ret);
return ret;
,
);
const t2 = new T2();
console.log(t2, t2.id, t2.foo(true));
Playground
【讨论】:
太棒了!再次感谢您! 您好船长!主要感谢您的帮助,我能够进行几个月来计划的重构!我正在处理sedentary;如果您想检查答案的效果,请将 v0.0.19 与 v0.0.20 进行比较,此外还有model
方法(从 8 个重载到只有 2 个!!!现在一切都按预期工作!!!)。如果您介意将您的 github 或 npm 帐户提供给我,那么您肯定应该在贡献者列表中获得第一名!
非常感谢您的反馈。它激励。 github.com/captain-yossarian以上是关于TypeScript:带有自定义方法的工厂 - 第三步的主要内容,如果未能解决你的问题,请参考以下文章
找不到带有 Webpack、Typescript、自定义模块目录的模块
带有 Typescript 的 React-Native 自定义文本组件:“将 React.ReactNode 类型转换为文本类型......”