一: 索引签名
索引签名用于定义对象类型,允许对象具有任意数量的属性,但属性名的类型必须是字符串(在大多数情况下)或数字(在某些特定的上下文中,如数组或类似数组的对象)。索引签名的值类型可以是任何 TypeScript 类型。
interface StringDictionary {
[index: string]: string | undefined;
}
let myDict: StringDictionary;
myDict["greeting"] = "hello";
console.log(myDict["greeting"]); // 输出 "hello"
二:类型索引访问
类型索引访问允许你在类型级别上访问一个对象的索引类型。在泛型编程中,这特别有用,因为你可以根据传入的类型来动态地获取该类型的索引签名类型。
1. T[number] 是一个索引访问类型(index access type),它用于从泛型类型 T 中提取数组或类数组(如元组)类型中元素的类型。
如果 T 是一个数组或元组类型,那么 T[number] 会返回该数组或元组中所有元素的共同类型(如果存在的话),或者是一个联合类型,包含了数组中所有可能的元素类型。
const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const
type TupleToObject<T extends readonly any[]> = {
[P in T[number]] : P
}
type result = TupleToObject<typeof tuple> // expected { 'tesla': 'tesla', 'model 3': 'model 3', 'model X': 'model X', 'model Y': 'model Y'}
2. T[0] 也是一个索引访问类型,但它特指泛型类型 T 的第一个元素的类型。
如果 T 是一个数组或元组类型,并且具有至少一个元素,那么 T[0] 将返回该数组或元组第一个元素的类型。
type NumberArray = number[];
type FirstElementTypeOfNumberArray = NumberArray[0]; // FirstElementTypeOfNumberArray 类型为 number
type Tuple = [string, number, boolean];
type FirstElementTypeOfTuple = Tuple[0]; // FirstElementTypeOfTuple 类型为 string
- T[]标识泛型数组
type NodeA = {
type: "A"
name: string
flag: number
}
type NodeB = {
type: "B"
id: number
flag: number
}
type NodeC = {
type: "C"
name: string
flag: number
}
type Nodes = NodeA | NodeB | NodeC
type ReplacedNodes = ReplaceKeys<Nodes>
// type ReplaceKeys<T>
// = T[] extends [NodeA , NodeB , NodeC] ? true : false // false
type ReplaceKeys<T>
= T[] extends (NodeA|NodeB|NodeC)[] ? true : false // true
索引访问操作符
索引访问操作符用于访问对象的属性或数组的元素,以及在类型级别上访问类型的索引签名。
--- 数组
let arr: number[] = [1, 2, 3];
type ElementType = typeof arr[number]; // ElementType 是 number
let tuple: [string, number] = ['hello', 42];
type FirstElementType = typeof tuple[0]; // FirstElementType 是 string
type SecondElementType = typeof tuple[1]; // SecondElementType 是 number
--对象
interface Person {
name: string;
age: number;
[propName: string]: any; // 索引签名
}
type PropValueType = Person[string]; // PropValueType 是 any,因为索引签名的值类型是 any
--泛型
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key]; // 这里使用了索引访问操作符来访问 obj 的属性
}
let person = { name: 'Alice', age: 30 };
let name = getProperty(person, 'name'); // name 的类型是 string,值是 'Alice'
在泛型中的应用
示例一:获取对象属性的类型
const person = {
name: 'Alice',
age: 30,
isStudent: false
};
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key]
}
const name2 = getProperty(person, 'name');
示例二: 映射对象类型(每个属性的值都被转换为字符串)
type Person = {
name: string;
age: number;
isStudent: boolean;
};
type Stringify<T> = {
[P in keyof T]: string
}
type PersonStringified = Stringify<Person>; // { name: string; age: string; isStudent: string; }
示例三: 处理数组和元组的元素
type MapArray<T, U> = {
[P in keyof T]: U;
} & { length: number }; // 这里我们简化了数组类型,仅用于演示
type NumberArray = number[];
type MappedArray = MapArray<NumberArray, string>; // 假设是 string[],但这里简化为 { [index: number]: string; length: number; }
// 对于元组,我们可以更精确地处理每个元素的类型
type TupleToUnion<T extends readonly any[]> = T[number];
type Tuple = [string, number, boolean];
type TupleUnion = TupleToUnion<Tuple>; // string | number | boolean
示例四:在条件类型中使用索引访问操作符 (比如我们可以创建一个类型,它根据对象是否具有某个属性来返回不同的类型。)
type HasProperty <T, K> = K extends keyof T ? T[K] : never
interface Person {
name: string;
age: number;
}
type NameOrNever = HasProperty<Person, 'name'>; // string
type RandomProperty = HasProperty<Person, 'random'>; // never