例如,我想将 Typescript 类型安全添加到 vanilla Javascript Sort array of objects by string property value解决方案。它接受要排序的对象的 args 键,以确定要排序的键。如果 key 以 -
为前缀,排序相反。
我将如何输入 arg 以接受,例如,"age"
和 "-age"
?
这是我的尝试:
export function dynamicSortMultiple<T extends object, U extends keyof T>(
props: Array<U>,
) {
function dynamicSort(key: U) {
let sortOrder = 1
if (typeof key === 'string' && key.startsWith('-')) {
sortOrder = -1
}
return function (a: T, b: T) {
const result = a[key] < b[key] ? -1 : a[key] > b[key] ? 1 : 0
return result * sortOrder
}
}
return function (obj1: T, obj2: T) {
let i = 0
let result = 0
const numberOfProperties = props?.length
while (result === 0 && i < numberOfProperties) {
result = dynamicSort(props[i])(obj1, obj2)
i++
}
return result
}
}
export interface User {
userId: string
firstName: string
lastName: string
login: string
password: string
rank: number
score: number
age?: number
}
dynamicSortMultiple<User, keyof User>(['firstName', 'score', '-age'])
typescript playground在最后一行我看到错误
Type '"-age"' is not assignable to type 'keyof User'.
有什么方法可以扩展keyof User
是否正确,以便以“-”为前缀的值仍被视为该类型的有效值?即使您完全更换我的解决方案,我也会很感激。
最佳答案
我的变化:
Note: I originally just replaced all your
U
references withkeyof T
, but then pulled it out tosortArg
to facilitate #2.
-
startsWith('-') 情况下的前缀必须给它的逻辑流程(TS 团队一直在改进
TS 编译器的流程分析,所以我打赌有一天这将是自动的)
sort
在代码中读取更好的函数(参见示例用法遵循解决方案代码)。
type sortArg<T> = keyof T | `-${string & keyof T}`
/**
* Returns a comparator for objects of type T that can be used by sort
* functions, were T objects are compared by the specified T properties.
*
* @param sortBy - the names of the properties to sort by, in precedence order.
* Prefix any name with `-` to sort it in descending order.
*/
export function byPropertiesOf<T extends object> (sortBy: Array<sortArg<T>>) {
function compareByProperty (arg: sortArg<T>) {
let key: keyof T
let sortOrder = 1
if (typeof arg === 'string' && arg.startsWith('-')) {
sortOrder = -1
// Typescript is not yet smart enough to infer that substring is keyof T
key = arg.substr(1) as keyof T
} else {
// Likewise it is not yet smart enough to infer that arg is not keyof T
key = arg as keyof T
}
return function (a: T, b: T) {
const result = a[key] < b[key] ? -1 : a[key] > b[key] ? 1 : 0
return result * sortOrder
}
}
return function (obj1: T, obj2: T) {
let i = 0
let result = 0
const numberOfProperties = sortBy?.length
while (result === 0 && i < numberOfProperties) {
result = compareByProperty(sortBy[i])(obj1, obj2)
i++
}
return result
}
}
/**
* Sorts an array of T by the specified properties of T.
*
* @param arr - the array to be sorted, all of the same type T
* @param sortBy - the names of the properties to sort by, in precedence order.
* Prefix any name with `-` to sort it in descending order.
*/
export function sort<T extends object> (arr: T[], ...sortBy: Array<sortArg<T>>) {
arr.sort(byPropertiesOf<T>(sortBy))
}
用法示例:interface User {
name: string
id: string
age?: number
}
const users: User[] = [
{name: 'Harriet Tubman', id: '01', age: 53},
{name: 'John Brown', id: '02', age: 31},
{name: 'John Brown', id: '03', age: 59},
{name: 'James Baldwin', id: '04', age: 42},
{name: 'Greta Thunberg', id: '05', age: 17}
]
// using Array.sort directly
users.sort(byPropertiesOf<User>(['name', '-age', 'id']))
// using the convenience function for much more readable code
sort(users, 'name', '-age', 'id')
关于typescript - 如何扩展 keyof 类型以使其包含 key 的修改版本,例如以 '-' 为前缀?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68278850/