我有这个用例,我有一个泛型类和一个包含泛型类的多个成员的容器类。我想使用 setViaFunction
来设置容器类的成员,而不取决于它们的类型。但是我收到以下错误:Argument of type 'string | boolean' is not assignable to parameter of type 'never'. Type 'string' is not assignable to type 'never'.(2345)
typescript playground link
另请注意,setAnyMember
手动执行相同的操作,但并非总是可以执行此操作不会产生该错误。
还有其他方法可以在打字稿中实现此功能吗?
class GenericClass<T> {
public value: T
constructor(_value: T){
this.value = _value
}
setValue(_value:T){
this.value = _value
}
}
class ContainerClass {
sthString = new GenericClass('sdad')
sthBoolean = new GenericClass(true)
setAnyMember = (field: 'sthString' | 'sthBoolean', val: string | boolean) => {
this[field].value = val
}
setViaFunction = (field: 'sthString' | 'sthBoolean', val: string | boolean) => {
this[field].setValue(val)
}
}
答案 0 :(得分:0)
我猜分配没有失败,因为类型匹配
this[field].value
的类型为 string | boolean
和 val 也是。
如果您尝试调用 this[field].setValue(val)
打字稿不够聪明,无法自行找出类型:/。
我想不出一种聪明的方法来帮助打字稿自动选择正确的类型。
我会尝试通过不传递字段并通过 val 类型调用正确的方法来解决此问题
class ContainerClass {
sthString = new GenericClass('sdad')
sthBoolean = new GenericClass(true)
setAnyMember = (field: 'sthString' | 'sthBoolean', val: string | boolean) => {
this[field].value = val
}
setViaFunction = (val: string | boolean) => {
if (typeof val === "string"){
this.sthString.setValue(val)
} else {
this.sthBoolean.setValue(val)
}
}
}
答案 1 :(得分:0)
让我们定义我们的工具类型:
class GenericClass<T> {
public value: T
constructor(_value: T) {
this.value = _value
}
setValue(_value: T) {
this.value = _value
}
}
// infer generic parameter from GenericClass
type GetGeneric<T> = T extends GenericClass<infer G> ? G : never
{
type Test = GetGeneric<GenericClass<boolean>> // boolean
}
// infer all props which are instances of GenericClass
type GetProps<T> = {
[Prop in keyof T]: T[Prop] extends GenericClass<any> ? Prop : never
}[keyof T]
{
type Test = GetProps<ContainerClass> // "sthString" | "sthBoolean"
}
// infer correct type of GenericClass constructor argument
type GetValues<Obj, Prop> = Prop extends GetProps<Obj> ? GetGeneric<Obj[Prop]> : never
{
type Test = GetValues<ContainerClass, 'sthString'> // string
}
class ContainerClass {
sthString = new GenericClass('sdad')
sthBoolean = new GenericClass(true)
/**
* Field is one of "sthString" | "sthBoolean"
*/
setAnyMember<Field extends GetProps<this>>(
/**
* this is a Record with Field keys and appropriate GenericClass instances
*/
this: Record<Field, GenericClass<GetValues<this, Field>>>,
field: Field, // "sthString" | "sthBoolean"
val: GetValues<this, Field> // get value by Field key
) {
this[field].setValue(val) // ok
}
}
const x = new ContainerClass();
x.setAnyMember('sthBoolean', true) // ok
x.setAnyMember('sthString', 'str') // ok
x.setAnyMember('sthBoolean', 32) // expected error
x.setAnyMember('sthString', false) // expected error
我使用 this
输入 setAnyMember
来给 TS 一些线索。
我还使非法状态无法表示,您不能将无效参数传递给 setAnyMember