kev*_*ler 11 typescript webpack typescript-typings
我正在将一个功能性 mixin 项目从 javascript 迁移到 typescript。我所有的 javascript minxins 都有带有单个参数的构造函数签名constructor(props){}
。
在打字稿中,我按照https://www.typescriptlang.org/docs/handbook/mixins.html的官方文档定义了 mixin 构造函数类型 :
export type ConstrainedMixin<T = {}> = new (...args: any[]) => T;
Run Code Online (Sandbox Code Playgroud)
即使我将该 mixin 签名更改为:
export type ConstrainedMixin<T = {}> = new (props: any) => T;
Run Code Online (Sandbox Code Playgroud)
并更新实现 TSC 将抛出错误:
TS2545:mixin 类必须具有一个带有“any[]”类型的单个剩余参数的构造函数。
不幸的是,它无法为传递给构造函数的参数创建唯一的类型签名。我现在还需要迁移所有现有的构造函数。如何为 mixin 构造函数创建更明确的类型接口?
我创建了一个游乐场示例
您可以在此屏幕截图中看到编译器在 MIXIN 定义上出现错误,并表示 mixin 类必须具有单个剩余参数。即使类型定义是:
type ConstrainedMixin<T = {}> = new (props: any) => T;
Run Code Online (Sandbox Code Playgroud)
在我的示例中,const mg = new MixedGeneric({cool: 'bro'});
我想为该{cool: 'bro'}
对象创建一个接口,并从 mixin 定义中强制执行它。我不确定如何正确执行此操作。如果构造函数是...args: any[]
更新 听起来这可能是一些反模式,所以这里有进一步的解释。我正在构建一个实体组件系统。在我当前的实现中,我有一些 mixins 链,例如:
const MixedEntity = RenderMixin(PhysicsMixin(GeometryMixin(Entity));
const entityInstance = new MixedEntity({bunch: "of", props: "that mixins use"});
Run Code Online (Sandbox Code Playgroud)
当最终的 MixedEntity 被实例化时,它会被传递一个props
数据包对象。所有 Mixin 在其构造函数中都有自己的初始化逻辑,用于查找对象的特定属性props
。
我以前的 mixin 类的构造函数如下:
constructor(props){
super(props);
if(props.Thing) // do props.thing
}
Run Code Online (Sandbox Code Playgroud)
我现在必须将构造函数迁移到:
constructor(...args: any[]){
const props = args[0]
super(props);
if(props.Thing) // do props thing
}
Run Code Online (Sandbox Code Playgroud)
hac*_*ape 18
TS 中的 Mixin 模式旨在使用额外的方法或属性扩展基类,但不会篡改构造函数签名。因此,派生类应该保持其构造函数签名与其扩展的基类相同。
\n这就是这个限制背后的原因,A mixin class must have a constructor with a single rest parameter of type \'any[]\'
因为 TS 不关心,它只是将构造传递给它super(\xe2\x80\xa6args)
并让它完成工作。
因此,如果您想约束构造函数参数,只需在基类构造函数签名中执行即可。
\n\ntype Constructor = new (...args: any[]) => {};\nfunction MixinGeneric<TBase extends Constructor>(Base: TBase) {\n return class extends Base {\n // \xe2\x80\xa6mixin traits\n }\n}\n\nclass Generic {\n // ctor param constraint goes here:\n constructor<P extends { cool: string }>(props: P) {}\n}\n\n// and it\xe2\x80\x99ll check:\nconst mg = new MixedGeneric({cool: \'bro\'});\n
Run Code Online (Sandbox Code Playgroud)\n响应OP的更新而更新
\n是的,篡改构造函数签名被视为反模式。但程序员总是违反规则。只要您了解自己在做什么,就一定要有创造力。
\n去游乐场看看吧。
\n技巧是通过使用类型断言和一堆实用程序类型来绕过 TS 限制。
\n// Utility types:\n\ntype GetProps<TBase> = TBase extends new (props: infer P) => any ? P : never\ntype GetInstance<TBase> = TBase extends new (...args: any[]) => infer I ? I : never\ntype MergeCtor<A, B> = new (props: GetProps<A> & GetProps<B>) => GetInstance<A> & GetInstance<B>\n\n\n// Usage:\n// bypass the restriction and manually type the signature\nfunction GeometryMixin<TBase extends MixinBase>(Base: TBase) {\n // key 1: assert Base as any to mute the TS error\n const Derived = class Geometry extends (Base as any) {\n shape: \'rectangle\' | \'triangle\'\n constructor(props: { shape: \'rectangle\' | \'triangle\' }) {\n super(props)\n this.shape = props.shape\n }\n }\n\n // key 2: manually cast type to be MergeCtor\n return Derived as MergeCtor<typeof Derived, TBase>\n}\n
Run Code Online (Sandbox Code Playgroud)\n
归档时间: |
|
查看次数: |
7253 次 |
最近记录: |