返回

独家秘籍:快速掌握TypeScript高级特性,助你面试得心应手!

前端

巧用 TypeScript 高级特性,玩转数据类型

TypeScript 是一门强大的语言,它的高级特性为开发者提供了广泛的工具,用于构建健壮且可维护的代码。这些特性可以帮助你处理复杂的数据结构,增强类型安全性,并简化代码重用。

Partial:可选属性的艺术

Partial 类型允许你将一个类型的属性全部变为可选属性。这在很多场景下非常有用,例如,你想创建一个函数来更新一个对象的某些属性,但你不想强制要求所有属性都必须传递。

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

const updateUser = (user: Partial<User>, updates: Partial<User>) => {
  return { ...user, ...updates };
};

const updatedUser = updateUser({ name: 'John' }, { age: 30 });

Pick:选择性属性

Pick 类型允许你从一个类型中选择一个或多个属性,并创建一个新的类型,只包含这些属性。这在很多场景下非常有用,例如,你想创建一个函数来获取一个对象的某些属性,但你不想返回整个对象。

interface User {
  name: string;
  age: number;
  email: string;
}

const getUserInfo = (user: User): Pick<User, 'name' | 'email'> => {
  return { name: user.name, email: user.email };
};

const userInfo = getUserInfo({ name: 'John', age: 30, email: 'john@example.com' });

Readonly:只读属性的保护

Readonly 类型允许你将一个类型的属性全部变为只读属性。这在很多场景下非常有用,例如,你想创建一个函数来创建一个只读的对象,或者你想防止一个对象的属性被意外更改。

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

const createUser = (name: string, age: number): Readonly<User> => {
  return { name, age };
};

const user = createUser('John', 30);
user.name = 'Jane'; // Error: Cannot assign to a read-only property

Required:必填属性的严格

Required 类型允许你将一个类型的属性全部变为必填属性。这在很多场景下非常有用,例如,你想创建一个函数来创建一个新的对象,并确保所有属性都有值。

interface User {
  name?: string;
  age?: number;
}

const createUser = (name: string, age: number): Required<User> => {
  return { name, age };
};

const user = createUser('John', 30);
console.log(user.name); // John
console.log(user.age); // 30

keyof:属性名集合的奥秘

keyof 操作符允许你获取一个类型的属性名的集合。这在很多场景下非常有用,例如,你想创建一个函数来获取一个对象的属性值,但你不想硬编码属性名。

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

const getUserProperty = <T>(obj: T, property: keyof T) => {
  return obj[property];
};

const userName = getUserProperty({ name: 'John', age: 30 }, 'name');
console.log(userName); // John

in:属性名查找的捷径

in 操作符允许你检查一个属性名是否在一个类型中存在。这在很多场景下非常有用,例如,你想创建一个函数来检查一个对象是否具有某个属性。

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

const hasProperty = <T>(obj: T, property: string): property is keyof T => {
  return property in obj;
};

const user = { name: 'John', age: 30 };
const hasNameProperty = hasProperty(user, 'name');
console.log(hasNameProperty); // true

infer:类型推断的魔法

infer 允许你推断一个类型的类型。这在很多场景下非常有用,例如,你想创建一个函数来获取一个函数的返回值类型,但你不想硬编码返回值类型。

type GetReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

const add = (a: number, b: number): number => {
  return a + b;
};

const addReturnType = GetReturnType<typeof add>;
console.log(addReturnType); // number

手撕笔试题:展示你的 TypeScript 真功夫

题目:

给定一个对象类型User,其中包含nameageemail属性。请编写一个函数pickUserProperties,该函数接受一个User对象和一个字符串数组properties作为参数,并返回一个只包含properties数组中指定属性的新对象。

例如:

const user = {
  name: 'John',
  age: 30,
  email: 'john@example.com'
};

const pickedUser = pickUserProperties(user, ['name', 'email']);

console.log(pickedUser); // { name: 'John', email: 'john@example.com' }

解答:

function pickUserProperties<T, K extends keyof T>(obj: T, properties: K[]): Pick<T, K> {
  const pickedObject: Pick<T, K> = {} as Pick<T, K>;
  properties.forEach((property) => {
    if (property in obj) {
      pickedObject[property] = obj[property];
    }
  });
  return pickedObject;
}

常见问题解答

1. 为什么使用高级类型特性?

高级类型特性可以增强代码的类型安全性,提高代码的可维护性,并简化代码重用。它们允许你创建更灵活和健壮的数据结构,从而提高代码质量。

2. Partial 和 Readonly 有什么区别?

Partial 将所有属性变为可选属性,而 Readonly 将所有属性变为只读属性。Partial 允许你更新对象的部分属性,而 Readonly 则创建了不可变的对象。

3. Pick 和 Required 有什么区别?

Pick 从一个类型中选择特定属性,而 Required 将所有属性变为必填属性。Pick 允许你创建包含特定属性的新对象,而 Required 确保对象具有所有必需的属性。

4. keyof 和 in 有什么区别?

keyof 返回一个类型的属性名的集合,而 in 检查一个属性名是否在一个类型中存在。keyof 用于获取属性名的列表,而 in 用于检查是否存在特定属性。

5. infer 的作用是什么?

infer 允许你推断一个类型的类型。这在需要动态确定类型的情况下非常有用,例如,当你想获取一个函数的返回值类型时。

结语

TypeScript 的高级特性是一把双刃剑。它们可以极大地提高代码质量,但也可能增加代码的复杂性。在使用这些特性时,重要的是要权衡利弊,并选择最适合你的特定需求的特性。

掌握 TypeScript 的高级特性将使你成为一名更强大的开发者。通过练习和探索,你可以解锁这些特性的全部潜力,并编写出更健壮、更可维护的代码。