#typescript
Вопрос:
Я читаю руководство по машинописи, и мне трудно понять, почему в следующем фрагменте кода есть сообщение об ошибке:
function fn(x: string): void;
function fn(vo) {
// ...
}
// Expected to be able to call with zero arguments
fn();
Вот объяснение, но я не мог его понять, Может ли кто-нибудь объяснить мне, что здесь происходит?
Подпись реализации не видна снаружи. При написании перегруженной функции вы всегда должны иметь две или более сигнатур над реализацией функции.
Комментарии:
1. Что конкретно в сообщении об ошибке неясно? В нем говорится, что у вас должно быть две или более подписей над реализацией, а у вас есть только одна. Кроме того, ваша сигнатура перегрузки не позволяет вызывать функцию с нулевыми аргументами, поэтому непонятно, почему вы ожидаете, что сможете это сделать.
2. Что такое
vo
и почему у него нет аннотации типа? Почему вы используете здесь перегрузки? Без реализации трудно понять, каковы ваши намерения и почему вы удивлены появлением сообщения об ошибке. Кодfunction fn(x: string) {}
, за которым следует,fn()
будет содержать сообщение об ошибке без каких-либо перегрузок вообще… функцияfn()
ожидает, что ее вызовут сstring
аргументом, а вы ему его не дали.
Ответ №1:
Это тоже меня крайне смутило. Исходя из фона Kotlin/Java для Android, я должен сказать, что для понимания перегрузочных машин Typescript требуется некоторое время.
Во-первых, нам нужно решить, как объявить overload
в Typescript
Проблема 1: Неправильный способ объявления перегрузок [не является причиной проблемы для вопроса]
Моя первоначальная идея об обработке перегрузки состоит в том, чтобы написать следующий код:
function makeDate(timestamp: number): void { /* code */ }
function makeDate(m: number, d: number, y: number): void { /* code */ }
Меня сразу же поразила Duplicate function implementation.ts(2393)
ошибка lint. Сначала я был сбит с толку, так как именно так вы объявляете overload
в Java и Котлине. Однако на самом деле это не так, как вы заявляете overload
в Typescript, и я считаю, что это основная причина проблем.
Ответ на вопрос 1:
Оказывается, в машинописном тексте объявление overload
не является результатом наличия двух методов с одинаковым именем и разной подписью с каждой из их собственных реализаций. Вместо этого сначала определяют методы с одинаковым именем и разными сигнатурами без тела и, наконец, предоставляют метод с реализацией (тело метода), который имеет возможность обрабатывать все ранее объявленные методы без тела.
Concern 2: Incorrect amount of argument for the overload
requirement [cause of issue for the question]
Now that I have figured out the correct way to create overloaded methods in Typescript, I went straight ahead to write the following code:
[код 2.1]
function fn(x: string): void; // <-- Define one way to call method
function fn(x: string, y: string, z: string): void; // <-- Define another way to call method with more param (overloaded way)
function fn(x: string, y?: string, z?: string): void { // <--- provide a method with a body that can handle both previous two declarations
if (y === undefined) {
console.log("branch 1")
} else {
console.log(`branch 2 -> ${x} :: ${y} :: ${z}`)
}
}
fn("x")
fn("xxx", "yyy", "zzz")
Выходы:
$ branch 1
$ branch 2 -> xxx :: yyy :: zzz
В приведенном выше фрагменте кода мы объявили 1 метод с 2 различными перегрузками.
- перегрузка 1 ->
function fn(x: string): void;
- перегрузка 2 -> >
function fn(x: string, y: string, z: string): void;
И оба они обрабатываются «конкретным» методом:
function fn(x: string, y?: string, z?: string): void {
if (y === undefined) {
console.log("branch 1")
} else {
console.log(`branch 2 -> ${x} :: ${y} :: ${z}`)
}
}
Поскольку у этого метода есть тело, именно поэтому я называю его конкретным методом. Также обратите внимание , что этот метод обрабатывает случай с @params: x
и с @params: y and z
необязательностью, делая это, он охватывает вызовы метода { overload1
и overload2
}. И это допустимая перегрузка.
Следуя тому же образу мышления, я пошел дальше и написал следующий код:
[код 2.2]
function fn2(x: string): void;
function fn2(x: string, y: string): void;
function fn2(x: string, y?: string): void {
if (y === undefined) {
console.log("branch 1")
} else {
console.log(`branch 2 -> ${x} :: ${y}`)
}
}
fn2("x")
fn2("x", "y")
Выходы:
$ branch 1
$ branch 2 -> x :: y
Код тоже сработал, как я и подозревал. Поэтому я написал еще немного кода:
[код 2.3]
function fn3(): void;
function fn3(x?: string): void {
if (x === undefined) {
console.log("branch 1")
} else {
console.log(`branch 2 -> ${x}`)
}
}
fn3()
fn3("x")
Но на этот раз код не сработал и tsc
жалуется:
Playground.ts:219:5 - error TS2554: Expected 0 arguments, but got 1.
219 fn3("x")
~~~
Found 1 error.
Теперь настало время, когда мы должны потратить некоторое время на понимание цитаты из документации:
Подпись реализации не видна снаружи. При написании перегруженной функции вы всегда должны иметь две или более сигнатур над реализацией функции.
Это было очень запутанно, если вы переосмыслите это, оказывается, вы можете просто понять это как «У вас должно быть 2 аргументов, чтобы выполнять перегрузки», вот почему пример кода [code 2.1]
и [code 2.2]
работал. С:
- Для
[code 2.1]
этого у него было 1 и 3 аргумента. Что соответствует требованиям указанной документации - Ибо
[code 2.2]
у него было 1 и 2. Что также соответствует требованиям, изложенным в документах. - Однако для
[code 2.3]
него было 0 и 1. Это не соответствует требованию о том, что вы всегда должны иметь две или более подписей над реализацией функции в документах, поэтомуtsc
жалуетесь.
И это действительно имеет смысл, так как:
function fn3(): void;
function fn3(x?: string): void {
if (x === undefined) {
console.log("branch 1")
} else {
console.log(`branch 2 -> ${x}`)
}
}
Это то же самое, что просто определить один аргумент с ?
необязательным параметром:
function fn3(x?: string): void {
if (x === undefined) {
console.log("branch 1")
} else {
console.log(`branch 2 -> ${x}`)
}
}
Итак, ответ на вопрос 2:
Объявление метода перегрузки работает только для метода с аргументами 2 и 2 , и для обработки всех случаев, объявленных для перегрузок, требуется метод с телом. Кроме того, это не работает с методами, которые имеют аргументы от 0 до 1, tsc
Expected 0 arguments, but got 1.ts(2554)
в этом случае будут жаловаться. В то же время объявлять перегрузку для методов с аргументами 0 и 1 излишне, так как вы можете просто объявить метод с 1 необязательным параметром.