typescript - 参数“a”和“left”的类型不兼容
问题描述
我是一个新的 TypeScript 用户,所以请多多包涵
⚽ 目标
我正在尝试通过接受一个数组number | string | object
和一个可选的比较函数(有点像Array.sort的函数)来创建一个返回 MinHeap (优先队列)的方法。
⩴⩴⩴⩴⩴⩴⩴⩴⩴⩴
有问题的代码
Repl.it上提供了一个演示。
useHeap
下面接受泛型数组类型,可选的comp
比较器也接受类型参数。
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
节目上,
[typescript] 算术运算的左侧必须是“any”、“number”、“bigint”类型或枚举类型。
(参数)a:T
第二次尝试
同时comp = (a: number, b: number) => a - b;
显示
[打字稿]类型'(a:数字,b:数字)=>数字'不可分配给类型'比较器'。参数“a”和“left”的类型不兼容。类型“T”不能分配给类型“数字”。(参数)comp:比较器| 不明确的
⩴⩴⩴⩴⩴⩴⩴⩴⩴⩴
主要问题
- 为什么即使
if (isNumberArray(args))
通过了号码也会被识别? - 如何
comp
正确识别 's 类型?
附加上下文
请不要犹豫,让我知道如何用更像 TypeScript 的方式编写它
解决方案
我会说这不是一个很好的解决方案。在泛型方法中使用运行时类型检查通常是不好的做法(“泛型”方法的全部意义在于逻辑应该适用于提供的任何类型)。但这是一个对类型更友好的解决方案,可以帮助您解决当前的问题:
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 个。
推荐阅读
- c - CS50 恢复 (Pset4) - 未恢复的图像
- angular - 将 Angular cli 从 8 更新到 10 后出错
- sql - Tree structure data approval hierarchy query
- python - 如何将numpy数组的元素设置为numpy数组?
- arrays - 过滤散列数组以仅保留散列包含数组中包含的键的那些元素?
- postgresql - 在 psql 中打印不同的语言字符
- algorithm - 有没有线性时间复杂度和O(1)辅助空间复杂度的排序算法?
- pandas - 将行附加到数据框
- python - Panda 相当于 R 的 dplyr group_by+mutate
- c - 从不兼容的指针类型传递“插入”的参数 1