Какая разница между общим ключом (T) и любым в typescript
В чем разница между generic key (T)
vs any
в typescript?
Функция 1
function identity(arg: any): any {
return arg;
}
Функция 2 и 3
function identity<T>(arg: T): T {
return arg;
}
function identity<T>(arg: T[]): T[] {
return arg;
}
Функция 1 и 3 принимает, если мы передаем любой тип data type
, но функция 2 не принимает, если мы пройдем array
. общий метод означает, что он принимает все типы данных во время компиляции. но вот почему нам нужно объявить array
в общем методе?
Также какая функция хороша для производительности (функция 1 или функция 3)?
Ответы
Ответ 1
Нет никакой разницы, если это функция идентичности, которая просто возвращает аргумент и используется без ограничений типа:
const foo: any = fn(['whatever']);
И есть разница для типизированного кода:
const foo: string = fn('ok');
const bar: string = fn([{ not: 'ok' }]);
Кроме того, использование универсального типа обеспечивает семантику. Эта сигнатура предполагает, что функция нетипизирована и возвращает что-либо:
function fn(arg: any): any { ... }
Эта сигнатура предполагает, что функция возвращает тот же тип, что и аргумент:
function fn<T>(arg: T): T { ... }
Реальные функции обычно более значимы, чем просто return arg
пример. Общий тип может получить преимущества от ограничений типа (в то время как any
, очевидно, не может):
function fn<T>(arg: T[]): T[] {
return arg.map((v, i) => arg[i - 1]);
}
Но преимущества становятся более очевидными, когда функция используется в сочетании с другими родовыми классами и универсальными функциями (и устраняется, если задействованы не-генерики):
function fn<T>(arg: T[]): T[] {
return Array.from(new Set<T>(arg));
}
Это позволяет последовательно поддерживать тип T
между вводом (аргументом) и выходом (возвращаемым значением):
const foo: string[] = fn(['ok']);
const bar: string[] = fn([{ not: 'ok' }]);
Не может быть никакой разницы в производительности, поскольку типы TypeScript существуют только во время разработки.
Ответ 2
При использовании любого из этих методов нет никакой разницы в производительности, потому что все эти фантазии - это всего лишь Typescript
сахара и предназначены только для разработки.
Вся проверка типов выполняется только во время компиляции (когда Typescript переводит/преобразует ваш код обратно в обычный javascript на вашем сервере).
В любом случае, когда ваш код отправляется в пользовательский браузер, это выглядит так:
function identity(arg){
return arg;
}
Но для объяснения различий:
При использовании any
вы потеряете все проверки типов и проверку безопасности, предлагаемые Typescript, тогда как T
ведет себя как переменная, которая будет удерживать тип, который вы не знаете, что он собирается быть.
So
function identity<T>(arg: T): T {
return arg;
}
В приведенном выше примере мы знаем, что если identify
принимает number
, он вернет number
и т.д., где as:
function identity(arg: any): any {
return arg;
}
Но теперь вы не знаете, являются ли теги arg
и returned
одним и тем же типом.
Другая проблема, которую будет решать T
, - это когда вы создаете метод внутри класса и ожидаете аргумент, который вы хотите удостовериться, что этот метод будет принимать аргументы только с тем же типом аргумента конструктора класса при создании экземпляра.
export class MyClass<T>{
myMethod(anotherArg:T){}
}
Итак, используя выше:
let str = "string";
let instance = new MyClass(str);
instance.myMethod("other string") // will compile
Где как:
let num = 32423423;
let instance = new MyClass(num);
instance.myMethod("other string") // won't compile
Ответ 3
Все время any
во время выполнения, а поверх этого оно any
во время компиляции в JavaScript
. Вот почему TypeScript
обеспечивает безопасность типов во время компиляции.
Разница между any
и T
/T extends
и т.д. заключается в том, что у вас есть безопасность типа во время компиляции, например
protected typeSafety = <T extends String>(args:T):T =>{
return args;
}
this.typeSafety(1); // compile error
this.typeSafety("string"); // good to go
Если функция принимает что-либо, у вас будет ошибка во время выполнения, которая будет слишком поздней.
Ответ 4
Основное использование T
заключается в том, чтобы избежать нарушения типа при вызове метода.
Пример:
Если вы выполните:
let foo = new Foo();
identity(foo).bar();
Вторая строка будет в порядке для компилятора, но не потому, что он знает, что bar
существует в типе Foo
, потому что он any
и any
может иметь любой метод.
Если вы выполните:
let foo = new Foo();
identity<Foo>(foo).bar();
identity<Foo>(foo).notExistingMethod();
Вторая строка будет компилироваться отлично, а не третья, потому что Foo
не имеет метода notExistingMethod
.
любой часто используется, когда вам нужно создать что-то более чем в Javascript-способе, что означает, что вы действительно не знаете, что находится в вашем объекте, поскольку Javascript не имеет каких-либо типов (я не говорю о es6
ofc).