typescript 可选属性-分享一些 TypeScript 最好的朋友方法

2023-08-26 0 7,904 百度已收录

TypeScript作为js的超集,可以帮助我们标准化代码,并对代码进行类型检查。 在日常开发中也经常用到。 以下摘录自以下好用的TypeScript好友方法,一起来学习一下

1—高级类型(AdvancedTypes)

使用 TypeScript 的中间类型(例如映射类型和条件类型),可以基于现有类型构建新类型。 通过使用这些类型,您可以修改和操作强类型系统中的类型,这反过来又使您的代码更加灵活和可维护。

映射类型

映射类型迭代现有类型的属性并应用转换来创建新类型。 一个常见的用例是创建类型的只读版本。

typescript复制代码type Readonly = {
  readonly [P in keyof T]: T[P];
};
interface Point {
  x: number;
  y: number;
}
type ReadonlyPoint = Readonly;

在此示例typescript 可选属性,我们定义了一个名为 Readonly 的映射类型,它将类型 T 作为子类参数,并将其所有属性设置为只读。 之后,我们创建了一个ReadonlyPoint类型,它基于Point套接字,其中所有属性都是只读的。

条件类型

条件类型允许您根据条件创建新类型。 句子类型与三元运算符类似,使用extends关键字作为类型约束。

typescript复制代码type NonNullable = T extends null | undefined ? never : T;

在此示例中,我们定义了一个名为 NonNullable 的条件类型,它采用类型 T 并检测它是否增强 null 或 undefined。 如果扩展,结果类型为 never,否则为原始类型 T。

让我们扩展中级类型的示例,放弃更多的可用性和输出。

typescript复制代码interface Point {
  x: number;
  y: number;
}
type ReadonlyPoint = Readonly;
const regularPoint: Point = {
  x: 5,
  y: 10
};
const readonlyPoint: ReadonlyPoint = {
  x: 20,
  y: 30
};
regularPoint.x = 15; // This works as 'x' is mutable in the 'Point' interface
console.log(regularPoint); // Output: { x: 15, y: 10 }
// readonlyPoint.x = 25; // Error: Cannot assign to 'x' because it is a read-only property
console.log(readonlyPoint); // Output: { x: 20, y: 30 }
function movePoint(p: Point, dx: number, dy: number): Point {
  return { x: p.x + dx, y: p.y + dy };
}
const movedRegularPoint = movePoint(regularPoint, 3, 4);
console.log(movedRegularPoint); // Output: { x: 18, y: 14 }
// const movedReadonlyPoint = movePoint(readonlyPoint, 3, 4); // Error: Argument of type 'ReadonlyPoint' is not assignable to parameter of type 'Point'

在此示例中,我们演示了只读映射类型的使用以及它们如何强制不变性。 我们创建一个可变的 Point 对象和一个只读的 ReadonlyPoint 对象。 我们表明尝试更改只读属性是一个编译时错误。 我们还明确指出,只读类型不能用在需要可变类型的地方,从而避免代码中出现意外的副作用。

2 - 装饰器(装饰器)

TypeScript 中的装饰器是一项强大的功能,允许您添加元数据以及更改或扩展类、方法、属性和参数的行为。 它们是高阶函数,可用于观察、修改或替换类定义、方法定义、访问器定义、属性定义或参数定义。

类装饰器

类装饰器应用于类的构造函数,可用于更改或扩展类定义。

typescript复制代码function LogClass(target: Function) {
  console.log(`Class ${target.name} was defined.`);
}
@LogClass
class MyClass {
  constructor() {}
}

在此示例中,我们定义了一个名为 LogClass 的类装饰器,它在定义时记录被装饰类的名称。 然后,我们使用 @sentence 模式将装饰器应用到 MyClass 类。

方法装饰器

方法装饰器应用于类的方法,可用于更改或扩充方法定义。

