用于检查数组中重复项的通用 Typescript 函数
Generic Typescript function to check for duplicates in an array
我正在尝试创建一个通用的 Typescript 函数来检查数组是否包含重复项。例如:
interface Student {
name: string;
class: string;
};
const students: Student[] = [
{ name: 'John Smith', class: 'Science' },
{ name: 'Edward Ryan', class: 'Math' },
{ name: 'Jessica Li', class: 'Social Studies'},
{ name: 'John Smith', class: 'English'}
];
这就是数据。
这就是我要对数据执行的操作:
const registerStudents = async (students: Student[]): Promise<void> {
checkDuplicate(students, existingState); //This is the function I want to build
const response = await axios.post('/students/new', students)
existingState.push(response); //pushes newly registers students to the existing state
};
关于checkDuplicate()
,我想让它成为一个通用函数,但我在逻辑上苦苦挣扎。
export const checkDuplicate = <T>(items: T[], existingState: T[]): void {
//checks if the items have any duplicate names, in this case, it would be 'John Smith', and if so, throw an error
//Also checks if items have any duplicate names with the existingState of the application, and if so, throw an error
if (duplicate) {
throw new Error('contains identical information')
};
};
它有点复杂,我一直无法弄清楚使用打字稿的逻辑。任何关于我如何实现它的建议都将不胜感激!
一个合理的方法是让 checkDuplicate()
接受一个通用类型 T[]
的数组 items
和另一个类型 [=18] 的数组 keysToCheck
=],其中 K
是类似键的类型(或 union 的类似键类型),其中 T
是具有 K
中的键的类型,并且这些键的值为 string
s。即checkDuplicate()
的调用签名应该是
declare const checkDuplicate: <T extends Record<K, string>, K extends PropertyKey>(
items: T[],
keysToCheck: K[]
) => void;
此函数应遍历 items
和 keysToCheck
,如果它找到一个项目,其中 属性 与 a 中的相同 属性 是相同的字符串上一项,它应该会引发错误。
如果你有这样的功能,你可以编写接受 students
和 existingState
的版本,两个 Student
对象数组,如下所示:
function checkDuplicateStudents(students: Student[], existingState: Student[]) {
checkDuplicate([...students, ...existingState], ["name", "class"]);
}
我们 spreading 将 students
和 existingState
数组合并为一个数组,作为 items
传递给 checkDuplicate()
,因为我们正在检查Student
我们将 ["name", "class"]
作为 keysToCheck
.
这是 checkDuplicate()
的可能实现:
const checkDuplicate = <T extends Record<K, string>, K extends PropertyKey>(
items: T[],
keysToCheck: K[]
): void => {
const vals = {} as Record<K, Set<string>>;
keysToCheck.forEach(key => vals[key] = new Set());
for (let item of items) {
for (let key of keysToCheck) {
const val: string = item[key];
const valSet: Set<string> = vals[key]
if (valSet.has(val)) {
throw new Error(
'contains identical information at key "' +
key + '" with value "' + val + '"');
};
valSet.add(val);
}
}
}
它的工作方式是我们创建一个名为 vals
的对象,并为 keysToCheck
的每个元素 key
创建一个键。每个元素 vals[key]
都是我们已经看到的 key
字符串的 Set
。每次我们在 items
数组中的任何 item
中看到带有键 key
的 string
值 属性 val
时,我们检查集合是否在 vals[key]
中有 val
。如果是这样,我们之前已经看到这个键的这个值,所以我们抛出一个错误。如果没有,我们将其添加到集合中。
(请注意,可以用 Record<string, true | undefined>
形式的普通对象替换 Set<string>
,如 Mimicking sets in JavaScript? 所示,但我在这里使用 Set
为清楚起见。)
好的,让我们根据您的示例进行测试:
checkDuplicateStudents(students, []);
// contains identical information at key "name" with value "John Smith"
看起来不错。它会在运行时抛出错误并正确识别重复数据。
我正在尝试创建一个通用的 Typescript 函数来检查数组是否包含重复项。例如:
interface Student {
name: string;
class: string;
};
const students: Student[] = [
{ name: 'John Smith', class: 'Science' },
{ name: 'Edward Ryan', class: 'Math' },
{ name: 'Jessica Li', class: 'Social Studies'},
{ name: 'John Smith', class: 'English'}
];
这就是数据。
这就是我要对数据执行的操作:
const registerStudents = async (students: Student[]): Promise<void> {
checkDuplicate(students, existingState); //This is the function I want to build
const response = await axios.post('/students/new', students)
existingState.push(response); //pushes newly registers students to the existing state
};
关于checkDuplicate()
,我想让它成为一个通用函数,但我在逻辑上苦苦挣扎。
export const checkDuplicate = <T>(items: T[], existingState: T[]): void {
//checks if the items have any duplicate names, in this case, it would be 'John Smith', and if so, throw an error
//Also checks if items have any duplicate names with the existingState of the application, and if so, throw an error
if (duplicate) {
throw new Error('contains identical information')
};
};
它有点复杂,我一直无法弄清楚使用打字稿的逻辑。任何关于我如何实现它的建议都将不胜感激!
一个合理的方法是让 checkDuplicate()
接受一个通用类型 T[]
的数组 items
和另一个类型 [=18] 的数组 keysToCheck
=],其中 K
是类似键的类型(或 union 的类似键类型),其中 T
是具有 K
中的键的类型,并且这些键的值为 string
s。即checkDuplicate()
的调用签名应该是
declare const checkDuplicate: <T extends Record<K, string>, K extends PropertyKey>(
items: T[],
keysToCheck: K[]
) => void;
此函数应遍历 items
和 keysToCheck
,如果它找到一个项目,其中 属性 与 a 中的相同 属性 是相同的字符串上一项,它应该会引发错误。
如果你有这样的功能,你可以编写接受 students
和 existingState
的版本,两个 Student
对象数组,如下所示:
function checkDuplicateStudents(students: Student[], existingState: Student[]) {
checkDuplicate([...students, ...existingState], ["name", "class"]);
}
我们 spreading 将 students
和 existingState
数组合并为一个数组,作为 items
传递给 checkDuplicate()
,因为我们正在检查Student
我们将 ["name", "class"]
作为 keysToCheck
.
这是 checkDuplicate()
的可能实现:
const checkDuplicate = <T extends Record<K, string>, K extends PropertyKey>(
items: T[],
keysToCheck: K[]
): void => {
const vals = {} as Record<K, Set<string>>;
keysToCheck.forEach(key => vals[key] = new Set());
for (let item of items) {
for (let key of keysToCheck) {
const val: string = item[key];
const valSet: Set<string> = vals[key]
if (valSet.has(val)) {
throw new Error(
'contains identical information at key "' +
key + '" with value "' + val + '"');
};
valSet.add(val);
}
}
}
它的工作方式是我们创建一个名为 vals
的对象,并为 keysToCheck
的每个元素 key
创建一个键。每个元素 vals[key]
都是我们已经看到的 key
字符串的 Set
。每次我们在 items
数组中的任何 item
中看到带有键 key
的 string
值 属性 val
时,我们检查集合是否在 vals[key]
中有 val
。如果是这样,我们之前已经看到这个键的这个值,所以我们抛出一个错误。如果没有,我们将其添加到集合中。
(请注意,可以用 Record<string, true | undefined>
形式的普通对象替换 Set<string>
,如 Mimicking sets in JavaScript? 所示,但我在这里使用 Set
为清楚起见。)
好的,让我们根据您的示例进行测试:
checkDuplicateStudents(students, []);
// contains identical information at key "name" with value "John Smith"
看起来不错。它会在运行时抛出错误并正确识别重复数据。