What are the difference between generic Type(T) vs any in typescript
JavascriptAngularTypescriptGenericsTypesJavascript Problem Overview
generic Type(T)
vs any
in typescript?
What is the difference between Function 1
function identity(arg: any): any {
return arg;
}
Function 2
function identity<T>(arg: T): T {
return arg;
}
Function 3
function identity<T>(arg: T[]): T[] {
return arg;
}
>Function 1 & 3 is accepted if we passing any kind of data type
, But the function 2 does not accept if we pass an array
. generic type is accepting all kind of data type on compile time. but here why it does not accept?
Also which function is good for better performance ( function 1 or function 3)?
Javascript Solutions
Solution 1 - Javascript
There is no difference if this is identity function that just returns an argument and used without type restrictions:
const foo: any = fn(['whatever']);
And there is a difference for typed code:
const foo: string = fn('ok');
const bar: string = fn([{ not: 'ok' }]);
Also, the usage of generic type provides semantics. This signature suggests that the function is untyped and returns anything:
function fn(arg: any): any { ... }
This signature suggests that the function returns the same type as its argument:
function fn<T>(arg: T): T { ... }
Real functions are usually more meaningful than just return arg
example. Generic type can benefit from type restrictions (while any
obviously can't):
function fn<T>(arg: T[]): T[] {
return arg.map((v, i) => arg[i - 1]);
}
But the benefits become more obvious when the function is used in conjunction with other generic classes and generic functions (and eliminated if non-generics are involved):
function fn<T>(arg: T[]): T[] {
return Array.from(new Set<T>(arg));
}
This allows to consistently maintain T
type between input (argument) and output (returned value):
const foo: string[] = fn(['ok']);
const bar: string[] = fn([{ not: 'ok' }]);
There cannot be any difference in performance because TypeScript types exist only on design time.
Solution 2 - Javascript
There is absolutely no performance difference while using any of those methods, because all of these fancy things are just Typescript
sugars and is only for development.
All the type checking is only in compile time ( when Typescript is transpiling/transforming your code back to normal javascript, in your server ).
Either way, when your code is shipped to the user's browser, this is how it looks :
function identity(arg){
return arg;
}
But to explain the differences :
When using any
you'll lose all type checking and safety checking that Typescript is offering, whereas, T
behaves like a variable that will hold the Type that you don't know what it is going to be.
So
function identity<T>(arg: T): T {
return arg;
}
In above, we know that if identify
accepts number
, it will return number
and so on, where as :
function identity(arg: any): any {
return arg;
}
But now, you don't know if arg
and the returned
value are the same type or not.
The other issue that T
will solve is when you're creating a method inside a class and it's expecting an argument which you want to make sure that this method will only accept arguments with the same type of the class's constructor's argument when instantiated.
export class MyClass<T>{
myMethod(anotherArg:T){}
}
So using above :
let str = "string";
let instance = new MyClass(str);
instance.myMethod("other string") // will compile
Where as :
let num = 32423423;
let instance = new MyClass(num);
instance.myMethod("other string") // won't compile
Solution 3 - Javascript
The main usage of T
is to avoid breaking the type when you call a method.
Example:
If you do :
let foo = new Foo();
identity(foo).bar();
The second line will be okay for the compiler, but not because he knows that bar
exists in Foo
type, because it's any
, and any
can have any method.
If you do :
let foo = new Foo();
identity<Foo>(foo).bar();
identity<Foo>(foo).notExistingMethod();
The second line will compile fine, not the third one because Foo
doesn't have a notExistingMethod
method.
any is often used when you need to create something in a more Javascript-way, meaning that you don't really know what is in your object, since Javascript doesn't have any types (I'm not talking about es6
ofc).
Solution 4 - Javascript
Everything is any
on runtime and on top of that it's any
at compile time in JavaScript
. That's why there is TypeScript
to provide type-safety at compile time.
The difference between any
and T
/ T extends
etc. is that you have type safety during compile time for example
protected typeSafety = <T extends String>(args:T):T =>{
return args;
}
this.typeSafety(1); // compile error
this.typeSafety("string"); // good to go
If the function accepts anything you would have the error at runtime which would be too late.