我正在创建一个简单的函数来从打字稿中的数组中删除重复项。
我知道有很多不同的方法可以实现该目标,但我的最终目标是了解类型的工作原理,因此我不需要与现有代码不同的解决方案。
function removeDuplicates(arr, propName) {
const newArr = [];
const lookup = {};
for (let i in arr) {
lookup[arr[i][propName]] = arr[i];
}
for (let i in lookup) {
newArr.push(lookup[i]);
}
return newArr;
}
Run Code Online (Sandbox Code Playgroud)
我正在尝试将该函数转换为 Typescript,但仍停留在声明查找变量的类型上。
这是我的打字稿代码:
function removeDuplicates<T, K extends keyof T>(arr: T[], propName: K) {
const newArr: T[] = [];
const lookup: Partial<Record<T[K], T>> = {};
^^^^ here is the error
for (let i in arr) {
lookup[arr[i][propName]] = arr[i];
}
for (let i in lookup) {
newArr.push(lookup[i]);
}
return newArr;
}
Run Code Online (Sandbox Code Playgroud)
Type 'T[K]' does not satisfy the constraint 'string | number | symbol'
Run Code Online (Sandbox Code Playgroud)
我知道为什么我会收到错误。我收到错误,因为 object.key 的值可以是任何值。但在我的用例中,我想限制开发人员仅传入值为 string | 的键。数字。但我不知道如何在打字稿中做到这一点。
正如您所说,您收到错误是因为 whileK被限制为数组元素 type 中的键T,但没有任何内容表明该键处的属性T[K]本身是类似键的:
function removeDuplicates<T, K extends keyof T>(arr: T[], propName: K) {
const lookup: Partial<Record<T[K], T>> = {}; // error!
}
removeDuplicatesOops([{ a: new Date(), b: "hey" }], "a"); // no error
Run Code Online (Sandbox Code Playgroud)
在 TypeScript 中,如果类型可分配给 ,则该类型是“类似键”的string | number | symbol,并为其指定了一个方便的别名 PropertyKey。
我们不能T[K] 直接约束,但我们可以约束K和/或T使其T[K]受到有效约束。在编译器意识到这是可接受的情况下获得所需行为的最简单方法Partial<Record<T[K], T>>是进行约束T,以便 in 键处的属性类型K必须可分配给PropertyKey:
function removeDuplicates<T extends Record<K, PropertyKey>, K extends keyof T>(
arr: T[], propName: K) {
const lookup: Partial<Record<T[K], T>> = {};
// okay
}
removeDuplicates([{ a: new Date(), b: "hey" }], "a");
// ---------------> ~
// Type 'Date' is not assignable to type 'PropertyKey'.
Run Code Online (Sandbox Code Playgroud)
T是的,对和 的约束K是循环的,但是是以允许的方式(尽管在这种情况下避免循环警告有时很棘手)。请注意,错误出现在参数的键上arr,而不是propName参数本身。如果您确实需要后者,那么您可以K进一步限制,例如
function removeDuplicates<
T extends Record<K, PropertyKey>,
K extends keyof { [P in keyof T as T[P] extends PropertyKey ? P : never]: any }
>(arr: T[], propName: K) {
const lookup: Partial<Record<T[K], T>> = {};
// okay
}
removeDuplicates([{ a: new Date(), b: "hey" }], "a"); // error!
// -------------------------------------------> ~~~
//Argument of type '"a"' is not assignable to parameter of type '"b"'.
Run Code Online (Sandbox Code Playgroud)
但这可能比您想要的更复杂(并且要解释该K约束是如何工作的,我会花很远的时间)。
| 归档时间: |
|
| 查看次数: |
4412 次 |
| 最近记录: |