陆陆续续从文档上手TypeScript,发现仍然还是有很多不懂。
比如各种框架的常用类型,ts中内置的常用类型,以及一些容易被忽略和遗忘的点,陆陆续续顺手把他们写到文章中记录起来。
TSkeyofThe
keyofoperator takes an object type and produces a string or numeric literal union of its keys
keyof操作符会将一个对象类型(注意这里是类型并不是值)的key组成联合类型返回。
interface IProps {
name: string;
count: number;
}
type Ikea = keyof IProps; // Ikea = 'name' | 'count'
function testKeyof(props: Ikea): void { }
复制代码extendsTs中extends除了用在继承上,还可以表达泛型约束,通过extends关键字可以约束泛型具有某些属性。
其实
extends关键字表示约束的时候,就是表示要求泛型上必须实现(包含)约束的属性。
Demo比如
function loggingIdentity<T>(arg: T): T {
console.log(arg.length) // Ts语法错误 T可以是任意类型,并不存在length属性
return arg
}
复制代码我们定义一个接口来描述约束条件,创建一个包含 .length 属性的接口,使用这个接口和 extends 关键字来实现约束:
interface Lengthwise {
length: number
}
// 表示传入的泛型T接受Lengthwise的约束
// T必须实现Lengthwise 换句话说 Lengthwise这个类型是完全可以赋给T
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length) // OK
return arg
}
复制代码现在这个泛型函数被定义了约束,因此它不再是适用于任意类型:
loggingIdentity(3); // Error
复制代码我们需要传入符合约束类型的值,必须包含必须的属性:
loggingIdentity({length: 10, value: 3}) // OK
复制代码你可以声明一个类型参数,且它被另一个类型参数所约束。 比如,现在我们想要用属性名从对象里获取这个属性。 并且我们想要确保这个属性存在于对象 obj 上,因此我们需要在这两个类型之间使用约束。
function getProperty<T, K extends keyof T> (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
复制代码表示传入的两个参数,第二个参数被约束成为只能传入
obj的key类型。
ReturnType<Type>Constructs a type consisting of the return type of function
Type.
ResultType<type>接受传入一个函数类型为泛型,返回值为函数的返回类型。
Demotype T0 = ReturnType<() => string>; // type T0 = string
type T1 = ReturnType<(s: string) => void>; // type T1 = void
复制代码查阅
ReturnType源代码中的类型定义,发现使用了infer类型定义。
infer
infer表示在extends条件语句中待推断的类型变量,必须联合extends类型出现。
demotype ParamType<T> = T extends (...args: infer P) => any ? P : T;
interface User {
name: string;
age: number;
}
type Func = (user: User) => void;
type Param = ParamType<Func>; // Param = User
type AA = ParamType<string>; // string
复制代码其实碰到infer关键字简单的将它理解为一个等待推断的类型(我现在不知道,得根据条件(extends)来判断)就可以了。
重点是:
infer跟随extends成双出现。infer P表示类型P是一个待推断的类型。(不使用infer直接P会报错)Record<Keys,Type>构造一个对象类型,其属性键为Keys,属性值为Type。此实用程序可用于将一种类型的属性映射到另一种类型。
type keys = 'name' | 'title' | 'hello';
interface values {
name: string;
label?: number;
}
// Record内置类型可以将 传入的keys联合类型遍历作为key
// 为每一个key的value赋值为 values从而形成一个全新的对象类型返回
const b: Record<keys, values> = {
name: {
name: 'wang',
label: 1,
},
title: {
name: 'hellp',
},
hello: {
name: 'nihao',
},
};
复制代码看看它的源码本质上很简单,就是遍历传入的范型T作为key,将传入的范型value作为值的类型。

Pick<Type, Keys>Pick的定义很简单,就是从传入的Type中跳出对应的Keys属性,从而返回新的类型。
interface Props {
name: string;
label: number;
value: boolean;
}
type ChildrenProps = Pick<Props, 'name' | 'label'>;
复制代码

Parameters<T>
Parameters<T>用于获得函数的参数类型组成的元组类型

源码中这样定义的
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any
? P : never;
复制代码Exclude<T,U>Exclude是进行排除联合类型中的一部分内容,相对于下面的Omit操作符来说Omit是针对于key&value/接口形式的,而Exclude是针对于联合类型来操作的。
let a: string | number;
type CustomType = Exclude<typeof a, string>; // number类型
复制代码Exclude的原理
type Exclude<T, U> = T extends U ? never : T
传入两个泛型
我们这里用 typeof a 也就是 string | number 去代表 T 用 string 属性去代表第二个泛型 U
T extends U 就判断是否string | number 有 string, 有string就返回never,就代表将其排除
Omit<T, K>3.5 版本之后,TypeScript 在 lib.es5.d.ts 里添加了一个
Omit<T, K>帮助类型。Omit<T, K>类型让我们可以从另一个对象类型中剔除某些属性,并创建一个新的对象类型。
比如:
`type User = {`
`id: string;`
`name: string;`
`email: string;`
`};`
`type UserWithoutEmail = Omit<User, "email">;`
`// 等价于:`
`type UserWithoutEmail = {`
`id: string;`
`name: string;`
`};`
复制代码new关键字ts中new()表示构造函数类型。
当我们声明一个类的时候,其实声明的是这个类的实例类型和静态类型两个类型。
比如
// type: { new(): T }
// 表示函数接受的参数type,是一个对象,这个对象有一个构造函数返回T
// 换句话说type是一个类类型
function factory<T>(type: { new (): T }): T {
return new type();
}
class Person {
static myName; // 类的静态属性
public yourName; // 类的实例属性
}
// 传入的范型Person指类的实例类型
const person = factory<Person>(Person);
复制代码typeof 类
ts中通过typeof 类可以获得类的类类型,直接使用类作为类型此时使用的是类的实例类型。
let a: Person; // Person表示类的实例类型
a.yourName;
let b: typeof Person; // typeof Person 表示类的类类型
b.myName;
let c: { new (): Person } = Person; // c为构造函数类型,c拥有一个构造函数,也就是new c() 返回的是Person的实例。表示c是Person类。
复制代码React & TS内置类型React.ReactNode源码类型中关于ReactNode的类型定义
type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;
复制代码可以看到ReactNode是一个类型别名,他是多种类型组成的联合类型。
其中ReactChild为type ReactChild = ReactElement | ReactText;
ReactPortal定义
interface ReactPortal extends ReactElement {
key: Key | null;
children: ReactNode;
}
复制代码所以
ReactNode是包含ReactElement类型的联合类型。换句话说ReactElement可以赋给ReactNode,但反过来不可以。

React.elementinterface ReactElement<P = any, T extends string | JSXElementConstructor<any> = string | JSXElementConstructor<any>> {
type: T;
props: P;
key: Key | null;
}
复制代码可以看到React.Element类型接受传入两个泛型分别是jsx编译后的vdom对象的props和组件本身。
返回的仅仅是包含type,props,key的一个Object对象。