10个超级实用的typescript使用技巧

概览:在实际的开发工作过程中,积累了一些常见又超级好用的 typescript 技巧和代码片段,包括整理的其他大神的ts使用技巧,今天筛选了 10+ 个,以供大家参考。

使用交叉类型来合并多个类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
type User = {
name: string;
};

type Admin = {
role: string;
};

type UserAndAdmin = User & Admin;

const user: UserAndAdmin = {
name: "John",
role: "admin"
};

使用联合类型来允许多个类型

1
2
3
4
5
6
7
type Status = "success" | "error" | "loading";

function showMessage(status: Status, message: string) {
// ...
}

showMessage("success", "Operation completed successfully");

使用类型守卫来判断变量的类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type User = {
name: string;
};

type Admin = {
name: string;
role: string;
};

function greet(user: User | Admin) {
if ("role" in user) {
console.log(`Hello, ${user.name}, you are an admin`);
} else {
console.log(`Hello, ${user.name}`);
}
}

使用optional chaining操作符(?.)和nullish coalescing操作符(??)来简化代码

1
2
3
4
5
6
7
8
const user = {
name: "John",
address: {
city: null
}
};

const cityName = user?.address?.city ?? "unknown";

使用装饰器来扩展类和方法的行为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;

descriptor.value = function(...args: any[]) {
console.log(`Calling method ${propertyKey} with arguments: ${JSON.stringify(args)}`);
return originalMethod.apply(this, args);
};

return descriptor;
}

class User {
constructor(public name: string, public age: number) {}

@log
greet() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old`);
}
}

const user = new User("John", 30);
user.greet();

使用 Record 来定义键值对类型

1
2
3
4
5
6
7
type AgeMap = Record<string, number>;

const ages: AgeMap = {
John: 30,
Mary: 25,
Mike: 35,
};

使用模板字符串和 keyof 来生成属性名称

1
2
3
4
5
6
7
8
9
10
11
12
13
interface Person {
name: string;
age: number;
}

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}

const person: Person = { name: "John", age: 30 };
const propertyName = "name";
console.log(getProperty(person, propertyName as keyof Person));
console.log(getProperty(person, "age"));

在上面的代码中,我们使用模板字符串和 keyof 操作符来生成属性名称,并将其作为参数传递给函数 getProperty。

使用类型保护来检查变量的类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
interface Dog {
name: string;
breed: string;
}

interface Cat {
name: string;
age: number;
}

function isDog(pet: Dog | Cat): pet is Dog {
return (pet as Dog).breed !== undefined;
}

const dog: Dog = { name: "Max", breed: "Labrador" };
const cat: Cat = { name: "Whiskers", age: 3 };

console.log(isDog(dog)); // true
console.log(isDog(cat)); // false

在上面的代码中,我们使用 isDog 函数来检查变量 pet 是否是 Dog 类型。

使用 Exclude 和 Extract 来过滤类型

1
2
3
type T1 = string | number | boolean;
type T2 = Exclude<T1, boolean>;
type T3 = Extract<T1, string>;

在上面的代码中,我们使用 Exclude 和 Extract 类型来过滤 T1 类型。T2 类型将移除 boolean 类型,而 T3 类型将只保留 string 类型。

使用 Partial 和 Required 来转换类型

1
2
3
4
5
6
7
interface Person {
name: string;
age: number;
}

type PartialPerson = Partial<Person>;
type RequiredPerson = Required<PartialPerson>;

在上面的代码中,我们使用 Partial 和 Required 类型来转换类型。PartialPerson 类型将转换为可选的属性,而 RequiredPerson 类型将转换为必填的属性。

使用 Pick 和 Omit 来选择和排除属性

1
2
3
4
5
6
7
8
interface Person {
name: string;
age: number;
address: string;
}

type PersonNameAge = Pick<Person, "name" | "age">;
type PersonWithoutAddress = Omit<Person, "address">;

在上面的代码中,我们使用 Pick 和 Omit 类型来选择和排除属性。PersonNameAge 类型将只保留 name 和 age 属性,而 PersonWithoutAddress 类型将排除 address 属性。

使用 as const 来创建只读数组和对象

1
2
const arr = ["foo", "bar"] as const;
const obj = { name: "John", age: 30 } as const;

在上面的代码中,我们使用 as const 来创建只读数组和对象。arr 和 obj 将不可修改。

使用 Readonly 来使对象的所有属性变为只读

1
2
3
4
5
6
7
8
9
10
interface Person {
name: string;
age: number;
address: string;
}

type ReadonlyPerson = Readonly<Person>;

const person: ReadonlyPerson = { name: "John", age: 30, address: "123 Main St." };
person.age = 31; // Error: Cannot assign to 'age' because it is a read-only property.

在上面的代码中,我们使用 Readonly 来使对象的所有属性变为只读。ReadonlyPerson 类型将具有与 Person 相同的属性,但所有属性都是只读的。

使用 Required 来使对象的所有属性变为必需的

1
2
3
4
5
6
7
8
9
interface Person {
name?: string;
age?: number;
address?: string;
}

type RequiredPerson = Required<Person>;

const person: RequiredPerson = { name: "John", age: 30, address: "123 Main St." };

在上面的代码中,我们使用 Required 来使对象的所有属性变为必需的。RequiredPerson 类型将具有与 Person 相同的属性,但所有属性都是必需的。

使用 NonNullable 来移除对象的所有可空属性

1
2
3
4
5
6
7
8
9
interface Person {
name?: string;
age?: number | null;
address?: string | null;
}

type NonNullablePerson = NonNullable<Person>;

const person: NonNullablePerson = { name: "John", age: 30, address: "123 Main St." };