亲宝软件园·资讯

展开

TypeScript 高级数据类型实例详解

zkj 人气:0

TypeScript 介绍

函数

TypeScript 具有定义函数参数和返回值的特定语法。

function getTime(): number {
  return new Date().getTime();
}
let time = getTime(); // let time: number
console.log(time);

如果没有定义返回类型,TypeScript 将尝试通过返回的变量或表达式的类型来推断它。

function printHello(): void {
  console.log('Hello!');
}
function multiply(a: number, b: number) {
  return a * b;
}

如果没有定义参数类型,TypeScript 将默认使用 any,除非额外的类型信息可用,如默认参数和类型别名。

// 这里的 `?` 运算符将参数 `c` 标记为可选
function add(a: number, b: number, c?: number) {
  return a + b + (c || 0);
}
console.log(add(2,5));
function pow(value: number, exponent: number = 10) {
  return value ** exponent;
}

TypeScript 还可以从默认值推断类型。

function pow(value, exponent = 10) {
  return value ** exponent;
}
console.log(pow(10, '2')); // Argument of type 'string' is not assignable to parameter of type 'number'.
function divide({ dividend, divisor }: { dividend: number, divisor: number }) {
  return dividend / divisor;
}
console.log(divide({dividend: 10, divisor: 2}));
function add(a: number, b: number, ...rest: number[]) {
  return a + b + rest.reduce((p, c) => p + c, 0);
}
console.log(add(10,10,10,10,10));
type Negate = (value: number) => number;
// 参数 value 自动从 Negate 类型被分配 number 类型
const negateFunction: Negate = (value) => value * -1;
console.log(negateFunction(10));
function makeDate(timestamp: number): Date;
function makeDate(m: number, d: number, y: number): Date;
function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {
  if (d !== undefined && y !== undefined) {
    return new Date(y, mOrTimestamp, d);
  } else {
    return new Date(mOrTimestamp);
  }
}
const d1 = makeDate(12345678);
const d2 = makeDate(5, 5, 5);
const d3 = makeDate(1, 3); // No overload expects 2 arguments, but overloads do exist that expect either 1 or 3 arguments.

在本例中,我们编写了两个重载:一个接受一个参数,另一个接受三个参数。前两个签名称为重载签名,但它们都不能用两个参数调用。

在下面这个示例中,我们可以用字符串或数组调用它。但是,我们不能使用可能是字符串或数组的值调用它,因为 TypeScript 只能将函数调用解析为单个重载:

function len(s: string): number;
function len(arr: any[]): number;
function len(x: any[] | string) {
  return x.length;
}
len(""); // OK
len([0]); // OK
len(Math.random() > 0.5 ? "hello" : [0]); // No overload matches this call.

因为两个重载都有相同的参数计数和相同的返回类型,所以我们可以编写一个非重载版本的函数:

function len(x: any[] | string) {
  return x.length;
}

现在我们可以使用任意一种值调用它,所以如果可能,首选具有联合类型的参数,而不是重载。

枚举

枚举是一个特殊的“类”,表示一组常量(不可更改的变量)。使用枚举类型可以为一组数值赋予更加友好的名字。枚举有两种数据类型:stringnumer

enum CardinalDirections {
  North,
  East,
  South,
  West
};
let currentDirection: CardinalDirections = CardinalDirections.North;
console.log(currentDirection); // '0' 因为 North 是第一个值
// currentDirection = 'North'; // Error: "North" is not assignable to type 'CardinalDirections'.
enum CardinalDirections {
  North = 1,
  East,
  South,
  West
}
console.log(CardinalDirections.North); // logs 1
console.log(CardinalDirections.West); // logs 4
enum StatusCodes {
  NotFound = 404,
  Success = 200,
  Accepted = 202,
  BadRequest = 400
};
console.log(StatusCodes.NotFound); // logs 404
console.log(StatusCodes.Success); // logs 200
enum CardinalDirections {
  North = 'North',
  East = "East",
  South = "South",
  West = "West"
};
console.log(CardinalDirections.North); // logs "North"
console.log(CardinalDirections.West); // logs "West"

可以混合字符串和数字枚举值,但不建议这样做。

enum StatusCodes {
  NotFound = 404,
  Success = 200,
  Accepted = 202,
  BadRequest = 400
};
let s1 = StatusCodes[200]; // string | undefined
console.log(s1); // Success
const value = 0;
enum List {
  A = value,
  B = 2,  // 必须初始化
  C,
}

联合类型

联合类型(Union Types)可以通过 | 运算符将变量设置多种类型,赋值时可以根据设置的类型来赋值。当一个值可以是多个单一类型时,可以使用联合类型。例如当变量是 string 或 number 时。

function printStatusCode(code: string | number) {
  console.log(`My status code is $[code].`)
}
printStatusCode(404);
printStatusCode('404');

注意:使用联合类型时,需要知道你的类型是什么,以避免类型错误:

function printStatusCode(code: string | number) {
  console.log(`My status code is ${code.toUpperCase()}.`); // error: Property 'toUpperCase' does not exist on type 'string | number'. Property 'toUpperCase' does not exist on type 'number'
}

在上述示例中,因为 toUpperCase() 是一个字符串方法,而数字无法访问它。

类型别名和接口

TypeScript 允许类型与使用它们的变量分开定义。类型别名和接口允许在不同的变量之间轻松共享类型。

