Тип переменной обычно выводится, когда переменная объявляется, и обычно не изменяется после (поэтому foo
набирается как Family<{ [name: string]: Animal; >
, поскольку на момент инициализации другой доступной информации нет)
Если вы можете передать member
в конструктор, чтобы сделать вывод T
на основе аргумента, который будет работать должным образом:
class Family <T extends { [name: string]: Animal }> {
constructor(public members: T) { }
public lookup <K extends keyof T>(name: K): T[K] {
return this.members[name]
}
}
const result1 = foo.lookup('missing') // err
const result2 = foo.lookup('kitty') // cat
Playground Link
Указание аргумента типа явно для конструктора также вариант, но не такой удобный:
const foo = new Family<{ kitty: Cat, bob: Dog }>()
foo.members = { kitty: cat, bob: dog }
const result1 = foo.lookup('missing') // err
const result2 = foo.lookup('kitty') // cat
Playground Link
Теперь, если ни один из этих вариантов это невозможно, вы можете go более эзотерический c маршрут и использовать пользовательскую функцию подтверждения . Эти пользовательские утверждения, если они используются в качестве оператора верхнего уровня, могут изменять тип переменной:
class Family <T extends { [name: string]: Animal }> {
private members!: T;
public setMemebers<TNew extends T>(members: TNew): asserts this is Family<TNew> {
this.members = members;
}
public lookup <K extends keyof T>(name: K): T[K] {
return this.members[name]
}
}
class Animal {}
class Cat extends Animal {}
class Dog extends Animal {}
const cat = new Cat
const dog = new Dog
const foo: Family<any> = new Family()
foo.setMemebers({ kitty: cat, bob: dog });
const result1 = foo.lookup('missing') // err
const result2 = foo.lookup('kitty') // cat
Playground Link