通用接口中的通用原型函数 ? Array<T>.GroupBy<K>(prop): { key: K, 数组: T[] }[]
Generic prototype function in a Generic interface ? Array<T>.GroupBy<K>(prop): { key: K, array: T[] }[]
所以我正在尝试完成这项工作:Array<T>.groupBy<KeyType> (property): {key: KeyType, array: Array<T> }[];
代码如下所示:
type ArrayByParameter<T, KeyType = any> = string | ((item: T) => KeyType);
declare global {
interface Array<T> {
groupBy<KeyType = string>(
property: ArrayByParameter<T,KeyType>
): { key: KeyType; array: T[] }[];
}
}
if (!Array.prototype.groupBy) {
Array.prototype.groupBy = function <KeyType = string>(
property: ArrayByParameter<any, KeyType>
) {
let callbackFunction: (item: any) => any;
if (typeof property === "string") {
callbackFunction = (mapObj) => mapObj[property];
} else if (typeof property === "function") {
callbackFunction = property;
} else {
throw "Parameter is not a string nor a function!";
}
// Edit version of :
return Object.entries(
this.reduce(function (rv, x) {
(rv[callbackFunction(x)] = rv[callbackFunction(x)] || []).push(
x
);
return rv;
}, {}) as { [key: string]: Array<any> }
).map(([key, array]) => {
return { key, array };
});
};
}
type Characters = "A" | "B" | "C";
type Numbers = "1" | "2" | "3";
type SomeKeyType = `${Characters}-${Numbers}`;
// Same thing as below.
type SomeKeyType2 =
| "A-1"
| "A-2"
| "A-3"
| "B-1"
| "B-2"
| "B-3"
| "C-1"
| "C-2"
| "C-3";
type SomeObject = {
c: Characters;
n: Numbers;
// ...
};
const array: SomeObject[] = [
{ c: "A", n: 1 },
{ c: "A", n: 2 },
{ c: "A", n: 2 },
{ c: "B", n: 1 },
// ...
];
const groupByArray: { key: SomeKeyType; array: SomeObject[] }[] =
array.groupBy<KeyType>((obj: SomeObject) => `${obj.c}-${obj.n}`);
Result expected :
[
{key: "A-1", array: [{c:A, n:1, /*...*/}]},
{key:"A-2", array: [{/*...*/},{/*...*/}]},
{key:"B-1", array:[{/*...*/}]},
/*...*/
];
我在“Array.prototype.groupBy”的第 12 行遇到这样的错误:
Type '<KeyType = string>(property: ArrayByParameter<any, KeyType>) => { key: string; array: any[]; }[]' is not assignable to type '<KeyType = string>(property: ArrayByParameter<any, KeyType>) => { key: KeyType; array: any[]; }[]'.
Type '{ key: string; array: any[]; }[]' is not assignable to type '{ key: KeyType; array: any[]; }[]'.
Type '{ key: string; array: any[]; }' is not assignable to type '{ key: KeyType; array: any[]; }'.
Types of property 'key' are incompatible.
Type 'string' is not assignable to type 'KeyType'.
'KeyType' could be instantiated with an arbitrary type which could be unrelated to 'string'.ts(2322)
我认为我的 KeyType 定义有问题,但我找不到解决方案。 KeyType 是一个字符串,但也可以是我现在想要的模板文字类型。
所以 :
- 我怎样才能解决这个问题,使代码正常工作?
- 有没有办法在 Array.prototype.groupBy 函数中获取 T 泛型?
- 现在,T被替换为any,因为我不知道如何在原型定义中使用T。
提前致谢! :)
我该如何解决这个问题才能使 KeyType
匹配?
这里的关键问题是 Object.entries
目前正在将 key
索引器硬编码为 string
而不是允许 K extends PropertyKey
(PropertyKey
是一个可以在 JavaScript).
中索引到对象的所有类型的内置类型别名
没有什么我们不能用额外的环境类型定义来解决的:
declare module "our-global-ambient-module" {
global {
interface Array<T> {
groupBy<KeyType extends PropertyKey = string>(
property: ArrayByParameter<T, KeyType>
): { key: KeyType; array: T[] }[];
}
// What we've added - an overload to `Object.entries`
// that will preserve the key's type.
interface ObjectConstructor {
entries<K extends PropertyKey, V>(object: any): [K, V][];
}
}
}
有没有办法让 T
作为 Array.prototype.groupBy
函数中的泛型
是的,只需添加一个类型参数并 type this
成为该类型:
Array.prototype.groupBy = function <T, KeyType extends PropertyKey = string>(
this: T[],
property: ArrayByParameter<any, KeyType>
)
您还需要在 reduce
调用中注释 {}
的类型:
{} as {[X in KeyType]: T[]}
所以我正在尝试完成这项工作:Array<T>.groupBy<KeyType> (property): {key: KeyType, array: Array<T> }[];
代码如下所示:
type ArrayByParameter<T, KeyType = any> = string | ((item: T) => KeyType);
declare global {
interface Array<T> {
groupBy<KeyType = string>(
property: ArrayByParameter<T,KeyType>
): { key: KeyType; array: T[] }[];
}
}
if (!Array.prototype.groupBy) {
Array.prototype.groupBy = function <KeyType = string>(
property: ArrayByParameter<any, KeyType>
) {
let callbackFunction: (item: any) => any;
if (typeof property === "string") {
callbackFunction = (mapObj) => mapObj[property];
} else if (typeof property === "function") {
callbackFunction = property;
} else {
throw "Parameter is not a string nor a function!";
}
// Edit version of :
return Object.entries(
this.reduce(function (rv, x) {
(rv[callbackFunction(x)] = rv[callbackFunction(x)] || []).push(
x
);
return rv;
}, {}) as { [key: string]: Array<any> }
).map(([key, array]) => {
return { key, array };
});
};
}
type Characters = "A" | "B" | "C";
type Numbers = "1" | "2" | "3";
type SomeKeyType = `${Characters}-${Numbers}`;
// Same thing as below.
type SomeKeyType2 =
| "A-1"
| "A-2"
| "A-3"
| "B-1"
| "B-2"
| "B-3"
| "C-1"
| "C-2"
| "C-3";
type SomeObject = {
c: Characters;
n: Numbers;
// ...
};
const array: SomeObject[] = [
{ c: "A", n: 1 },
{ c: "A", n: 2 },
{ c: "A", n: 2 },
{ c: "B", n: 1 },
// ...
];
const groupByArray: { key: SomeKeyType; array: SomeObject[] }[] =
array.groupBy<KeyType>((obj: SomeObject) => `${obj.c}-${obj.n}`);
Result expected :
[
{key: "A-1", array: [{c:A, n:1, /*...*/}]},
{key:"A-2", array: [{/*...*/},{/*...*/}]},
{key:"B-1", array:[{/*...*/}]},
/*...*/
];
我在“Array.prototype.groupBy”的第 12 行遇到这样的错误:
Type '<KeyType = string>(property: ArrayByParameter<any, KeyType>) => { key: string; array: any[]; }[]' is not assignable to type '<KeyType = string>(property: ArrayByParameter<any, KeyType>) => { key: KeyType; array: any[]; }[]'. Type '{ key: string; array: any[]; }[]' is not assignable to type '{ key: KeyType; array: any[]; }[]'. Type '{ key: string; array: any[]; }' is not assignable to type '{ key: KeyType; array: any[]; }'. Types of property 'key' are incompatible. Type 'string' is not assignable to type 'KeyType'. 'KeyType' could be instantiated with an arbitrary type which could be unrelated to 'string'.ts(2322)
我认为我的 KeyType 定义有问题,但我找不到解决方案。 KeyType 是一个字符串,但也可以是我现在想要的模板文字类型。
所以 :
- 我怎样才能解决这个问题,使代码正常工作?
- 有没有办法在 Array.prototype.groupBy 函数中获取 T 泛型?
- 现在,T被替换为any,因为我不知道如何在原型定义中使用T。
提前致谢! :)
我该如何解决这个问题才能使 KeyType
匹配?
这里的关键问题是 Object.entries
目前正在将 key
索引器硬编码为 string
而不是允许 K extends PropertyKey
(PropertyKey
是一个可以在 JavaScript).
没有什么我们不能用额外的环境类型定义来解决的:
declare module "our-global-ambient-module" {
global {
interface Array<T> {
groupBy<KeyType extends PropertyKey = string>(
property: ArrayByParameter<T, KeyType>
): { key: KeyType; array: T[] }[];
}
// What we've added - an overload to `Object.entries`
// that will preserve the key's type.
interface ObjectConstructor {
entries<K extends PropertyKey, V>(object: any): [K, V][];
}
}
}
有没有办法让 T
作为 Array.prototype.groupBy
函数中的泛型
是的,只需添加一个类型参数并 type this
成为该类型:
Array.prototype.groupBy = function <T, KeyType extends PropertyKey = string>(
this: T[],
property: ArrayByParameter<any, KeyType>
)
您还需要在 reduce
调用中注释 {}
的类型:
{} as {[X in KeyType]: T[]}