从联合类型推断泛型类方法的参数



我有这样一个用例,其中我有一个泛型类和一个包含泛型类的多个成员的容器类。我想使用setViaFunction来设置容器类的成员,而不依赖于它们的类型。然而,我得到以下错误:Argument of type 'string | boolean' is not assignable to parameter of type 'never'. Type 'string' is not assignable to type 'never'.(2345)typescript操场链接

还请注意,setAnyMember手动做同样的事情,但并不总是可能做到,不会产生该错误。

在typescript中是否有其他方法实现此功能?

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)
}
}

我猜赋值没有失败,因为类型匹配

this[field].value属于string | boolean类型val也是。

如果你尝试调用this[field].setValue(val), typescript不够聪明,无法自己找出类型:/.

我想不出一个聪明的方法来帮助typescript自动选择正确的类型。

我将尝试通过不传递field并通过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)
}
}
}

让我们定义util类型:

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

游乐场

我在setAnyMember中使用this类型给TS一些线索。我还使非法状态不可表示,你不能传递无效参数给setAnyMember

最新更新