学习TypeScript 之 Pick与泛型约束

ts(TypeScript)常用语法

比如有一个联系人列表

export interface Contact{
  name: string; // 姓名
  phone?: string; // 手机号
  email: string; // 邮箱
  avatar: string; // 头像
  userid: string; // id
}

1.Omit去除类型中某些项(官方提供)

现在需要定义一个新的数据类型,新的联系人列表没有邮箱项
可以使用Omit,其源码如下

/**
 * Construct a type with the properties of T except for those in type K.
 */
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

Omit会构造一个除类型K外具有T性质的类型
可以看出需Omit要两个参数,Omit<type,string>:
参数:第一个为继承的type类型,第二个为想要的key的字符串,多个字符串用|分开
使用也很简单:
去除单个,原始类型为联系人列表,新数据数据为没有邮箱项的联系人列表

export type OmitEmailContact = Omit<Contact, 'email' >;
OmitEmailContact{
  name: string;
  phone?: string; 
  avatar: string;
  userid: string;
}

去除多个,原始类型为联系人列表,新数据数据为没有邮箱项与头像的联系人列表

export type OmitEmailAvatarContact = Omit<Contact, 'email' | 'avatar'>;
OmitEmailAvatarContact {
  name: string;
  phone?: string; 
  userid: string;
}

2.Pick选取类型中指定类型(官方提供)

现在联系人列表只要姓名电话即可
从T中选择一组属性,将它们在K中联合

type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

使用如下

export interface ContactPick extends Pick<Contact, 'name' | 'phone'> {}
ContactPick {
  name: string;
  phone?: string; 
}


3.给类型加上指定类型(自定义)

已经定义好了数据类型,现在需要给其中一些加上id这个类型

export type WithId<T, P = string> = T & { id: P };

使用如下

export interface ContactWithId = WithId<Contact>

4.Partial将类型中所有选项变为可选,即加上?(官方提供)

可以使用Partial,其源码如下

/**
 * Make all properties in T optional
 */
type Partial<T> = {
    [P in keyof T]?: T[P];
};

使用如下

export interface PartialContact= Partial<Contact>
PartialContact{
  name?: string; // 姓名
  phone?: string; // 手机号
  email?: string; // 邮箱
  avatar?: string; // 头像
  userid?: string; // id
}

5.Required将类型中所有选项变为必选,去除所有?(官方提供)

可以使用Required,其源码如下

扫描二维码关注公众号,回复: 15382713 查看本文章
/**
 * Make all properties in T required
 */
type Required<T> = {
    [P in keyof T]-?: T[P];
};

使用如下

export interface RequiredContact= Required<Contact>
RequiredContact{
  name: string; // 姓名
  phone: string; // 手机号
  email: string; // 邮箱
  avatar: string; // 头像
  userid: string; // id
}


何为Pick?

type Pick<T, K extends keyof T> = {
	[key in K]: T[key]
}

就是从一个复合类型中,取出几个想要的类型的组合,例如:

// 原始类型
interface TState {
	name: string;
	age: number;
	like: string[];
}
// 如果我只想要name和age怎么办,最粗暴的就是直接再定义一个(我之前就是这么搞得)
interface TSingleState {
	name: string;
	age: number;
}
// 这样的弊端是什么?就是在Tstate发生改变的时候,TSingleState并不会跟着一起改变,所以应该这么写
interface TSingleState extends Pick<TState, "name" | "age"> {};

写到这里,Pick的用法就写完了,但是会有个疑问,extends不是用来继承的么?那为什么可以写在泛型里?有没有人跟我一样的疑惑?
我去查了资料后发现,还是官方文档中有这个解释(所以还是要多看文档,官方文档大多数比外面写的好得多),以下这段内容来自于官方文档。

泛型约束《官方文档传送门

你应该会记得之前的一个例子,我们有时候想操作某类型的一组值,并且我们知道这组值具有什么样的属性。 在 loggingIdentity例子中,我们想访问arg的length属性,但是编译器并不能证明每种类型都有length属性,所以就报错了。

function loggingIdentity<T>(arg: T): T {
    console.log(arg.length);  // Error: T doesn't have .length
    return arg;
}

相比于操作any所有类型,我们想要限制函数去处理任意带有.length属性的所有类型。 只要传入的类型有这个属性,我们就允许,就是说至少包含这一属性。 为此,我们需要列出对于T的约束要求。

为此,我们定义一个接口来描述约束条件。 创建一个包含 .length属性的接口,使用这个接口和extends关键字来实现约束:

interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);  // Now we know it has a .length property, so no more error
    return arg;
}

现在这个泛型函数被定义了约束,因此它不再是适用于任意类型:

loggingIdentity(3);  // Error, number doesn't have a .length property

我们需要传入符合约束类型的值,必须包含必须的属性:

loggingIdentity({length: 10, value: 3});

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

你可以声明一个类型参数,且它被另一个类型参数所约束。 比如,现在我们想要用属性名从对象里获取这个属性。 并且我们想要确保这个属性存在于对象 obj上,因此我们需要在这两个类型之间使用约束。

function getProperty(obj: T, key: K) {
    return obj[key];
}

let x = { a: 1, b: 2, c: 3, d: 4 };

getProperty(x, "a"); // okay
getProperty(x, "m"); // error: Argument of type 'm' isn't assignable to 'a' | 'b' | 'c' | 'd'.

在泛型里使用类类型

在TypeScript使用泛型创建工厂函数时,需要引用构造函数的类类型。比如,

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

一个更高级的例子,使用原型属性推断并约束构造函数与类实例的关系。

class BeeKeeper {
    hasMask: boolean;
}

class ZooKeeper {
    nametag: string;
}

class Animal {
    numLegs: number;
}

class Bee extends Animal {
    keeper: BeeKeeper;
}

class Lion extends Animal {
    keeper: ZooKeeper;
}

function createInstance<A extends Animal>(c: new () => A): A {
    return new c();
}

createInstance(Lion).keeper.nametag;  // typechecks!
createInstance(Bee).keeper.hasMask;   // typechecks!
function getProperty(obj:T,key:K){
         return obj[key];
}
let x={a:1,b:2,c:3,d:4}

猜你喜欢

转载自blog.csdn.net/weixin_51225684/article/details/130944023