Skip to main content

Generics (Type Placeholder)

what's generics

泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。

泛型:泛化的類型

我们在声明方法时,当在完成方法功能时如果有未知的数据需要参与,这些未知的数据需要在调用方法时才能确定,那么我们把这样的数据通过形参表示。在方法体中,用这个形参名来代表那个未知的数据,而调用者在调用时,对应的传入实参就可以了

受此啟發,誕生了泛型的概念。

泛型,即類型參數,参数化类型(Parameterized type)。 這個類型參數代表未知的某種通用的類型

how to use generics

generics with function

function identity<T>(value: T)T {
return value;
}

<T> 是我们希望传递给 identity 函数的类型占位符

常见泛型变量: T, Type 表示类型 K, Key 表示对象中键的类型 V, Value 表示对象中值的类型 E, Element 表示元素类型

实际上,T 可以用任何有效名称代替。

(value: T) : T 是将 <T> 链式传递给参数和返回值类型。

// 增加一个新的泛型变量 U
function identity<T, U>(value: T, message: U): T {
console.log(message);
return value;
}

// 在使用函数的时候,再显式指定泛型变量的实际类型
identity<number, string>(1999, '1999')
// 也可以不显式指定,让 TypeScript 自动完成类型推导
identity(1998, 1998)

generics with interface and function

const isObj = <T>(arg: T): boolean => {
// Object.prototype.toString.call('hhh').slice(8,-1) === 'Object'
return (
typeof arg === 'object' &&
!Array.isArray(arg) &&
arg !== null
)
}

interface defineArg<T> {
value: T,
is: boolean
}

const isTrue = <T>(arg: T): defineArg<T> => {
if (Array.isArray(arg) && !arg.length) {
return { value: arg, is: false}
}
if (isObj(arg) && !Object.keys(arg as keyof T).length) {
return { value: arg, is: false}
}
return { value: arg, is: !!arg}
}

console.log(isTrue(''))
console.log(isTrue(1))
console.log(isTrue(0))
console.log(isTrue(null))
console.log(isTrue({}))
console.log(isTrue([]))
console.log(isTrue([1, 2]))
console.log(isTrue({name: 'nansen'}))
console.log(isTrue(true))
console.log(isTrue(false))
console.log(isTrue(NaN))
console.log(isTrue(-0))
console.log(isTrue(undefined))

generics with interface and extends

interface Id {
id: number
}

function userEcho<T extends Id>(user: T): T {
return user
}

console.log(userEcho({id: 0, name: 'nansen'}))
console.log(userEcho({id: 0}))

more complex example:

interface UserId {
id: number;
}

const getUserProperty = <T extends UserId, K extends keyof T>(
users: T[],
key: K
): T[K][] => {
return users.map((user) => user[key]);
};

let userArray = [
{id: 0, name: 'John', email: 'xxxxxx.com'},
{id: 1, name: 'Ross', email: 'xxxxxx.com'},
{id: 2, name: 'Max', email: 'xxxxxx.com'},
{id: 3, name: 'Halen', email: 'xxxxxx.com'},
];

console.log(getUserProperty(userArray, 'name'));

generics with class