我的目的是编写一个辅助函数,其目的是根据作为第二个参数传递的key
,按字母顺序动态对对象数组(第一个参数)进行排序。
功能:
interface GenericObject {
[key: string]: string;
}
export const sortAlphabetically = (array: Array<GenericObject>, sortBy: keyof GenericObject) => {
let isKeyValid = false;
// check the key exists in the object before attempting to sort by it
if (array.length > 0) {
isKeyValid = array.every(obj => Object.prototype.hasOwnProperty.call(obj, sortBy) && typeof obj[sortBy] === 'string');
}
if (isKeyValid) {
array.sort((a: GenericObject, b: GenericObject) =>
a[sortBy].toLowerCase() < b[sortBy].toLowerCase()
? -1
: a[sortBy].toLowerCase() > b[sortBy].toLowerCase()
? 1
: 0,
);
return array;
} else {
return;
}
};
所以现在,即使在能够测试我的功能之前,如果我尝试这样做:
export interface Person {
name: string;
surname: string;
}
const people: Person[] = [
{name: 'John', surname: 'Smith'},
{name: 'Tony', surname: 'Denver'},
{name: 'Mary', surname: 'Howard'},
]
sortAlphabetically(people, 'name');
或者这个:
export interface Car {
model: string;
make: string;
}
const cars: Car[] = [
{model: 'Golf', make: 'Volkswagen'},
{model: 'X1', make: 'BMW'},
{model: 'Clio', make: 'Renault'},
]
sortAlphabetically(cars, 'make');
我收到错误:
TS2345:“Person[]”类型的参数不可分配给“GenericObject[]”类型的参数。类型“Person”不可分配给类型“GenericObject”。 “Person”类型中缺少索引签名。
Car[]
也会发生同样的情况。
作为辅助函数,关键点是它需要适应将在数组内传递的任何类型的对象,而不会提示类型。
因此,我非常确定问题出在我定义 GenericObject
的方式上。
有人可以指出我在这里缺少什么吗?非常感谢。
最佳答案
嗯,首先要说的是正确的实现会很麻烦。
您寻求什么:
- 传递一个数组
- 传递属于字符串属性的键
- 按该键对数组进行排序。
对于上述内容,您需要做一些事情:
- 缩小关键参数范围,仅允许字符串属性
GenericObject
类型不足以单独提供此功能- 您需要一些仅过滤字符串属性的类型映射器
- 由于
GenericObject
和Person
类型之间没有关系,因此您无法执行此转换:array.sort((a: GenericObject, b: GenericObject )
- 如果将该数组类型泛化为
任何
类型,那么这将不起作用:a[sortBy].toLowerCase()
,因为.toLowerCase()
必须适用于任何类型的对象属性。 因此,您需要一个类型保护来将该属性缩小为GenericObject
所以 TL;DR
interface GenericObject {
[key: string]: string;
}
type FilterFlags<Base, Condition> = {
[Key in keyof Base]:
Base[Key] extends Condition ? Key : never
};
type AllowedNames<Base, Condition> =
FilterFlags<Base, Condition>[keyof Base];
type SubType<Base, Condition> =
Pick<Base, AllowedNames<Base, Condition>>;
export function sort<T>(array: Array<T>, sortBy: keyof SubType<T, string>) {
let isKeyValid = false;
// check the key exists in the object before attempting to sort by it
if (array.length > 0) {
isKeyValid = array.every(obj => Object.prototype.hasOwnProperty.call(obj, sortBy));
}
if (isKeyValid) {
array.sort((a, b) =>
(isGeneric(a, sortBy) && isGeneric(b, sortBy)) ? // narrow down type to GenericObject so that .toLowerCase becomes valid here
a[sortBy].toLowerCase() < b[sortBy].toLowerCase()
? -1
: a[sortBy].toLowerCase() > b[sortBy].toLowerCase()
? 1
: 0 :
1 // this shouldn't be happening
);
return array;
} else {
return;
}
};
const isGeneric = (a: any, key: keyof typeof a): a is GenericObject =>
typeof a[key] === "string";
export interface Person {
id: number;
name: string;
}
const people: Person[] = [
{ name: 'John', id: 1 },
{ name: 'Tony', id: 2 },
{ name: 'Mary', id: 3 },
]
sort(people, "name"); // this won't allow passing "id" as parameter
SubType
类型映射器取自 here
关于typescript - 类型 'InputType[]' 的参数不可分配给类型 'GenericType[]' Typescript 的参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63738033/