前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Key Concepts of TS - GENERICS (泛型)

Key Concepts of TS - GENERICS (泛型)

作者头像
Cellinlab
发布2023-05-17 19:35:06
1790
发布2023-05-17 19:35:06
举报
文章被收录于专栏:Cellinlab's BlogCellinlab's Blog

# Description

代码语言:javascript
复制
function identify (arg: number): number {
  return arg;
}

Of course, in TS, we can specify any so that the functioncan be used for any data type:

代码语言:javascript
复制
function identify (arg: any): any {
  return arg;
}

We can say that this function is a generalization, since it can work with any type of data. But in this case, we have absolutely no information about the type of the returned value.

When using generalizations, we can explicitly specify the type of the argument and thus, within the framework of our example, determine the type of the return value.

代码语言:javascript
复制
function identify<T>(arg: T): T {
  return arg;
}

let numberOutput = identify<number>(5);
let wrongOutput = identify<number>("5"); // Error
let stringOutput = identify<string>("5"); // OK

# Working with Generalized Type Variables

When using generalizations, the compiler assumes that the generalized parameters passed to the function are used correctly. In fact, the compiler treats them as “any data type” or any.

You can describe it as if we are creating an array:

代码语言:javascript
复制
function loggingIdentity<T> (arg: T[]): T[] {
  console.log(arg.length); // Array has a .length, so no error
  return arg;
}

This allows us to use the generalized type variable Tas part of the type we are working with, rather than just as an entire type, which gives us more flexibility.

代码语言:javascript
复制
function loggingIdentity<T>(arg: Array<T>): Array<T> {
  console.log(arg.length); // Array has a .length, so no error
  return arg;
}

# Generalized Types

Defining a generic function type is very similar to defining a type for a regular function. The only difference is that you first need to specify the type of parameters to be passed and the return value, just like when creating a generalized function:

代码语言:javascript
复制
function identity<T>(arg: T): T {
  return arg;
}
let myIdentify: <T>(arg: T) => T = identity;

A different name could be used for the standard parameter, but it is only important that the number of standard parameters and how they are used are consistent.

代码语言:javascript
复制
function identify<T>(arg: T): T {
  return arg;
}
let myIdentify: <U>(arg: U) => U = identify;

You can also write a generic type as a call signature on the type of an object literal:

代码语言:javascript
复制
function identity<T>(arg: T): T {
  return arg;
}
let myIdentify: {<T>(arg: T): T} = identity;

To the description of the first generalized interface.

代码语言:javascript
复制
interface GenericIdentityFn {
  <T>(arg: T): T;
}
function identity<T>(arg: T): T {
  return arg;
}
let myIdentity: GenericIdentityFn = identity;

Moreover, we can specify a generic type for the entire interface, which will make this parameter available to all its methods.

代码语言:javascript
复制
interface GenericIdentityFn<T> {
  (arg: T): T;
}
function identity<T>(arg: T): T {
  return arg;
}
let myIdentity: GenericIdentityFn<number> = identity;

In addition to generic interfaces, you can also create generic classes.

Note that you cannot create generic enumerations andnamespaces.

# Generalized Classes

Generalized classes have the same form as generalized interfaces. They have a list of typical parameters in angle brackets (<>) after the class name.

代码语言:javascript
复制
class GenericNumber<T> {
  zeroValue: T;
  add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };

This is a fairly literal use of the GenericNumber type (lit.a generalized number), but you can see that nothing prevents you from using other types with it, except number.

代码语言:javascript
复制
let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = "";
stringNumeric.add = function(x, y) { return x + y; };
console.log(stringNumeric.add(stringNumeric.zeroValue, "test")); // test

A class has two types: the static part type and the instance type. Generic types are such only in relation to the instance type, but not to the static part type. Therefore, static class members cannot use typical class parameters.

# Limitations of Generalizations

代码语言:javascript
复制
function loggingIdentity<T>(arg: T): T {
  console.log(arg.length); // Error! T doesn't have .length property
  return arg;
}

Instead of working with any possible type, we would like to create a constraint so that the function works with all types that have a property .length.

代码语言:javascript
复制
interface Lengthwise {
  length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length); // Now we know it has a .length property
  return arg;
}

# Using Generic Parameters in Generalization Constraints

You can define a type parameter that will be limited to the type of another type parameter.

代码语言:javascript
复制
function getProperty<T, K extends keyof T>(obj: T, key: K) {
  return obj[key];
}
let x = { a: 1, b: 2, c: 3, d: 4 };
console.log(getProperty(x, "a")); // okay
console.log(getProperty(x, "m")); // error: Argument of type 'm' isn't assignable to 'a' | 'b' | 'c' | 'd'.

# Using Class Types in Generalizations

When creating object factories in TS using generalizations, you must refer to class types in constructor functions.

代码语言:javascript
复制
function create <T>(c: {new(): T; }): T {
  return new c();
}
class SomeClass { }
var obj = create(SomeClass);
console.log(obj.constructor.name); // "SomeClass"

The following example shows how to impose restrictions on the types of classes created using the class factory:

代码语言:javascript
复制
class BeeKeeper {
  hasMask: boolean = false;
}
class ZooKeeper {
  nametag: string = "tag";
}
class Animal {
  numLegs: number = 0;
}
class Bee extends Animal {
  keeper: BeeKeeper = new BeeKeeper();
}
class Lion extends Animal {
  keeper: ZooKeeper = new ZooKeeper();
}
function createInstance<TAnimal extends Animal>(c: new () => TAnimal): TAnimal {
  return new c();
}
console.log(createInstance(Lion).keeper.nametag); // tag  
console.log(createInstance(Bee).keeper.hasMask); // false

# new Keyword

To create a new object in the generalization code, we need to specify that the generalized type T has a constructor. This means that instead of the type: T parameter, we need to specify type: {new(): T;}.

代码语言:javascript
复制
function UserFactory <T>(): T {
  return new T(); // Error: 'T' only refers to a type, but is being used as a value here.
}

To make the interface work, use the word new:

代码语言:javascript
复制
function UserFactory<T> (type: {new(): T;}): T {
  return new type();
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022/4/20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • # Description
  • # Working with Generalized Type Variables
  • # Generalized Types
  • # Generalized Classes
  • # Limitations of Generalizations
    • # Using Generic Parameters in Generalization Constraints
    • # Using Class Types in Generalizations
      • # new Keyword
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档