Я изучаю дженерики машинописного текста. Я создал общую функцию, подобную следующей:
function getRandomElement<T>(items: T[]): T {
let ranIndex = Math.floor(Math.random() * items.length);
return items[ranIndex];
}
затем я намеренно вызвал эту функцию и передал только тип (не передавая аргумент в функцию).
let result = getRandomElement<number>;
Затем я ожидал, что компилятор Ts выдаст мне сообщение об ошибке создания оператора результирующей переменной, но ничего не произошло. результат после этого стал функцией ((items: number[]) => number
).
Я хочу больше узнать об этой особенности машинописного текста. Но после некоторого поиска я не нашел никакой важной информации.
Не могли бы вы помочь объяснить эту функцию или дать мне ключевое слово? Спасибо за внимание к моему глупому вопросу.
Машинописный текст @VLAZ добавляет отслеживание его типа. Он отличается от let result = getRandomElement;
типом.
@Калет, но это почти не связано. fungtion fn<T>(x: T): T{}
- это TS можно назвать fn<number>(42)
, который сначала будет удовлетворять общему параметру путем передачи <number>
, а затем удовлетворять обычному параметру с помощью 42
. Если вы опустите (42)
в этом выражении, у вас останется универсальная функция, в которой удовлетворяется только общий параметр, но он не вызывается. На самом деле ничего особенного — у вас есть двухэтапный процесс, но вы делаете только первый шаг. Тогда, естественно, вам остается второй шаг. Хотя специального названия для него нет. Более того, ОП ожидал ошибку с fn<number>
.
По иронии судьбы, то, что вы только что сделали со строкой ниже, вполне нормально для многих языков программирования:
let result = getRandomElement<number>;
Вы просто присвоили функцию переменной, и это полностью справедливо в JavaScript/Typescript. Вот почему TypeScript не будет жаловаться — вы не сделали ничего плохого — пока что ;-)
Обратите внимание, что вы не вызываете функцию... а просто присваиваете ее другой переменной. Это также означает, что вы можете просто вызвать назначенную функцию напрямую, если хотите, например:
const dummyItems = ["one", "two", "three"];
const assignedFunction = getRandomElement<string>;
const resultOfRunningAssignedFunction = assignedFunction(dummyItems);
Эта строка кода (вызов функции) необходима, если вы хотите, чтобы что-то произошло. Другими словами, вам может потребоваться вызвать функцию, чтобы увидеть какой-либо разумный вывод/результат.
getRandomElement<number>
— это выражение экземпляра , реализованное в microsoft/TypeScript#47607 и представленное в TypeScript 4.7.
Мы всегда могли вручную указать аргументы типа универсальной функции при ее вызове, например f<X, Y>(a, b, c)
:
declare const f: <T, U>(x: T, y: U, z: T[]) => [T, U]
// const f: <T, U>(x: T, y: U, z: T[]) => [T, U]
declare const a: X;
declare const b: Y;
declare const c: X[];
f<X, Y>(a, b, c); // calling a generic function
но выражения создания экземпляров позволяют сделать это без его вызова, например f<X, Y>
. То есть теперь можно написать (f<X, Y>)(a, b, c)
, где f<X, Y>
— собственное выражение:
(f<X, Y>)(a, b, c); // calling an instantiation expression
Полученная функция (f<X, Y>)
не является универсальной и может быть сохранена в отдельной переменной:
const g = (f<X, Y>);
// const g: (x: X, y: Y, z: X[]) => [X, Y]
Затем эту функцию можно вызвать повторно с аргументами того же типа:
g(a, b, c);
declare const d: X;
declare const e: Y;
g(d, e, [a, d]);
Это не совсем особенность TS. В JS функции являются первоклассными гражданами: их можно присваивать переменным, передавать в качестве аргументов, возвращать из функций. То же самое вы можете делать, скажем, со строками или числами. И вот что вы сделали — присвоили функцию
getRandomElement
переменнойresult
. Это неотличимо (на уровне языка) отf = () => { console.info("this is a function") }
, когда вы просто присваиваете функцию переменной. Это просто через другую переменную:g = f