我是TypeScript的新用户,请耐心
我正在尝试创建一种方法,该方法通过接受number | string | object
数组和可选的比较函数(类似于Array.sort的比较函数)来返回MinHeap(优先级队列)。
⩴⩴⩴⩴⩴⩴⩴⩴⩴⩴
Repl.it上的演示。
下面的 useHeap
接受通用数组类型,可选的comp
比较器也接受type参数。
function isNumberArray(o: any[]): o is number[] {
return o.every(n => typeof n === "number");
}
function isStringArray(o: any[]): o is string[] {
return o.every(n => typeof n === "string");
}
// type Unpack<T> = T extends (infer R)[] ? R : T;
interface Comparor<T> {
(left: T, right: T): number;
}
function useHeap<T>(args: T[], comp?: Comparor<T>): T[] {
if (!comp) {
if (isStringArray(args)) {
comp = (a, b) => a < b ? -1 : a > b ? 1 : 0;
console.log(`args is an STRING array!`, ...args, comp);
} else if (isNumberArray(args)) {
console.log(`args is a NUMBER array!`, ...args, comp);
} else {
// throw new Error("You need to pass a comparor for an object array");
console.log(`args is an OBJECT array!`, ...args, comp);
}
} else {
console.log(` comp available!`, ...args, comp);
}
// turn the T[] into a heap using the Comparor
return [] as T[];
}
⩴⩴⩴⩴⩴⩴⩴⩴⩴⩴
当我像下面这样呼叫useHeap
时,
useHeap([1, 2, 3]);
useHeap([1, 2, 3], (a, b) => a * b);
useHeap(["c1", "a1", "b1"]);
useHeap(["c", "a", "b"], (a, b) => a < b ? -1 : a > b ? 1 : 0);
useHeap([{ id: 1, weight: 10 }, { id: 2, weight: 20 }]);
useHeap([{ id: 1, weight: 10 }, { id: 2, weight: 20 }], (a, b) => a.weight - b.weight);
以下内容打印在控制台中。
TypeScript v3.3.3 linux/amd64
args is a NUMBER array! 1 2 3 undefined
comp available! 1 2 3 (a, b) => a * b
args is an STRING array! c1 a1 b1 (a, b) => a < b ? -1 : a > b ? 1 : 0
comp available! c a b (a, b) => a < b ? -1 : a > b ? 1 : 0
args is an OBJECT array! { id: 1, weight: 10 } { id: 2, weight: 20 } undefined
comp available! { id: 1, weight: 10 } { id: 2, weight: 20 } (a, b) => a.weight - b.weight
问题是当我尝试为数字类型的数组分配默认比较器时。
function useHeap<T>(args: T[], comp?: Comparor<T>): T[] {
if (!comp) {
if (isStringArray(args)) {
comp = (a, b) => a < b ? -1 : a > b ? 1 : 0;
console.log(`args is an STRING array!`, ...args, comp);
} else if (isNumberArray(args)) {
// These throw an error
+ comp = (a, b) => a - b;
+ comp = (a: number, b: number) => a - b;
console.log(`args is a NUMBER array!`, ...args, comp);
} else {
}
} else {
console.log(` comp available!`, ...args, comp);
}
// turn the T[] into a heap using the Comparor
return [] as T[];
}
将鼠标悬停在comp = (a, b) => a - b
上,
[打字稿]算术运算的左侧必须为'any','number','bigint'或枚举类型。
(参数)a:T
comp = (a: number, b: number) => a - b;
显示时
[打字稿] 类型“(a:数字,b:数字)=>数字”不可分配给“比较器”类型。 参数“ a”和“ left”的类型不兼容。 类型“ T”不可分配给类型“数字”。 (参数)comp:比较器|未定义
⩴⩴⩴⩴⩴⩴⩴⩴⩴⩴
if (isNumberArray(args))
通过,为什么仍能识别数字?comp
的类型正确识别?请不要犹豫,让我知道如何用更像TypeScript的方式编写它
答案 0 :(得分:1)
我会说这不是一个很好的解决方案。在泛型方法中使用运行时类型检查通常是不好的做法(“泛型”方法的要点是,逻辑应适用于所提供的任何类型)。但是,这是一种更友好的类型的解决方案,可帮助您解决当前的问题:
const stringComparer = <T extends string>(a: T, b: T) => a < b ? -1 : a > b ? 1 : 0;
const numberComparer = <T extends number>(a: T, b: T) => a - b;
function getDefaultComparitor<T>(args: T[]): Comparor<T> | undefined {
if (isStringArray(args)) {
return stringComparer as Comparor<T>;
} else if (isNumberArray(args)) {
return numberComparer as Comparor<T>;
}
return undefined;
}
function useHeap<T>(args: T[], comp?: Comparor<T>): T[] {
if (!comp) {
comp = getDefaultComparitor(args);
if (!comp) {
console.log(` unable to determine default comparitor!`, ...args);
}
} else {
console.log(` comp available!`, ...args, comp);
}
// turn the T[] into a heap using the Comparor
return [] as T[];
}
注意:as Comparer<T>
是代码气味,应提醒您这里有些古怪。
一个更好的解决方案是使用重载在编译时提供错误:
function useHeap(args: string[]);
function useHeap(args: number[]);
function useHeap<T>(args: T[], comp: Comparor<T>);
function useHeap<T>(args: T[], comp?: Comparor<T>) {
// same as above
}
现在,此测试用例将生成错误:
useHeap([{ id: 1, weight: 10 }, { id: 2, weight: 20 }]);
类型'
{ id: number; weight: number; }
'不能分配给类型'number
'。
这不是一个非常有用的错误消息,但是至少可以更早地发现它。您可以通过以下一些更细微的重载来改善错误消息:
type ComparitorParameter<T> = T extends string|number ? []|[Comparor<T>] : [Comparor<T>];
function useHeap<T>(args: T[], ...comp:ComparitorParameter<T>);
function useHeap<T>(args: T[], comp?: Comparor<T>): T[] {
// same as above
}
无效的测试用例现在将产生一个更加直观的错误:
预期2个参数,但得到1个。