typescript复制代码function LogMethod(target: any, key: string, descriptor: PropertyDescriptor) {
  console.log(`Method ${key} was called.`);
}
class MyClass {
  @LogMethod
  myMethod() {
    console.log("Inside myMethod.");
  }
}
const instance = new MyClass();
instance.myMethod();

在这个例子中,我们定义了一个名为 LogMethod 的方法装饰器,它在调用方法时记录被装饰的方法的名称。 之后,我们使用 @sentence 模式将装饰器应用于 MyClass 类的 myMethod 技巧。

属性装饰器

属性装饰器应用于类的属性,可用于更改或扩充属性定义。

typescript复制代码function DefaultValue(value: any) {
  return (target: any, key: string) => {
    target[key] = value;
  };
}
class MyClass {
  @DefaultValue(42)
  myProperty: number;
}
const instance = new MyClass();
console.log(instance.myProperty); // Output: 42

在此示例中,我们定义了一个名为 DefaultValue 的属性装饰器,用于设置装饰属性的默认值。 然后,我们使用 @sentence 模式将装饰器应用到 MyClass 类的 myProperty 属性。

参数装饰器

参数装饰器应用于方法或构造函数的参数,可用于更改或扩展参数定义。

typescript复制代码function LogParameter(target: any, key: string, parameterIndex: number) {
  console.log(`方法 ${key} 的参数 ${parameterIndex} 被调用了。`);
}
class MyClass {
  myMethod(@LogParameter value: number) {
    console.log(`在 myMethod 方法内,使用值 ${value}。`);
  }
}
const instance = new MyClass();
instance.myMethod(5);

在这个例子中,我们定义了一个名为LogParameter的参数装饰器,它记录了调用方法时被装饰的参数的索引和名称。 然后,我们使用 @sentence 模式将装饰器应用于 MyClass 类的 myMethod 方法的 value 参数。

3—命名空间

typescript 可选属性-分享一些 TypeScript 最好的朋友方法

在 TypeScript 中,命名空间是一种组织和分组相关代码的形式。 它们通过封装属于一起的代码来帮助您防止命名冲突并促进模块化。 命名空间可以包含类、接口、函数、变量和其他命名空间。

定义命名空间

要定义名称空间,请使用名称空间关键字,后跟名称空间名称。 然后您可以在大括号内添加任何相关代码。

typescript复制代码namespace MyNamespace {
  export class MyClass {
    constructor(public value: number) {}
    displayValue() {
      console.log(`The value is: ${this.value}`);
    }
  }
}

在此示例中,我们定义一个名为 MyNamespace 的命名空间,并向其中添加一个类 MyClass。 请注意,我们使用export关键字使该类可以在命名空间之外访问。

使用命名空间

要在命名空间中使用代码,您可以使用完全限定名称或使用命名空间导出来导出代码。

typescript复制代码// 使用完全限定的名称
const instance1 = new MyNamespace.MyClass(5);
instance1.displayValue(); // 输出:The value is: 5
// 使用命名空间导入
import MyClass = MyNamespace.MyClass;
const instance2 = new MyClass(10);
instance2.displayValue(); // 输出:The value is: 10

在此示例中,我们演示了在 MyNamespace 命名空间中使用 MyClass 类的两种方法。 首先,我们使用完全限定名称 MyNamespace.MyClass。 其次,我们使用命名空间导出语句导出类 MyClass,并使用更短的名称。

嵌套命名空间

命名空间可以嵌套以创建层次结构并进一步组织代码。

typescript复制代码namespace OuterNamespace {
  export namespace InnerNamespace {
    export class MyClass {
      constructor(public value: number) {}
      displayValue() {
        console.log(`The value is: ${this.value}`);
      }
    }
  }
}
// 使用完全限定的名称
const instance = new OuterNamespace.InnerNamespace.MyClass(15);
instance.displayValue(); // 输出:The value is: 15

