TypeScript
泛型
通用约束
typescript
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // Now we know it has a .length property, so no more error
return arg;
}在泛型约束中使用类型参数
您可以声明一个受另一个类型参数约束的类型参数。例如,在这里我们想从给定名称的对象中获取属性。我们想确保不会意外获取不存在的属性 obj,因此我们将在两种类型之间设置约束:
typescript
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");
getProperty(x, "m"); // Error: Argument of type '"m"' is not assignable to parameter of type '"a" | "b" | "c" | "d"'.在泛型中使用类类型
typescript
class Person {
name: string = "John";
age: number = 30;
sayHello() {
console.log(
`Hello, my name is ${this.name} and I am ${this.age} years old.`
);
}
}
/**
* 形参也可以是这种方式: cls: { new (): T }
*/
function create<T>(cls: new () => T): T {
return new cls();
}
const person = create(Person);
person.sayHello(); // Output: "Hello, my name is John and I am 30 years old."通用参数默认值
typescript
class Animal {
name: string;
}
class Dog extends Animal {
constructor() {
super();
this.name = "Dog";
}
}
class Cat extends Animal {
constructor() {
super();
this.name = "Cat";
}
}
function createAnimal<A extends Animal = Dog>(c: new () => A): A {
return new c();
}
console.log(createAnimal(Dog).name); // output: Dog
console.log(createAnimal(Cat).name); // output: Cat
console.log(createAnimal(Animal).name); // output: Dog类型运算符
keyof
typescript
type Point = { x: number; y: number };
type P = keyof Point; // "x" | "y"
type Arrayish = { [index: number]: unknown };
type A = keyof Arrayish; // number
type Mapish = { [key: string]: boolean };
type M = keyof Mapish; // string | number提示
请注意,在此示例中,M 是 string | number。这是因为 JavaScript 对象键总是被强制转换为字符串,因此 obj[0] 总是与 obj["0"]相同。
typeof
typescript
function fn() {
return { x: 10, y: "2" };
}
type P = ReturnType<typeof fn>; // { x: number; y: string }索引访问类型
可以使用索引访问类型来查找另一种类型的特定属性:
typescript
type Person = { age: number; name: string; alive: boolean };
type Age = Person["age"]; // number索引类型本身是一种类型,因此我们可以使用联合 keyof 或其他类型:
typescript
type I1 = Person["age" | "name"]; // string | number
type I2 = Person[keyof Person]; // string | number | boolean
type AliveOrName = "alive" | "name";
type I3 = Person[AliveOrName]; // string | boolean使用任意类型进行索引的另一个示例是使用 number 来获取数组元素的类型。我们可以将其与 typeof 方便地捕获数组文字的元素类型相结合:
typescript
const MyArray = [
{ name: "Alice", age: 15 },
{ name: "Bob", age: 23 },
{ name: "Eve", age: 38 },
];
type Person = (typeof MyArray)[number]; // { name: string; age: number }
type Age = (typeof MyArray)[number]["age"]; // number
// Or
type Age2 = Person["age"]; // number索引时只能使用类型,这意味着您不能使用 const 来创建变量引用:
typescript
const key = "age";
type Age = Person[key]; // Type 'key' cannot be used as an index type. 'key' refers to a value, but is being used as a type here. Did you mean 'typeof key'?但是,您可以使用类型别名进行类似风格的重构:
typescript
type key = "age";
type Age = Person[key]; // number映射类型
映射类型是一种通用类型,它使用 PropertyKeys 的联合(通常通过 keyof 创建)来遍历键来创建类型:
typescript
type OptionsFlags<T> = {
[prop in keyof T]: boolean;
};在这个例子中,OptionsFlags 将从类型中获取所有属性 T 并将其值更改为布尔值。
typescript
type Features = {
darkMode: () => void;
newUserProfile: () => void;
};
type FeatureOptions = OptionsFlags<Features>; // { darkMode: boolean; newUserProfile: boolean; }映射修饰符
映射期间可以应用两个附加修饰符:readonly 和 ?,它们分别影响可变性和可选性。
您可以通过在前缀中添加 - 或 + 来删除或添加这些修饰符。如果您不添加前缀,则假定使用 +。
typescript
// Removes 'readonly' attributes from a type's properties
type CreateMutable<T> = {
-readonly [prop in keyof T]: T[prop];
};
type LockedAccount = {
readonly id: string;
readonly name: string;
};
type UnlockedAccount = CreateMutable<LockedAccount>; // { id: string; name: string; }typescript
// Removes 'optional' attributes from a type's properties
type Concrete<T> = {
[prop in keyof T]-?: T[prop];
};
type MaybeUser = {
id: string;
name?: string;
age?: number;
};
type User = Concrete<MaybeUser>; // { id: string; name: string; age: number }as
在 TypeScript 4.1 及更高版本中,您可以使用映射类型中的子句as重新映射类型中的键:
typescript
type MappedTypeWithNewProperties<Type> = {
[Properties in keyof Type as NewKeyType]: Type[Properties];
};从以前的属性名称创建新的属性名称:
typescript
type Getters<T> = {
[prop in keyof T as `get${Capitalize<string & prop>}`]: () => T[prop];
};
interface Person {
name: string;
age: number;
location: string;
}
type LazyPerson = Getters<Person>; // { getLocation: () => string, getName: () => string, getAge: () => number }通过条件类型生成来过滤掉键:
typescript
// Remove the 'kind' property
type RemoveKindField<T> = {
[prop in keyof T as Exclude<prop, "kind">]: T[prop];
};
interface Circle {
kind: "circle";
radius: number;
}
type KindlessCircle = RemoveKindField<Circle>; // { radius: number }