如何在 Typescript 中使用泛型动态设置特定类型的值
How to dynamically set a value of a specific type using generics in Typescript
假设我有一个通用实用程序 class,它应该与 class 接口,并且有一个方法 setPropertiesToTrue 接受 class 属性列表,并设置这些属性实例里面的 class 为 true.
class SomeObject{
x: boolean
y: boolean
z: string
constructor(x: boolean,y: boolean,z: string){
this.x = x,
this.y = y,
this.z = z
}
}
class ProperySetter<TSomeObject>{
objectContext: TSomeObject
constructor(objectContext: TSomeObject){
this.objectContext = objectContext
}
setPropertiesToTrue(properties: Array<keyof TSomeObject>){
properties.forEach(property => {
this.objectContext[property] = true
})
}
}
const someObject = new SomeObject(false, false, "hello")
const propertySetter = new ProperySetter(someObject);
propertySetter.setPropertiesToTrue(["x", "y"])
console.log(someObject.x) // changed from false to true
console.log(someObject.y) // changed from false to true
console.log(someObject.z) // unchanged
Here 是一个 TS Playground 示例,或多或少是我正在尝试做的事情。
在上面的例子中,(在 playground 的第 22 行),打字稿似乎不知道作为属性传递的键对应于通用 TSomeObject
中的布尔值。所以我得到了错误:
Type 'boolean' is not assignable to type 'TSomeObject[keyof
TSomeObject]'.
这是有道理的,因为 keyof TSomeObject
对应于 TSomeObject 的所有键,而不仅仅是与布尔键对应的键。
有办法解决这个问题吗?
您可以加强输入数组的约束,使其仅包含 boolean
值的键。然而,TS 不够聪明,无法知道数组中的键是有效的。因此,您将只需要强制转换就可以使代码正常工作。以下是对键类型具有更好约束的工作代码示例:
class SomeObject{
x: boolean
y: boolean
z: string
constructor(x: boolean, y: boolean, z: string){
this.x = x,
this.y = y,
this.z = z
}
}
class ProperySetter<TSomeObject>{
objectContext: TSomeObject
constructor(objectContext: TSomeObject){
this.objectContext = objectContext
}
setPropertiesToTrue(properties: Array<keyof { [K in keyof TSomeObject as TSomeObject[K] extends boolean ? K : never]: 0 }>){
properties.forEach(property => {
(this.objectContext as any)[property] = true
})
}
}
const someObj = new SomeObject(true, true, "hey");
const setter = new ProperySetter(someObj);
setter.setPropertiesToTrue(["x", "y"])
// @ts-expect-error not a boolean property
setter.setPropertiesToTrue(["z"]);
假设我有一个通用实用程序 class,它应该与 class 接口,并且有一个方法 setPropertiesToTrue 接受 class 属性列表,并设置这些属性实例里面的 class 为 true.
class SomeObject{
x: boolean
y: boolean
z: string
constructor(x: boolean,y: boolean,z: string){
this.x = x,
this.y = y,
this.z = z
}
}
class ProperySetter<TSomeObject>{
objectContext: TSomeObject
constructor(objectContext: TSomeObject){
this.objectContext = objectContext
}
setPropertiesToTrue(properties: Array<keyof TSomeObject>){
properties.forEach(property => {
this.objectContext[property] = true
})
}
}
const someObject = new SomeObject(false, false, "hello")
const propertySetter = new ProperySetter(someObject);
propertySetter.setPropertiesToTrue(["x", "y"])
console.log(someObject.x) // changed from false to true
console.log(someObject.y) // changed from false to true
console.log(someObject.z) // unchanged
Here 是一个 TS Playground 示例,或多或少是我正在尝试做的事情。
在上面的例子中,(在 playground 的第 22 行),打字稿似乎不知道作为属性传递的键对应于通用 TSomeObject
中的布尔值。所以我得到了错误:
Type 'boolean' is not assignable to type 'TSomeObject[keyof TSomeObject]'.
这是有道理的,因为 keyof TSomeObject
对应于 TSomeObject 的所有键,而不仅仅是与布尔键对应的键。
有办法解决这个问题吗?
您可以加强输入数组的约束,使其仅包含 boolean
值的键。然而,TS 不够聪明,无法知道数组中的键是有效的。因此,您将只需要强制转换就可以使代码正常工作。以下是对键类型具有更好约束的工作代码示例:
class SomeObject{
x: boolean
y: boolean
z: string
constructor(x: boolean, y: boolean, z: string){
this.x = x,
this.y = y,
this.z = z
}
}
class ProperySetter<TSomeObject>{
objectContext: TSomeObject
constructor(objectContext: TSomeObject){
this.objectContext = objectContext
}
setPropertiesToTrue(properties: Array<keyof { [K in keyof TSomeObject as TSomeObject[K] extends boolean ? K : never]: 0 }>){
properties.forEach(property => {
(this.objectContext as any)[property] = true
})
}
}
const someObj = new SomeObject(true, true, "hey");
const setter = new ProperySetter(someObj);
setter.setPropertiesToTrue(["x", "y"])
// @ts-expect-error not a boolean property
setter.setPropertiesToTrue(["z"]);