Мой вопрос немного сложнее, поэтому, возможно, все необходимые детали:
// Common interface with an id and a string lieral type
interface IHandler {
id: Id<IHandler>;
type: string;
}
// Base class for all the handler, with generic argument providing string literal type and access to inheriting type
class Base<Type extends string, T extends Base<Type, T>> implements IHandler {
id: Id<T> = Guid.raw() as any
// In consturctor string literal type is instantiated
protected constructor(public type: Type) {
this.type = type;
}
// Static function that retrieves handler by it's key from a store
static GetHandler: <T extends IHandler>(get: Id<T>) => T;
// Getter that accepts key of an id attribute and returns instance from store
get = <Handler extends Base<Handler["type"], Handler>>(key: HandlerIds<T, Handler>) => Base.GetHandler<Handler>((this as any)[key]);
}
// Keys of attributes that are Id's
type HandlerIds<T extends Base<T["type"], T>, U extends Base<U["type"], U>> = keyof SubType<Model<T>, Id<U>>;
// Creates a subtype based on condition
type SubType<Base, Condition> = Pick<Base, { [Key in keyof Base]: Base[Key] extends Condition ? Key : never }[keyof Base]>;
// Excludes attributes of Base
type Model<T extends Base<T["type"], T>> = Partial<Pick<T, Exclude<keyof T, keyof Base<T["type"], T>>>>;
// Type that holds guid reference and also a type that guid is supposed to be pointing to
type Id<T extends IHandler> = string & { __type: T }
Итак, у меня есть interface
, затем класс base
, который реализует getter
, и затем производные классы, которые передают свой тип базовому классу. Также существует тип Id
, который содержит уникальный идентификатор обработчика, а также его тип. Каждый обработчик имеет свой собственный идентификатор в переменной id
и затем может сохранять ссылки на другие обработчики в атрибуте типа Id
с общим аргументом типа этого обработчика.
Что я хотел бы сделать, так это правильно набрать функцию get
, чтобы она определяла тип обработчика, который он получает, при условии key
. Поскольку каждый ключ определяется типом обработчика, на который он указывает, этот тип, вероятно, следует использовать для определения типа возвращаемого значения, но при такой настройке он не работает.
Вы можете увидеть пример желаемого использования здесь:
class Foo extends Base<"Foo", Foo> {
a: Id<Goo>;
b: Id<Foo>;
constructor() {
super("Foo");
// Get a reference to instance of "a" of type Goo
var aHandler = this.get("a");
// Get a reference to instance of "b" of type Foo
var bHandler = this.get("b");
}
}
class Goo extends Base<"Goo", Goo> {
constructor() {
super("Goo");
}
}
Я хотел бы добиться, чтобы атрибуты aHandler
и bHandler
были автоматически выведены как Foo
и Goo
.