РЕДАКТИРОВАТЬ: Я предлагаю вам взглянуть на Mixins в Typescript и исследовать разницу между Object.assign
и applyMixins
хелпер, представленный там. Возможно, вам нужен именно этот шаблон проектирования.
Вот грязное, но строго типизированное решение, использующее буквальный объект и не повторяющее все его ключи в соответствии с запросом. Встроенные пояснения и ссылка на TypeScript Playground .
// Hide these helpers away in your `utils.ts` somewhere, see below what they do.
/**
* Gives Constructor given a instance, like inverse of `InstanceType`.
*
* Second optional parameter is argument tuple for the `constructor()`.
*
* @todo this interface lacks signature for static methods/properties.
*/
export interface IConstructor<T extends object = object, TA extends unknown[] = unknown[]> {
new(...args: TA): T
}
/**
* Overrrides a class to return a instance that includes the given mixin.
*/
export type ClassWithMixin<T extends IConstructor, TMixin extends object> =
IConstructor<InstanceType<T> & TMixin, ConstructorParameters<T>>
// A mixin many keys and/or methods. Use `typeof someLiteralObject` to use it as interface.
const someLiteralObject = {
key1: 'foo',
key2: 'bar',
} as const // <-- `as const` is optional, but handy.
// `this:` type tells method internal scope that `this` is more than TS thinks by default.
class FooPure {
constructor(){
Object.assign(this, someLiteralObject)
}
test(this: this & typeof someLiteralObject) {
console.log(this.key1)
}
}
// And `ClassWithMixin` type tells all other codebase that `Foo` is more than `FooHidden`.
const Foo = FooPure as ClassWithMixin<typeof FooPure, typeof someLiteralObject>
// Works as expected.
const foo = new Foo()
console.log(foo.key1)
foo.test()
class Bar extends Foo {
constructor() {
super()
this.test()
}
}
console.log(new Bar())