在此示例中,我们定义一个名为 InnerNamespace 的嵌套命名空间,在 OuterNamespace 中定义一个类 MyClass,并将其与完全限定名称 OuterNamespace.InnerNamespace.MyClass 一起使用。

4—混合

混合(Mixins)是 TypeScript 中组合类的方法,它由多个更小的部分组成,即混合类(mixinclasses)。 它们允许您在不同类之间重用和共享行为,从而促进模块化和代码可重用性。

定义混合

要定义 mixin,请创建一个类,该类使用构造函数签名来扩充类库类型参数。 这允许 mixin 与其他类组合。

typescript复制代码class TimestampMixin any>(Base: TBase) {
  constructor(...args: any[]) {
    super(...args);
  }
  getTimestamp() {
    return new Date();
  }
}

在此示例中typescript 可选属性,我们定义了一个名为 TimestampMixin 的 mixin,它添加了一个返回当前日期和时间的 getTimestamp 方法。 mixin 类通过带有构造函数签名的类库类型参数 TBase 进行了扩充,以允许它与其他类组合。

使用混合

要使用 mixin,请定义一个泛型类型并使用 extends 关键字将 mixin 应用于它。

typescript复制代码class MyBaseClass {
  constructor(public value: number) {}
  displayValue() {
    console.log(`The value is: ${this.value}`);
  }
}
class MyMixedClass extends TimestampMixin(MyBaseClass) {
  constructor(value: number) {
    super(value);
  }
}

在此示例中,我们定义了一个名为 MyBaseClass 的泛型,其中包含一个 displayValue 方法。 之后,我们创建一个名为 MyMixedClass 的新类,它扩展了泛型并将 TimestampMixin mixin 应用于它。

让我们演示一下 mixin 在实践中是如何工作的。

typescript复制代码const instance = new MyMixedClass(42);
instance.displayValue(); // 输出:The value is: 42
const timestamp = instance.getTimestamp();
console.log(`The timestamp is: ${timestamp}`); // 输出:The timestamp is: [当前日期和时间]

在此示例中,我们创建 MyMixedClass 类的实例,其中包括 MyBaseClass 的 displayValue 方法和 TimestampMixin 混合类的 getTimestamp 方法。 之后,我们调用这两个方法并显示它们的输出。

5—类型保护

TypeScript 中的类型保护是一种缩小特定代码块内变量或参数类型范围的方法。 它们允许您区分不同的类型并访问特定于这些类型的属性或方法,从而提高类型安全性并减少运行时错误的可能性。

定义类型保护

要定义类型保护,请创建一个接受变量或参数并返回基元类型的函数。 类型子句是一个布尔表达式,可缩小函数范围内参数的类型。

typescript复制代码function isString(value: any): value is string {
  return typeof value === "string";
}

在本例中,我们定义了一个类型保护函数 isString,它检查给定值是否是字符串类型。 该函数返回一个类型子句valueisstring,该子句缩小了函数范围内值参数的类型。

使用类型保护

要使用类型保护,只需在条件语句(例如 if 语句或 switch 语句)中调用类型保护函数即可。

typescript复制代码function processValue(value: string | number) {
  if (isString(value)) {
    console.log(`The length of the string is: ${value.length}`);
  } else {
    console.log(`The square of the number is: ${value * value}`);
  }
}

在此示例中,我们定义了一个名为 processValue 的函数,它接受 string|number 类型的值。 我们使用 isString 类型保护函数来检查该值是否是字符串。 如果它是字符串,我们访问特定于字符串类型的长度属性。 否则,我们假设该值是一个数字并估计其平方。

让我们演示一下类型防护在实践中是如何工作的。

typescript复制代码processValue("hello"); // 输出: The length of the string is: 5
processValue(42); // 输出: The square of the number is: 1764

在本例中,我们调用 processValue 函数并传入一个字符串和一个数字。 类型保护函数 isString 确保为每种类型执行适当的代码块,从而允许我们访问特定于类型的属性和技巧,而不会导致任何类型错误。

