学过java后学TS一天就感觉学会了,一看就会 一做就废。B站上的绝大部分TS还不如去看看文档 一点类型编程的进阶知识都没有。建议有编程基础的直接看文档。
看的b站视频感觉ts很简单,看了掘金小册的ts发现b站的视频只能学个定义。学到类型编程就发现晦涩难懂。第一眼会了,再仔细看看又不会了。那先从最简单的索引类型开始。
索引类型
索引类型:索引签名类型 、索引类型查询 与索引类型访问。
索引签名类型
索引签名类型
主要指的是在接口或类型别名中,通过以下语法来快速声明一个键值类型一致的类型结构:
typescript
interface MyObject {
[key: string]: number;
}
const obj: MyObject = {
a: 1,
b: 2,
c: 3,
};
//[]是索引类型访问 具体详情下面小节有
console.log(obj['a']); // 输出: 1
console.log(obj['b']); // 输出: 2
定义了一个名为MyObject
的接口,它具有一个索引签名类型,允许使用字符串作为索引,并且对应的值类型为数字。然后,我们创建了一个obj
对象,可以通过字符串索引来访问其属性。
不同的属性名,定义不同的类型
typescript
// 错误的尝试: TypeScript不允许这样做
interface MixedTypeDictionary {
[key: string]: string;
[key: number]: number; // Error: An index signature parameter type cannot be a union type
}
需要不同的属性具有不同的类型,你应该明确地在接口或类型别名中声明它们:
javascript
interface StringOrBooleanTypes {
propA: number;
propB: boolean;
[key: string]: number | boolean;
}
索引类型查询
将对象中的所有键转换为对应字面量类型,然后再组合成联合类型
typescript
interface Foo {
gsy: 1,
599: 2
}
type FooKeys = keyof Foo; // "gsy" | 599
索引类型访问
通过 obj[expression]
的方式来访问属性
typescript
interface Foo {
propA: number;
propB: boolean;
}
type PropAType = Foo['propA']; // number
type PropBType = Foo['propB']; // boolean
配合keyof
typescipt
interface Foo {
propA: number;
propB: boolean;
propC: string;
}
type PropTypeUnion = Foo[keyof Foo]; // string | number | boolean
在未声明索引签名类型的情况下,我们不能使用 NumberRecord[string]
这种原始类型的访问方式,而只能通过键名的字面量类型来进行访问。
ts
interface Foo {
propA: number;
}
// 类型"Foo"没有匹配的类型"string"的索引签名。
type PropAType = Foo[string];
★映射类型 ★
前置知识学完了,就到三合一了。
映射类型的主要作用即是基于键名映射到键值类型。放段小册的伪代码。
javascript
type Stringify<T> = {
[K in keyof T]: string;
};
//伪代码
const StringifiedFoo = {};
for (const k of Object.keys(Foo)){
StringifiedFoo[k] = string;
}
xdm看了上面的代码 有点基础肯定学会了,我也学会了 但过会又忘了。还得再细点,来点正确的废话
我的废话
ts
type Clone<T> = {
[K in keyof T]: T[K];
};
这里的T[K]
其实就是上面说到的索引类型访问,我们使用键的字面量类型访问到了键值的类型,这里就相当于克隆了一个接口。需要注意的是,这里其实只有K in
属于映射类型的语法,keyof T
属于 keyof 操作符,[K in keyof T]
的[]
属于索引签名类型,T[K]
属于索引类型访问。
T
是一个将被克隆的类型变量。[K in keyof T]
是一个索引类型查询和映射类型的结合。对于类型T
中的每个属性键K
,都会创建一个相同键的属性。T[K]
表示键K
在原始类型T
中对应的属性类型。
ts
type User = {
id: number;
name: string;
email: string;
};
type UserClone = Clone<User>;
定义了一个名为 User
的类型,它有三个属性:id
、name
、和 email
。当我们使用映射类型 [K in keyof T]
时,这里的 T
是指我们定义的 User
类型,keyof T
是 User
的所有属性键的联合类型,K
是这些键中的每一个。 对于 User
类型,keyof User
将得到所有属性名的联合类型
ts
keyof User = "id" | "name" | "email";
每个 K
将相继地是这个联合类型的成员,即先是 "id"
,然后 "name"
,最后 "email"
。
对于 T[K]
,它表示类型 T
中键 K
对应的值的类型。在我们的例子中,User[K]
的可能值为以下类型:
- 对于
K
为"id"
,User[K]
的类型是number
。 - 对于
K
为"name"
,User[K]
的类型是string
。 - 对于
K
为"email"
,User[K]
的类型是string
。
在 Clone<User>
的上下文中,[K in keyof User]: User[K];
将分别为每个属性创建一个同名的属性,并且保持对应的类型,如下所示:
id: number
,因为User["id"]
是number
类型。name: string
,因为User["name"]
是string
类型。email: string
,因为User["email"]
是string
类型。 因此,映射类型[K in keyof T]: T[K];
实际上遍历了User
类型的每个属性,保留了每个属性的键和类型,并在新的Clone<User>
类型中复制了这个结构。