有没有办法使用泛型来正确地输入setValue
和getValue
函数的类型?我理解这个错误,因为它看到了给定属性的多种类型。但是有没有办法也让函数根据提供的属性值来识别name/age属性类型?
import { BehaviorSubject, Observable } from 'rxjs';
interface Person {
age: BehaviorSubject<number>;
name: BehaviorSubject<string>;
}
class SomeClass {
private _somePerson:Person = {
age: new BehaviorSubject(0),
name: new BehaviorSubject('John')
};
public setValue<T>(inID: number, inProperty: keyof(Person), inValue: T): void {
this._somePerson[inProperty].next(inValue);
}
public getValue<T>(inID: number, inProperty: keyof(Person)): Observable<T> {
return this._somePerson[inProperty].asObservable();
}
}
TSPlayground链接
1条答案
按热度按时间wi3ka0sx1#
从概念上讲,您希望将操作表示为indexing,其中generic键
K
(对应于inProperty
)转换为某个"基"Person
类型,其中值仅为string
和number
,而不是BehaviorSubject<string>
和BehaviorSubject<number>
。使用条件类型推理将
BehaviorSubject<V>
转换为V
,等效于:然后这个类看起来像这样:
所有这些都适用于该类的消费者:
但是,正如您所看到的,编译器无法遵循
setValue()
和getValue()
实现内部的逻辑。对于 * generic *K
,它需要查看BehaviorSubject<Person[K] extends BehaviorSubject<infer V> ? V : never>
与Person[K]
的类型相同。不幸的是,这超出了编译器的当前能力。它会丢失 * correlation * 的跟踪在一米十五纳一和一米十六纳一之间。所以你会收到错误消息说你正在做的事情可能不安全,这本质上就是microsoft/TypeScript#30581中描述的问题(那个问题讨论的是相关联合类型而不是泛型类型,但它是相同的底层问题)。
如果你不关心编译器在这些实现中验证类型安全,你可以只使用类型Assert来抑制警告:
这是因为类型Assert将验证类型安全性的负担从编译器转移到了开发人员身上。
如果你关心编译器验证这些实现的类型安全性,那么你需要按照microsoft/TypeScript#47109中的描述进行重构,而不是定义
Person
并从中计算BasePerson
,你可以直接定义BasePerson
:然后
Person
可以表示为mapped type的性质:这种表示非常重要,因为现在
Person[K]
上的操作将保持泛型,也就是说,编译器可以在索引到Map类型时遵循相关性:编译器发现
this._somePerson[inProperty]
是Person[K]
类型,它的计算结果是BehaviorSubject<BasePerson[K]>
,在此之后,其他一切都正常工作。Playground代码链接