6-实用程序类型(UtilityTypes)

TypeScript 中的实用程序类型提供了一种将现有类型转换为新类型的便捷方法。 它们允许您创建更复杂和灵活的类型,而无需从头开始定义它们,从而提高代码可重用性和类型安全性。

使用实用程序类型

要使用实用类型,请使用尖括号语句将实用类型应用到现有类型。 TypeScript 提供了多种外部实用程序类型,例如 Partial、Readonly、Pick 和 Omit。

typescript复制代码interface Person {
  name: string;
  age: number;
  email: string;
}
type PartialPerson = Partial;
type ReadonlyPerson = Readonly;
type NameAndAge = Pick;
type WithoutEmail = Omit;

在本例中,我们定义了一个名为 Person 的套接字,它包含三个属性:name、age 和 email。 之后,我们使用各种外部实用程序类型基于 Person 套接字创建了新类型。

让我们演示一下这些实用程序类型的实际工作原理。

部分的

typescript复制代码const partialPerson: PartialPerson = {
  name: "John Doe",
};

在此示例中,我们创建一个 PartialPerson 类型的partialPerson 对象。 Partial 实用程序类型使 Person 套接字的所有属性都是可选的,允许我们仅使用 name 属性创建部分 person。

只读

typescript复制代码const readonlyPerson: ReadonlyPerson = {
  name: "Jane Doe",
  age: 30,
  email: "jane@example.com",
};
// readonlyPerson.age = 31; // 错误:无法分配到 'age',因为它是只读属性。

在此示例中,我们创建一个 ReadonlyPerson 类型的 readonlyPerson 对象。 Readonly 实用程序类型使 Person 套接字的所有属性都变为只读,从而阻止我们更改age 属性。

挑选

typescript复制代码const nameAndAge: NameAndAge = {
  name: "John Smith",
  age: 25,
};
// nameAndAge.email; // 错误:在类型 'Pick' 上不存在属性 'email'。

在此示例中,我们创建一个 NameAndAge 类型的 nameAndAge 对象。 Pick 实用程序类型创建一个新类型,其中仅包含 Person 套接字的指定属性,在本例中为名称和年龄。

忽略

typescript复制代码const withoutEmail: WithoutEmail = {
  name: "Jane Smith",
  age: 28,
};
// withoutEmail.email; // 错误:在类型 'Omit' 上不存在属性 'email'。

在此示例中,我们创建一个 WithoutEmail 类型的 withoutEmail 对象。 Omit 使用 Person 套接字创建一个新类型,并从中删除指定的属性,此处为 email 属性。 这提示我们使用 withoutEmail 对象来表示没有 email 属性的 Person 对象。

typescript复制代码const withoutEmail: WithoutEmail = {
  name: "Jane Smith",
  age: 28,
};
// withoutEmail.email; // Error: Property 'email' does not exist on type 'Omit'

在上面的示例中,我们创建了一个 WithoutEmail 类型的 withoutEmail 对象。 Omit 使用 Person 套接字创建一个新类型,并从中删除指定的属性,此处为 email 属性。 这提示我们使用 withoutEmail 对象来表示没有 email 属性的 Person 对象。

总结

事实上,本文涵盖了各种中级 TypeScript 主题,例如命名空间、高级类型、装饰器、mixin、类型防护和实用程序类型。 通过理解和利用这一特性,您可以创建更加模块化、可重用和可维护的代码,这些代码符合最佳实践并减少运行时错误的可能性。

通过利用这种中级 TypeScript 功能,您可以利用 TypeScript 强大的类型系统和语言功能编写更干净、更有组织且更易于维护的代码。

如果您喜欢这篇文章,觉得有帮助,可以点赞转发,让更多的人可以清楚的写出代码!

原来的:

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 typescript typescript 可选属性-分享一些 TypeScript 最好的朋友方法 https://www.wkzy.net/game/164136.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务