类型别名

type Point = {
  x: number;
  y: number;
};
function printCoord(pt: Point) {
  console.log("The coordinate's x value is " + pt.x);
  console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 100, y: 100 });
type ID = number | string;
type Direction = 'center' | 'left' | 'right';
let d: Direction = ''; // Type '""' is not assignable to type 'Direction'.
type BooleanString = `${boolean}`;
const bool: BooleanString = '1'; // Type '"1"' is not assignable to type '"false" | "true"'.
type SerialNumber= `${number}.${number}`;
const id: SerialNumber= '1.2';

接口

接口类似于类型别名,但是只适用于对象类型。

interface Point {
  x: number;
  y: number;
}
function printCoord(pt: Point) {
  console.log("The coordinate's x value is " + pt.x);
  console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 100, y: 100 });
type Window = {
  title: string
}
// Error: Duplicate identifier 'Window'.
type Window = {
  ts: TypeScriptAPI
}
interface Window {
  title: string
}
interface Window {
  ts: TypeScriptAPI
}
interface Show {
  isShow: boolean;
}
type Graphic = {
  name: string;
}
class Point {
  x: number;
  y: number;
}
interface Point3d extends Point, Graphic, Show {
  z: number;
}
const point3d: Point3d = { x: 1, y: 2, z: 3, name: '1', isShow: true };
interface i1 {
  [index: number]: string
}
let list: i1 = ["0", "1", "2"];
// list2 = ["0", 1, "2"] // Type 'number' is not assignable to type 'string'.
interface i2 {
  [index: string]: number
}
const list2: i2 = {};
list2["0"] = 0;
list2[1] = "1"; // Type 'string' is not assignable to type 'number'.

交叉类型

接口允许我们通过扩展其他类型来构建新类型。TypeScript 还提供了另一种称为交叉类型的结构,使用 & 运算符定义,主要用于组合现有的对象类型。

interface Colorful {
  color: string;
}
interface Circle {
  radius: number;
}
function draw(circle: Colorful & Circle) {
  console.log(`Color was ${circle.color}`);
  console.log(`Radius was ${circle.radius}`);
}
draw({ color: "blue", radius: 42 });
// 'raidus' does not exist in type 'Colorful & Circle'. Did you mean to write 'radius'?
draw({ color: "red", raidus: 42 });

在这里,我们将 ColorfulCircle 相交以生成一个包含 ColorfulCircle 的所有成员的新类型。

interface A {
  name: string;
  age: number;
}
interface B {
  name: string;
  height: string;
}
type Person = A & B;  // 相当于求并集
const person: Person = { name: 'Tom', age: 18, height: '60kg' };
interface Animal {
  name: string
}
type Person = Animal & {
  age: number;
}
type Animal = {
  name: string
}
type Bear = Animal & { 
  honey: boolean 
}
type Useless = string & number; // type Useless: never
Useless = 1; // 'Useless' only refers to a type, but is being used as a value here.

TypeScript 向 JavaScript 类添加了类型和可见性修饰符。

class Person {
  name: string;
}
const person = new Person();
person.name = "Jane";
class Person {
  private name: string;
  constructor(name: string) {
    this.name = name;
  }
  getName(): string {
    return this.name;
  }
}
const person = new Person("Jane");
console.log(person.getName()); // person.name isn't accessible from outside the class since it's private
class Person {
  constructor(private name: string) {}
  getName(): string {
    return this.name;
  }
}
const person = new Person("Jane");
console.log(person.getName()); // Jane
class Person {
  readonly name: string = 'Jane';
  constructor(name?: string) {
    if(name) this.name = name;
  }
}
const person = new Person("a");
// person.name = ''; // Cannot assign to 'name' because it is a read-only property.
interface Shape {
  getArea: () => number;
}
class Rectangle implements Shape {
  constructor(protected readonly width: number, protected readonly height: number) {}
  getArea(): number {
    return this.width * this.height;
  }
}
class Square extends Rectangle {
  constructor(width: number) {
    super(width, width);
  }
}
class Rectangle {
  constructor(protected readonly width: number, protected readonly height: number) {}
  toString(): string {
    return `Rectangle[width=${this.width}, height=${this.height}]`;
  }
}
class Square extends Rectangle {
  constructor(width: number) {
    super(width, width);
  }
  override toString(): string {
    return `Square[width=${this.width}]`;
  }
}
abstract class Polygon {
  abstract getArea(): number;
  toString(): string {
    return `Polygon[area=${this.getArea()}]`;
  }
}
class Rectangle extends Polygon {
  constructor(protected readonly width: number, protected readonly height: number) {
    super();
  }
  getArea(): number {
    return this.width * this.height;
  }
}
class Employee {
  login: boolean;
  private _fullName: string;
  get fullName(): string {
    return this._fullName;
  }
  set fullName(newName: string) {
    console.log(this.login);
    if (this.login === true) {
      this._fullName = newName;
    } else {
      console.log("Error: Unauthorized update of employee!");
    }
  }
}
const employee = new Employee();
employee.login = true;
employee.fullName = "Bob Smith";
if (employee.fullName) {
  console.log(employee.fullName);
}
class StaticMem {
  static num: number;
  static disp(): void {
    console.log("num 值为 " + StaticMem.num);
  }
}
StaticMem.num = 12;
StaticMem.disp();

加载全部内容

相关教程
猜你喜欢
用户评论