gpt4 book ai didi

typescript - 参数类型 'a' 和 'left' 不兼容

转载 作者:搜寻专家 更新时间:2023-10-30 21:45:40 24 4
gpt4 key购买 nike

我是 TypeScript 的新用户所以请多多包涵 🤞

⚽ 目标

我正在尝试创建一个通过接受 number | 数组返回 MinHeap(优先级队列)的方法。字符串 |对象 和可选的比较函数(有点像 Array.sort 的函数)。

⩴⩴⩴⩴⩴⩴⩴⩴⩴⩴

🤔 问题代码

演示可用 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] The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.

(parameter) a: T

first error

第二次尝试

while comp = (a: number, b: number) => a - b; 显示

[typescript] Type '(a: number, b: number) => number' is not assignable to type 'Comparor'. Types of parameters 'a' and 'left' are incompatible. Type 'T' is not assignable to type 'number'. (parameter) comp: Comparor | undefined

second error

⩴⩴⩴⩴⩴⩴⩴⩴⩴⩴

主要问题

  1. 为什么即使通过了 if (isNumberArray(args)) 也能识别数字?
  2. 如何使 comp 的类型被正确识别?

附加上下文

请不要犹豫,让我知道如何用更像 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 }]);

Type '{ id: number; weight: number; }' is not assignable to type '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
}

无效的测试用例现在会产生一个更直观的错误:

Expected 2 arguments, but got 1.

关于typescript - 参数类型 'a' 和 'left' 不兼容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55522136/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com