定义某种类型的通用打字稿排序函数

问题描述 投票:0回答:1

我有一堆对象,它们都有一个类型为

Moment
的属性,但键的名称不同。

我正在尝试使用打字稿编写一个小型实用函数,我可以在其中对这些对象中的任何一个进行排序。 可以朝正确的方向推一些。

interface ExampleType1 {
    startDate: Moment;
    // ... other members
}

interface ExampleType2 {
    dueDate: Moment;
    // ... other members
}

interface ExampleType3 {
    createdAt: Moment;
}

我希望我的函数看起来像这样(半伪代码):

function sortByDateAsc(data: ATypeThatHasAMoment[], keyName: KeyToTheMomentTypeWithinATypeThatHasAMoment) {
    return data.sort((a, b) => {
        // whatever sort logic i use here
        // accessing the Moment object via a[keyName] and b[keyName]
    }
}

我一直在摆弄这样的东西

function sortByDateAsc<T, K extends keyof T>(data: T[], dateKey: K);

虽然函数 T[K] 没有类型? 我不知道如何告诉函数“T[K] 必须是 Moment 类型”

typescript
1个回答
4
投票

你可以这样做:

declare function sortByDateAsc<K extends keyof any, T extends Record<K, Moment>>(
  data: T[], 
  dateKey: K
): T[];

您将

T
限制为
T[K]
Moment
的类型。 这样做的好处是定义简单并且有效……但它可能不会给出很好的 IntelliSense 提示。例如:

declare const ex1arr: ExampleType1[];
sortByDateAsc(ex1arr, "startdate"); // error
//            ~~~~~~ <-- "startdate" not in ExampleType1

这是

ex1arr
上的错误,而不是
"startdate"
上的错误。 此外,它并不建议
"startDate"
作为更正。


您可以使用更复杂的条件类型,如下所示:

type KeysMatching<T, V> = {[K in keyof T]: T[K] extends V ? K : never}[keyof T];
declare function sortByDateAsc<T extends any, K extends KeysMatching<T, Moment>>(
  data: T[], 
  dateKey: K
): T[];

该签名不是限制

T
,而是将
K
限制为
T[K]
Moment
匹配的键。 现在同样的例子给你一个更好的错误:

declare const ex1arr: ExampleType1[];
sortByDateAsc(ex1arr, "startdate"); // error
//                    ~~~~~~~~~~~ <-- does not match "startDate"

当您开始输入

dateKey
参数时,会获得更好的 IntelliSense 提示(它建议
"startDate"
)。

© www.soinside.com 2019 - 2024. All rights reserved.