[英]Making a mixin of interfaces in Typescript
我有一个包含 80 多个方法的类,每个方法都接受一个包含一些定义接口的对象。
class Stuff {
/* many more */
getAccount(req: IAccount, callback: ICallback) {
return this._call('getAccount', req, callback);
}
getIds(req: IIDs, callback: ICallback) {
return this._call('getIds', req, callback);
}
/* many more */
}
相当“无聊”的东西,因为它只是映射到底层_call
方法并使其对每个方法都类型安全。
但有时这些req
param 对象由 2 个或更多接口组成,而不是每次出现“尴尬”时都创建另一个接口,如下所示:
export interface ILoled extends IAccount {
loled: boolean;
}
export interface IRofloled extends ILoled {
rofled: boolean;
}
class Stuff {
getLols(req: ILoled){
}
getRofls(req: IRofloled){
}
}
有什么办法可以把它作为方法参数列表中接口的“内联”混合? 喜欢(这显然不起作用):
class Stuff {
getMoreStuff(req: <{} extends IAccount, ITime>) {
}
}
是的,你可以, 从 Typescript 1.6 开始。 称为Intersection types ,使用&
运算符来组合类型。
function extend<T, U>(first: T, second: U): T & U {
let result = <T & U> {};
for (let id in first) {
result[id] = first[id];
}
for (let id in second) {
if (!result.hasOwnProperty(id)) {
result[id] = second[id];
}
}
return result;
}
var x = extend({ a: "hello" }, { b: 42 });
x.a; // works
x.b; // works
有什么办法可以把它作为方法参数列表中接口的“内联”混合
否。您不能内联扩展接口
我不确定这是否有帮助,但是您是否了解 Kotlin 的接口实现委托与by
关键字?
在 Kotlin 中,您基本上可以创建一个实现一个接口的类,并使用它来将同一接口的实现委托给另一个类,如下所示:
interface Abc {
val foo: Int
}
class HelloAbc : Abc {
val foo = 5
}
class MyClass : Abc by HelloAbc() {
val bar = "Hello world"
}
上面的代码创建了一个名为Abc
的接口、一个实现该接口的类HelloAbc
和另一个类MyClass
,它使用HelloAbc
来实现Abc
。
我刚刚意识到它在 TypeScript 中也很有用,我可以想出一个类型安全的混合实现,如下所示:
type UnionToIntersectionUnchecked<T> =
(T extends any
? (k: T) => void
: never
) extends ((k: infer I) => void)
? I
: never
type IsUnion<T> = [T] extends [UnionToIntersectionUnchecked<T>] ? false : true
type UnionToIntersection<T> =
IsUnion<T> extends true
? UnionToIntersectionUnchecked<T>
: T
function deepCopy<T, U>(target: T, source: U): T & U {
const chain = []
for (let proto = source; source !== Object.prototype; source = Object.getPrototypeOf(source))
chain.unshift(proto)
for (const proto of chain)
Object.defineProperties(target, Object.getOwnPropertyDescriptors(proto))
return target as T & U
}
function mixin<
TBase extends object,
T extends object[]
>(
baseClass: { new (...args: any[]): TBase },
...objects: T
): { new (): TBase & UnionToIntersection<T[number]> } {
const proto = Object.assign(Object.create(baseClass.prototype), ...objects)
const ctor = (function(this: TBase, ...args: any[]) {
const thisProto = Object.getPrototypeOf(this)
const instance = new baseClass(...args)
Object.setPrototypeOf(instance, deepCopy(proto, thisProto))
return instance
}) as any
Object.setPrototypeOf(ctor, baseClass)
return ctor
}
下面的演示代码说明了如何使用这种技术来委托接口实现:
interface Abc {
readonly foo: number
}
interface Def {
readonly bar: string
}
class HelloAbc implements Abc {
readonly foo = 5
}
class HelloDef implements Def {
readonly bar = "Hello world"
}
class GreetingBase {
sayHello() {
console.log("Hello!")
}
}
class Greeting extends mixin(GreetingBase, new HelloAbc(), new HelloDef()) implements Abc, Def {
printTest() {
console.log("test")
}
}
const o = new Greeting()
o.sayHello()
o.printTest()
console.log(o.foo)
console.log(o.bar)
您甚至可以在操场上对其进行测试。
您会希望在性能关键代码中避免这种情况,因为创建所有这些原型可能很昂贵,但我不希望它对整体产生太大影响。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.