我认为这是可能的,但我有麻烦搜索正确的关键字。我有一个方法,用于设置一个对象的多个属性,我希望它类型安全。
interface ICase {
caseDetails: ICaseDetails;
observations: IObservations;
}
interface ICaseDetails {
a: string;
}
interface IObservations {
b: number;
}
const updateCasePart = (state: ICase, payload: any, propName: keyof ICase) => {
state[propName] = payload
}
有没有一种方法可以输入payload,以便调用函数将被限制为正确的payload类型?我知道我可以做payload: ICaseDetails | IObservations
,但我希望像payload: typeof keyof ICase
这样的东西
1条答案
按热度按时间tcomlyy61#
如标题所示,应按如下方式创建函数generic:
不将
propName
参数注解为keyof ICase
类型(等价于联合类型"caseDetails" | "observations"
),我们将其注解为泛型类型K
,该泛型类型已被约束为keyof ICase
。这允许propName
比keyof ICase
* 更具体 *。例如,如果您将"caseDetails"
作为propName
传入,编译器将推断K
是字符串文字类型"caseDetails"
。注意,
payload
的类型是indexed access typeICase[K]
,意味着ICase
的属性在K
类型的键上的类型,所以如果K
是"caseDetails"
,那么ICase[K]
就是ICaseDetails
,这(大部分)确保了你为payload
传入的值是合适的。赋值
state[propName] = payload
类型检查是因为编译器将赋值的两端视为相同的泛型类型ICase[K]
。让我们来测试一下:
看起来不错。编译器允许有效调用,(大部分)不允许无效调用。
好吧,我一直在说"大部分"。泛型涉及联合时存在类型安全漏洞;如果由于某种奇怪原因,您传入了一个类型为键类型联合的
propName
参数,那么K
将被推断为联合,且ICase[K]
也将是联合,这意味着可能允许错误调用:上面没有错误,但是您有99%的可能性将
"observations"
作为propName
传入,将ICaseDetails
作为payload
传入。如果这真的很重要,可以开始重写
updateCasePart
来减少这种情况的发生......但是由于TypeScript不是完全类型安全的,因此您无法真正防止每一个可能的不安全操作,而且付出的努力会导致回报递减。对于大多数用途来说,像上面这样的泛型函数提供了足够的安全性和可用性,所以我不会在这里进一步离题,详细描述在通往纯粹可靠性的无尽的、越来越危险的道路上可能发生的偏离。
Playground代码链接