typescript - 如何告诉 TypeScript 只允许具有字符串值的属性作为函数的参数
问题描述
我想编写一个泛型函数,将泛型类型的属性名称作为参数。我需要让 TypeScript 断言该属性的值是特定类型的。考虑以下简化代码:
interface MyObject {
myProp: number;
mySecondProp: string;
myOtherProp: string;
myFlagProp: boolean;
}
const doStuff<T> = (obj: T, propName: SomeType) => { /***/ }
我可以提取特定类型的所有属性(例如string
),但编译器不会确切知道属性的类型:
type StringProps<T> = {
[K in keyof T]: T[K] extends string ? K : never }[keyof T]
}
const doStuff<T> = (obj: T, propName: StringProps<T>) => {
obj[propName].indexOf("a"); // Property 'indexOf' does not exist on type 'T[{ [K in keyof T]: T[K] extends string ? K : never; }[keyof T]]'
}
我能做些什么来让编译器明白它应该只接受字符串属性名称并且值始终是 type string
?
解决方案
Typescript 通常不擅长推断仍然包含未解析类型参数的条件类型。因此,当您调用StringProps<T>
很容易解析为T
函数内部的字符串键时,编译器不会尝试感知T[StringProps<T>]
.
您可以通过其他方式指定参数。您可以为属性键使用另一个类型参数,并指定它T
必须是Record<K, string>
. 对于编译器来说,这将更容易推理:
type StringProps<T> = { [K in keyof T]: T[K] extends string ? K : never }[keyof T];
function doStuff<T>(obj: T, propName: StringProps<T>): void
function doStuff<K extends PropertyKey, T extends Record<K, string>>(obj: T, propName: K): void {
obj[propName].indexOf("a");
}
你会注意到我也保留了你的签名,一个对调用站点上的智能感知表现更好,新签名对实现表现更好。
根据您在函数中执行多少索引,您可能最好只使用断言:
type StringProps<T> = { [K in keyof T]: T[K] extends string ? K : never }[keyof T];
function doStuff<T>(obj: T, propName: StringProps<T>): void{
(obj[propName] as unknown as string).indexOf("a");
}
推荐阅读
- batch-file - Batch-VBScript 发送特定键特定次数
- r - 如何按月/周生成开始和结束日期向量,但使向量的最后一个结束日期以今天结束?
- visual-studio - 使用 VS 在我的 Unity 项目中将“附加到 Unity”按钮替换为“开始”
- javascript - 如何使用 AJAX 向处理程序发送数据
- git - Github 在成功合并后仍然显示分支之间的差异
- python - 从数据框中删除布尔行
- r - 有没有比 for 循环更快的方法在 R 中使用 facet_wrap_paginate?
- javascript - 如何在引导程序 4 上进行响应式布局
- linux - 未找到 Bash 事件
- go - 有没有办法将地图附加到切片?