Open su37josephxia opened 2 years ago
function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] {
return names.map((n) => o[n]);
}
let person = {
name: 'tom',
age: 11,
};
type Persion = typeof person;
let strings: (string | number)[] = pluck(person, ['name', 'age']);
上例中的keyof T为索引类型操作符,对于任何类型 T,keyof T的结果为T上已知的公共属性名的联合。 T[K]为索引访问操作符,在这里,类型语法反映了表达式语法,这意味着 person['name']具有类型 Person['name'] 编译器会检查 name,age是否真的是 Person的属性。
interface Example<T> {
[x: string]: T;
}
let keys: keyof Example<number>;
let values: Example<number>[KeyType];
使用索引类型,编译器就能够检查使用了动态属性名的代码
let person = {
name: 'musion',
age: 35
}
function getValues(person: any, keys: string[]) {
return keys.map(key => person[key])
}
console.log(getValues(person, ['name', age])) // ['musion', 35]
console.log(getValues(person, ['gender'])) // [undefined]
在上述例子中,可以看到getValues(persion, ['gender'])打印出来的是[undefined],但是ts编译器并没有给出报错信息,那么如何使用ts对这种模式进行类型约束呢?这里就要用到了索引类型,改造一下getValues函数,通过 索引类型查询和 索引访问 操作符:
function getValues<T, K extends keyof T>(person: T, keys: K[]): T[K][] {
return keys.map(key => person[key]);
}
interface Person {
name: string;
age: number;
}
const person: Person = {
name: 'musion',
age: 35
}
getValues(person, ['name']) // ['musion']
getValues(person, ['gender']) // 报错:
// Argument of Type '"gender"[]' is not assignable to parameter of type '("name" | "age")[]'.
// Type "gender" is not assignable to type "name" | "age".
编译器会检查传入的值是否是Person的一部分。
几个类型操作符:
keyof T ---索引类型查询操作符。 表示类型T的所有公共属性的字面量的联合类型
T[K] --- 索引访问操作符。表示对象T的属性K所代表的类型
T extends U --- 表示泛型变量可以通过继承某个类型,获得某些属性
索引类型让静态检查能够覆盖到类型不确定(无法穷举)的”动态“场景
function pluck(o, names) {
return names.map(n => o[n]);
}
索引类型查询操作符(index type query operator)
keyof T
取类型T
上的所有public
属性名构成联合类型, keyof
是针对类型的,而不是值
索引访问操作符(indexed access operator)
相当于类型层面的属性访问操作符
编译器能够通过索引类型检查使用了动态属性名的代码。
function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] {
return names.map(n => o[n]);
}
interface Person {
name: string;
age: number;
}
let person: Person = {
name: 'Jarid',
age: 35
};
let strings: string[] = pluck(person, ['name']); // ok, string[]
编译器会检查 name是否真的是 Person的一个属性。
类型操作符:
索引类型就是对象的 key,数组的 index 的类型。可以使用 keyof,typeof,in 关键字更灵活的定义类型。索引类型一般用于描述使用的对象和他的属性。
设置索引类型最简单的方法就是直接指定类型。
interface foo<T> {
[key: string]: T
}
interface bar<T> {
[index: number]: T
}
但是我们无法约束具体的 key 和 不同的值类型,所以我们可以借助 keyof 和 in
type bar = 'a' | 'b' | 'c'
type foo = {
[K in bar]: number
}
let a: foo = {
a: '1', // error
b: 2,
c: 4,
d: 4 // error
}
type foo<T> = {
[K in keyof T]: T[K] // 可以原封不动的表示 T 的结构
}
// 可以简单配合 typeof 使用
foo<typeof bar>
// 借助了泛型,通过 T 约束第二个参数的类型为其索引,
// 如果没有提供第一个参数的类型会根据第一个参数的 key 的联合类型。
function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] {
return names.map((n) => o[n])
}
TS中什么是索引类型?
索引类型可以约束对象属性的查询和访问 配合泛型约束能够建立对象,对象属性,属性值之间的约束关系
function getValues<T, K extends keyof T>(obj: T, keys: K[]): T[K][] {
return keys.map(key => obj[key])
}
目的:从obj对象中抽取的属性数组keys中的元素,一定得是obj对象中的属性
实现思路:
K extends keyof T
T[K][]