泛型<T,K,…,P>其实就可以理解为函数的函数头function(形参),其中的T,K,P等可以理解为函数的形参。
但是在泛型中不叫形参,而叫类型参数。为什么呢,因为只有类型才能作为泛型的参数传入,例如ts中用type,interface,class这种定义的数据叫类型,这种数据就可以作为泛型的类型参数传入,而在js中使用let,var,const定义的叫字面量数据,只能作为函数的参数传入。
所以总结
泛型的参数,是以类型数据作为实际参数传入
函数的参数是以字面量作为实际参数
泛型与函数在使用上可以说一样,所以如何使用泛型可以参考如何函数

我们创建一个完整泛型通常是 (下面是我个人为了方便理解而定义的名称,非专业名称)
类型头+类型名+<类型参数>=类型体
例如
type userType<T,K,P>="name"||"age"
这个type就是类型头,userType就是类型名,
<T,K,P>就是<类型参数>,"name"||"age"就是类型体。
我们创建函数通常是这样
函数头+函数名+(形参)+函数体
例如:

Function add(num1,num2,num3){}

我们发现一个完整的泛型和函数长得非常像。
例如泛型中的类型头(Type,interface,class等)就是函数中的函数头(Function),泛型中的类型名就是函数中的函数名,泛型中的<T,K,P>就是函数中的(形参1,形参2,形参3),泛型中的类型体就是函数中的函数体。

但是泛型的类型头有很多种,例如type,interface,class,而函数头只能是function,这就导致了泛型体有很多种,例如使用type定义的类型,他的类型体interface,class类型头的类型体不一样。但是函数不同,函数的函数头只能是function,所以函数体必须是{函数内部}这个样子。
同时我们在写ts的时候发现定义一个类型时可以不在类型名后加<K,…,P>,这个时候定义的类型就是普通类型,就不叫泛型。

就像我们定义一个变量,字面量,如果不加(形参1,…,形参n),那他就是一个普通的变量