英文:
what is the difference between a function with generic type parameter and non-generic function in typescript?
问题
I recently came across a scenario where I thought I might need to use generics and looked into the typescript documentation on generics to understand it correctly. but I am still not clear about the different use cases for using generics over non generics.
以下是要翻译的内容:
interface Type1 {
name: string,
age: 23
}
const function1 = (each: Type1) => {
// some logic...
return 'something';
}
和
interface Type2 {
name: string,
age: 23
}
const function2 = <Type2>(each: Type2) => {
// some logic...
return 'something';
}
I read the documentation for generics multiple times and tried to find the difference in code playground
update 1
const genericTest = <T>(arg: T): T => { return arg; };
const genericTest1 = <T extends Test1>(arg: T): T => {
console.log(arg.name); return arg; }; // this will work
const genericTest2 = <T>(arg: T): T => { console.log(arg.name); return arg; }; // error: Property 'name' does not exist on type 'T'
interface Test1 {
name: string,
age: number
}
const result1 = genericTest<Test1>({ name: 'vishnu', age: 29 });
console.log('result1::> ', result1);
what are some of the use-cases of unrestricted generics (without using extends)??
if I am using unrestricted generics, how can i use the arg inside the function?
Update 2
I found a implementation of a custom array.find method and converted it into generics function. I think I have a pretty good idea of what generics are used for.
loosely speaking, generics is about the ability to handle multiple types safely rather then the type itself
interface Array<T> {
customFind(o: CB<T>): T | undefined;
}
interface CB<T> {
(each: T, index?: number, array?: Array<T>): boolean;
}
Array.prototype.customFind = function<T>(callback: CB<T>) {
for (let i = 0; i < this.length; i++) if(callback(this[i], i, this)) return this[i]
}
const array: number[] = [1,2,3,4,5,6,7]
const result = array.customFind((each)=>{
return each===1
})
console.log(result);
英文:
I recently came across a scenario where I thought I might need to use generics and looked into the typescript documentation on generics to understand it correctly. but I am still not clear about the different use cases for using generics over non generics.
what is the difference between the following snippets?
interface Type1 {
name: string,
age: 23
}
const function1 = (each: Type1) => {
// some logic...
return 'something';
}
and
interface Type2 {
name: string,
age: 23
}
const function2 = <Type2>(each: Type2) => {
// some logic...
return 'something';
}
I read the documentation for generics multiple times and tried to find the difference in code playground
update 1
const genericTest = <T>(arg: T): T => { return arg; };
const genericTest1 = <T extends Test1>(arg: T): T => {
console.log(arg.name); return arg; }; // this will work
const genericTest2 = <T>(arg: T): T => { console.log(arg.name); return arg; }; // error: Property 'name' does not exist on type 'T'
interface Test1 {
name: string,
age: number
}
const result1 = genericTest<Test1>({ name: 'vishnu', age: 29 });
console.log('result1::> ', result1);
what are some of the use-cases of unrestricted generics (without using extends)??
if I am using unrestricted generics, how can i use the arg inside the function?
Update 2
I found a implementation of a custom array.find method and converted it into generics function. I think I have a pretty good idea of what generics are used for.
loosely speaking, generics is about the ability to handle multiple types safely rather then the type itself
interface Array<T> {
customFind(o: CB<T>): T | undefined;
}
interface CB<T> {
(each: T, index?: number, array?: Array<T>): boolean;
}
Array.prototype.customFind = function<T>(callback: CB<T>) {
for (let i = 0; i < this.length; i++) if(callback(this[i], i, this)) return this[i]
}
const array: number[] = [1,2,3,4,5,6,7]
const result = array.customFind((each)=>{
return each===1
})
console.log(result);
答案1
得分: 1
A generic type parameter in a function is useful when you need to reference or reuse a type in some way. In your examples you do not do this.
But let's say you have a function that logs a value and then returns it.
Without generic the best you could is this:
const logAndReturn = (arg: unknown): unknown => {
console.log(arg)
return arg
}
const userA: User = { name: 'Foo', age: 30 }
const userB: User = logAndReturn(userA) // error: cannot assign unknown to user
Now with generics:
const logAndReturn = <T>(arg: T): T => {
console.log(arg)
return arg
}
const userA: User = { name: 'Foo', age: 30 }
const userB: User = logAndReturn(userA) // fine
Now if I pass in a User
I get a User
back, but the function itself doesn't care what I pass in. So this function needs to be generic because the return type depends on the type of arg
.
Another example, say you want a random element from an array.
function getRandomElement<T>(arr: T[]): T {
const index = Math.floor(Math.random() * arr.length)
return arr[index]
}
const users: User[] = [...]
const randomUser = getRandomElement(users) // returns object of type: User
Here you declare a generic T
to be the type for members of the array. Accept an argument that is an array of T
, and then return T
.
Again, you need a generic here because the return type depends on a type that will only be known when the function is called with a specific type elsewhere in your code.
> if I am using unrestricted generics, how can i use the arg inside the function?
Your function typically won't care what the type is, but something downstream will. For example, in my getRandomElement
function above it doesn't matter what the elements in the array actually are to this function, but that just sets the type that will be returned.
If you want to access specific fields of those values, then that is when you need to constrain it.
function filterCool<T extends { isCool: boolean }>(arr: T[]): T {
return arr.filter(item => item.isCool)
}
const users = [{ name: "Abc", isCool: true }, { name: "Def", isCool: false }]
const coolUsers = filterCool(users) // { name: string, isCool: boolean }[]
Here we use T extends { isCool: boolean }
because the function requires isCool
to work, but we want to allow other fields as well.
> loosely speaking, generics is about the ability to handle multiple types safely rather then the type itself
A better way to say it is that generics allow you to accept a type that may differ throughout your program, and it allows you to reference whatever that type is elsewhere.
When one type in a function depends on another type in that function, that usually means you want a generic function.
英文:
A generic type parameter in a function is useful when you need to reference or reuse a type in some way. In your examples you do not do this.
But let's say you have a function that logs a value and then returns it.
Without generic the best you could is this:
const logAndReturn = (arg: unknown): unknown => {
console.log(arg)
return arg
}
const userA: User = { name: 'Foo', age: 30 }
const userB: User = logAndReturn(userA) // error: cannot assign unknown to user
Now with generics:
const logAndReturn = <T>(arg: T): T => {
console.log(arg)
return arg
}
const userA: User = { name: 'Foo', age: 30 }
const userB: User = logAndReturn(userA) // fine
Now if I pass in a User
I get a User
back, but the function itself doesn't care what I pass in. So this function needs to be generic because the return type depends on the type of arg
.
Another example, say you want a random element from an array.
function getRandomElement<T>(arr: T[]): T {
const index = Math.floor(Math.random() * arr.length)
return arr[index]
}
const users: User[] = [...]
const randomUser = getRandomElement(users) // returns object of type: User
Here you declare a generic T
to be the type for members of the array. Accept an argument that is an array of T
, and then return T
.
Again, you need a generic here because the return type depends on a type that will only be known when the function is called with a specific type elsewhere in your code.
> if I am using unrestricted generics, how can i use the arg inside the function?
Your function typically wont care what the type is, but something downstream will. For example, in my getRandomElement
function above it doesn't matter what the elements in the array actually are to this function, but that just sets the type that will be returned.
If you want to access specific fields of those values, then that is when you need to constrain it.
function filterCool<T extends { isCool: boolean }>(arr: T[]): T {
return arr.filter(item => item.isCool)
}
const users = [{ name: "Abc", isCool: true }, { name: "Def", isCool: false }]
const coolUsers = filterCool(users) // { name: string, isCool: boolean }[]
Here we use T extends { isCool: boolean }
because the function requires isCool
to work, but we want to allow other fields as well.
> loosely speaking, generics is about the ability to handle multiple types safely rather then the type itself
A better way to say it is that generics allow you accept a type that may differ throughout your program, and it allows to reference whatever that type is elsewhere.
When one type in a function depends on another type in that function, that usually means you want a generic function.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论