typescript - TypeScript 重载实现与签名不匹配
问题描述
我想使用 TypeScript 的重载功能来创建一个函数,该函数根据传入的参数返回不同的类型。我设法让它工作,但编译器无法在重载函数的实现中捕获错误。
下面的示例来自TypeScript 文档(见下文)。该函数接受两种不同类型的参数:
object
: 期望返回类型number
number
: 期望返回类型object
// With incompatible types
const suits = ["hearts", "spades", "clubs", "diamonds"];
function pickCard(x: { suit: string; card: number }[]): number;
function pickCard(x: number): { suit: string; card: number };
function pickCard(x): any {
if (typeof x == "object") {
let pickedCard = Math.floor(Math.random() * x.length);
// This part does not match the overload definition. The signature
// expect a `number` but we provide a `string`. The compiler does
// not throw an error in that case.
return pickedCard.toString();
} else if (typeof x == "number") {
let pickedSuit = Math.floor(x / 13);
return { suit: suits[pickedSuit], card: x % 13 };
}
}
const card = pickCard([{ suit: 'hearts', card: 5 }])
card.toFixed() // throw a runtime error: card.toFixed is not a function
// With compatible types
type Hand = { suit: string; card: number };
type HandWithScore = Hand & { score: number }
const suits = ["hearts", "spades", "clubs", "diamonds"];
function pickCard(x: Hand[]): HandWithScore;
function pickCard(x: number): Hand;
function pickCard(x): HandWithScore | Hand {
if (typeof x == "object") {
let pickedCard = Math.floor(Math.random() * x.length);
// This part does not match the overload definition.
return { suit: 'hearts', card: x % 13 };
} else if (typeof x == "number") {
let pickedSuit = Math.floor(x / 13);
return { suit: suits[pickedSuit], card: x % 13 };
}
}
const card = pickCard([{ suit: 'hearts', card: 5 }])
card.score.toFixed() // throw a runtime
实现与重载的定义不匹配,并且在这种情况下编译器不会警告我们,这意味着我们可能在运行时遇到问题,因为我们期望 anumber
但我们实际上得到了 a string
。是否期望编译器不会抛出?
您可以在 TypeScript 操场内测试示例。
解决方案
TypeScript 编译器无法分析代码的逻辑以确保其符合合约。我很惊讶地发现它无法识别您从应该返回数字或对象的函数返回字符串的事实,但能够做到这一点很可能在“待办事项”列表中(有很多事情要做),只是还没有到达那里。我倾向于认为它的优先级相当低,因为它无论如何都无法确保正确性,因为它无法分析逻辑流程。
如果为卡片定义类型,则可以指定number | Card
而不是any
实现:
const suits = ["hearts", "spades", "clubs", "diamonds"];
type Card = { suit: string; card: number; };
function pickCard(x: Card[]): number;
function pickCard(x: number): Card;
function pickCard(x): number | Card {
if (typeof x == "object") {
const cards = x as Card[];
let pickedCard = Math.floor(Math.random() * cards.length);
return pickedCard.toString(); // <========================== Compilation error
} else if (typeof x == "number") {
const n = x as number;
let pickedSuit = Math.floor(n / 13);
return { suit: suits[pickedSuit], card: x % 13 };
}
}
const card = pickCard([{ suit: 'hearts', card: 5 }])
card.toFixed()
操场上。
这不能帮助您解决没有正确分支的情况,但它可以帮助您解决从应该返回数字或卡片的函数返回字符串的情况。
(也许你可以在不定义类型的情况下让它工作,但我不能立即这样做,无论如何,所有重新输入似乎都有问题。)
如果实现很重要,您甚至可以将其与我之前提出的将实现拆分为它们自己的类型安全函数的建议结合起来:
const suits = ["hearts", "spades", "clubs", "diamonds"];
type Card = { suit: string; card: number; };
function pickCard(x: Card[]): number;
function pickCard(x: number): Card;
function pickCard(x): number | Card {
if (typeof x == "object") {
return pickCard_Cards(x as Card[]);
} else if (typeof x == "number") {
return pickCard_number(x as number);
}
}
// These wouldn't be exported
function pickCard_Cards(cards: Card[]): number {
let pickedCard = Math.floor(Math.random() * cards.length);
return pickedCard.toString(); // <========================== Compilation error
}
function pickCard_number(n: number): Card {
let pickedSuit = Math.floor(n / 13);
return { suit: suits[pickedSuit], card: x % 13 };
}
const card = pickCard([{ suit: 'hearts', card: 5 }])
card.toFixed()
...以便单独检查每个分支的逻辑(您不会意外地Card[]
从应该返回 a 的分支返回 a number
,反之亦然)。
推荐阅读
- python - TypeError:不支持的操作数类型 -:“BatchDataset”和“float”。我无法使用 tensorflow 从谷歌驱动器加载未标记的图像
- javascript - 如何在mongodb中使用聚合和匹配?
- android - 错误:找不到符号导入 my.package.name.Class
- java - 在此 java 代码中使用引用变量
- azure - Visual Studio 中的 Azure 服务总线托管标识返回 401 - 令牌颁发者无效
- javascript - 如何从 router.post 上的 URL 获取参数?
- javascript - 模板数据未传递到 Django view.py
- python - 错误:scikit-image 的构建轮失败
- ios - 使用 SceneKit 时,动画会在短时间内暂停或停止其他动作和动画
- python - Plotly:行数 > 500 时不显示范围滑块