这篇文章讲解类型
。莫要让 TypeScript
成为 AnyScript
,学习类型也是从简单
到复杂
。typescript
T
表示 type 类型P
表示 props 属性K/V
key/valueU
经常使用的类型变量复杂类型中经常使用的关键字和操做符json
keyof
至关于 Object.keysin
至关于 for-in?
可选操做符-?
可选取反extends
interface/class
表示继承type
中表示约束[]
定义函数的输入和输出api
为了更好的使用 TypeScript, 须要开启严格的 TypeScript 代码检查:markdown
noImplicitAny
没有隐式的 any 类型推断
strictNullChecks
严格的 null 检查
{
"compilerOptions": {
"noImplicitAny": true,
"strictNullChecks": true,
}
}
复制代码
严格的 null 检查 最佳实践1 , 在处理空指针的状况下,很是实用。app
type User = {
name: string;
age?: number; // 可选的属性,不存在时,不能使用其上面的属性和方法
}
const getUser = (user: User) => {
console.log(user.name, user.age.toString()) // user.age 🐛 可能不存在可是调用方法
}
复制代码
age 是可选的,可是在 console.log 中调用了 toString 方法。dom
?.
来解决这个🐛,严格检查console.log(user.name, user.age?.toString())
复制代码
any[]
类型type
引出接口 interface
在 TypeScript 中,使用 type 关键字,定义类型别名函数
type User = number | string; // 定义 number | string 的联合类型为 User
复制代码
⚠️:别名 type 一旦定义定义就不能扩展本身
,只能用 type
定一个其余的类型。基于别名 type 自生不可扩展,引出 接口 interface 的概念就很合适了。oop
interface Global {
api1: number
}
复制代码
咱们想要扩展 Global 接口,就能够直接从新定义(从新定义不是简单的覆盖行为)学习
interface Global {
api2: number
}
复制代码
api2接口属性是补充在 Global 属性上面的,而不是覆盖以前定义的 api1。ui
对象类型应该是咱们最经常使用的复合类型在之一了。
他们的最主要的区别之一就是:能不能不产生新的类型
的基础上扩展本身。
?.<your option>
readonly <you option>
有时候,咱们不肯定属性的名称,此时咱们就能够定义索引类型
interface User {
[index: string]: any
}
复制代码
index
表示索引,索引的类型是 string,属性对应的类型是 any
不产生
一个新的接口产生
一个新的接口|
联合类型,进行扩展,产生
一个新的类型。两个类型交叉,将两个不一样类型组合成一个新的类型没有重复
的新的类型
type A = {
name: string
age: number
}
type B = {
age: number
sex: string
}
const C: A & B = {
name: 'sdfd',
age: 123,
sex: 'male'
}
const D: A | B = {
name: 'sdf',
age: 123
}
复制代码
重要
的条件类型extends
约束类型extends关键字,在类型约束
中起到重要做用。
SomeType extends OtherType ? TrueType : FalseType;
复制代码
extends
关键字,本质是遍历,每个属性对比是子集,返回 TrueType
, 不然返回 FalseType
。 extends 表示条件? :
, 分配类型泛条件类型
。本质很简单,就是将是三目运算符,放在了类型的判断中:(一个前提:条件是继承关系)
T extends U ? X : Y
复制代码
也就是说 子类型 T
是否是继承自父类型 U
,若是是
,取 X 类型,若是不是
取 Y 类型。
既然是条件,那有 true/false 就很正常
type User = {
name: string;
age: number
}
declare function <T extends boolean>f(x: T): T extends true ? User : null;
// T 类型继承 true 类型时,函数 f 的返回值是 User, 不然是 null
const a = f(Math.random() < 0.1); // User | number
const b = f( 1 < 2) // User
const c = f( 1 > 2) // null
复制代码
关于范型,这里不讨论。
type Exclude<T, U> = T extends U ? never : T;
复制代码
type Ex<T, U> = T extends U ? never : T
type Parent = {
name: string;
age: number;
}
type User = {
name: string;
age: number;
sex: string;
}
// A 是 User 类型, 下面的 sex 的存在
const A: Ex<User, Parent> = {
name: 'xiaoming',
age: 234,
sex: 'sdf' // Type '{ name: string; age: number; pa: number; ad: number; sex: string; }' is not assignable to type 'User'.
}
复制代码
A
是 Ex<User, Parent> 类型,Parent
类型,不是 extends
User
,因此得 A
就是 User
类型.
type IId = { id: number }
type IName = { name: string }
type NameOrId<T extends string | number> = T extends number ? IId : IIName
复制代码
从上面看了 Exclude 的源码,是 子集 + never
, 由此,咱们也能扩展其余的类型:
子集 + null
子集 + undefined
子集 + any
(好像没有必要)type CNull<T, U> = T extends U ? null : T;
type CUndefined<T, U> = T extends U ? undefined : T;
type CAnd<T, U> = T extends U ? and : T;
复制代码