【发布时间】:2022-01-03 01:25:43
【问题描述】:
所以我有这些类型:
type car = {
id: number;
horsePower?: number;
date: Date;
};
type book = {
id: string;
title?: string;
date: Date;
};
现在我想创建一个通用函数,它接受horsePower 或title 之类的参数,并在cars 或books 的列表中搜索重复项。所以搜索参数和id的类型可以不同,所以string|number两者都可以。
但是传入的key和value必须是同一类型,string或者number。
我试过这种方法:
constructor() {
const carList: Array<car> = [{ id: 111, horsePower: 1337 }];
this.ifAlreadyExists(carList, 'horsePower', 1337, 'id', 100);
const bookList: Array<book> = [{ id: '222', title: 'Title 1' }];
this.ifAlreadyExists(bookList, 'title', 'Title 1', 'id', '200');
}
ifAlreadyExists<T, H extends keyof T, K extends keyof T>(
data: Array<T>,
key: Extract<keyof T, string | number>,
value: Extract<T[K], string | number>,
idKey: H,
idValue: T[H]
): boolean {
if (typeof value === 'string' && typeof key === 'string') {
return (
data.filter(
(item) =>
item[idKey] !== idValue &&
item[key] &&
value &&
item[key].trim().toLowerCase() ===
value.trim().toLowerCase()
).length === 0
);
} else {
return (
data.filter(
(item) =>
item[idKey] !== idValue &&
item[key] &&
value &&
item[key] === value
).length === 0
);
}
}
复制:https://codesandbox.io/s/angular-11-playground-forked-y9ku0?file=/src/app/app.component.ts
但是当我想进行特定类型的调用时,它会失败:
Property 'trim' does not exist on type 'T[Extract<keyof T, string | number> & string]'.ts(2339)
我如何告诉 typescript,传递的 key 与传递的 value 的类型匹配。那么item[key] 只能是string 或number 的类型
【问题讨论】:
-
您可能会惊讶地发现
item[key]实际上可能是number? Observe...。编译器在技术上是正确的抱怨。大概你应该只是假设这不会发生and use a type assertion 或be extra careful(不确定如果违反了你想做什么)或其他什么。我很高兴将这些写下来作为答案;但是,如果您仍有未满足的需求,请edit 指定问题。 -
this 是否满足您的需求?这可以防止有人使用
string | number调用函数,但它仍然需要类型断言,因为编译器无法真正理解item[key]和value彼此相关;见ms/TS#30581。让我知道我是否可以将其写为答案,或者您是否需要其他内容。 -
糟糕,这有点像我的代码中的拼写错误(我忘了在调用签名中使用
H)。 this 对你有用吗?如果是这样,我会把它写下来作为答案。如果仍有不满意的用例,请告诉我,我会尽力解决。 -
喜欢this?只需确保更新问题中的示例代码(这样答案看起来就不会突然引入
undefined),如果有机会,我会很乐意写下答案。跨度>
标签: angular typescript typescript-generics