Typescript 类型初探

157 阅读2分钟

1、泛型

泛型,即能够创建一个可以在多种类型上而不是单一类型上工作的组件。这允许用户使用这些组件并使用他们自己的类型。

举个例子:

function identity(arg: number): number {
    return arg;
}

我们定义的参数类型是number类型,返回类型也是number类型。那么如果想要参数还可以是string类型,以前我们是这么做的。

function identity(arg: any): any {
    return arg;
}

使用any确实可以达到效果,但也是存在问题的。我们期望的是传入的参数跟返回的结果的类型是一致的。这里我们传入参数number类型,返回的可以是任何类型。丢失了返回的值的类型信息。

在这里,我们将使用类型变量,一种特殊的变量,它作用于类型而不是值。

// T 是一个类型的
function identity<T>(arg: T): T {
    return arg;
}
let res = identity<string>("hello world")  // string

// 简单的类型,可以直接被推导出来
let str = identity("hello world") // string

let num = identity<number>(1) // number

// 箭头函数
const f = <T>(arg: T) => T

function loggingIdentity<T>(arg: T): T {
    // 这里会报错,因为arg不一定有length, 比如参数是number类型
    console.log(arg.length);
    return arg;
}

// T[] 等价于 Array<T>
function loggingIdentity<T>(arg: T[]): T {
    // 改为T[],数组类型一定有length
    console.log(arg.length);
    return arg;
}

探讨函数本身的类型以及如何创建通用接口。

函数类型声明,myIdentity 的类型就是 <T>(arg: T) => T

function identity<T>(arg: T): T {
  return arg;
}
 
let myIdentity: <T>(arg: T) => T = identity

//也可以写成这种形式
let myIdentity: { <T>(arg: T): T } = identity

接口官方例子

// 定义一个接口,
interface GenericIdentityFn<T> {
    (arg: T): T;
}

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

let myIdentity: GenericIdentityFn<number> = identity;

泛型类

泛型类,在类名称后面加上<T>,约定类中某些属性或者方法使用的类型。官方案例:

class GenericNumber<NumType> {
    zeroValue: NumType;
    add: (x: NumType, y: NumType) => NumType;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x, y) {
    return x + y;
};

通用约束

之前的例子,我们要使用参数的length属性,可以约束下泛型必须具备length

interface HasLength {
    length: number;
}

 
function loggingIdentity<T extends HasLength>(arg: T): T {
    console.log(arg.length); 
    return arg;
}

在通用约束中使用类型参数

function getProperty<Type, Key extends keyof Type>(obj: Type, key: Key) {
  return obj[key];
}
 
let x = { a: 1, b: 2, c: 3, d: 4 };
 
getProperty(x, "a");
getProperty(x, "m"); // 报错,m 不存在x的key 中

keyof会取出x中的所有的key的unino,结果为'a'|'b'|'c'|'d',m不存在。

使用类,作为类型

When creating factories in TypeScript using generics, it is necessary to refer to class types by their constructor functions.

译文:

当使用泛型在 TypeScript 中创建工厂时,必须通过类的构造函数引用类类型。

function create<Type>(c: { new (): Type }): Type {
    return new c();
}