亲宝软件园·资讯

展开

TypeScript 基本数据类型实例详解

zkj 人气:0

TypeScript 介绍

类型分配

创建变量时,TypeScript 有两种分配类型的方式:

let firstName = "Dylan"; // 推断为 string 类型
firstName = 33; // 现在赋值为 number 类型,报错

TypeScript 不能正确地推断出变量的类型时,将设置类型为 any(禁用类型检查的类型)。

// json 为隐式 any 类型,因为 JSON.parse 不知道它返回什么类型的数据
let json = JSON.parse("55");
console.log(typeof json); // number
json = '1';
console.log(typeof json); // string

类型推导

let x = 3;

变量的类型 x 将被推断为 number,这种推断发生在初始化变量和成员、设置参数默认值和确定函数返回类型时。

let x = [0, 1, ''];

要推断上例中 x 的类型,我们必须考虑每个数组元素的类型。在这里,我们为数组类型提供了两种选择:numberstring,可以看到提示推导为 let x: (number | string)[]

class Animal {}
class Rhino extends Animal {
  hasHorn: true;
}
class Elephant extends Animal {
  hasTrunk: true;
}
class Snake extends Animal {
  hasLegs: false;
}
let zoo = [new Rhino(), new Elephant(), new Snake()];

当没有找到“最佳通用类型”时,得到的推断将是联合数组类型,可以看到提示推导为 let zoo: (Rhino | Elephant | Snake)[]

理想情况下,我们可能希望 zoo 被推断为 Animal[],但是因为数组中没有严格意义上的 Animal 类型的对象,所以我们没有对数组元素类型进行推断。为了纠正这一点,当没有一个类型是所有其他候选类型的超级类型时,就明确地提供类型。

let zoo: Animal[] = [new Rhino(), new Elephant(), new Snake()];
window.onmousedown = function (mouseEvent) {
  console.log(mouseEvent.button);
  console.log(mouseEvent.kangaroo);
};

在这里,TypeScript 类型检查器通过 Window.onmousedown 事件能够推断出 mouseEvent 参数的类型,该参数确实包含 button 属性,但不包含 kangaroo 属性。可以看到报错提示:Property 'kangaroo' does not exist on type 'MouseEvent'.。TypeScript 足够聪明,它也可以在其他上下文中推断类型:

window.onscroll = function (uiEvent) {
  console.log(uiEvent.button);
};

TypeScript 知道 Window.onscroll 事件中参数 uiEvent 是一个 UIEvent,而不是像前面示例那样的 MouseEventUIEvent 对象不包含 button 属性,因此会抛出错误 Property 'button' does not exist on type 'Event'.

如果此函数不在上下文类型位置,则函数的参数将隐式具有类型 any,并且不会发出错误(除非使用 noImplicitAny 配置):

// @noImplicitAny: false
const handler = function (uiEvent) {
  console.log(uiEvent.button); // <- OK
};

我们还可以显式地为函数的参数提供类型信息以覆盖任何上下文类型:

window.onscroll = function (uiEvent: any) {
  console.log(uiEvent.button); // 不报错,打印undefined,因为UIEvent对象不包含button属性
};

上下文类型化适用于许多情况。常见情况包括函数调用的参数、赋值的右侧、类型断言、对象和数组文字的成员以及返回语句。上下文类型也会充当“最佳通用类型”中的候选类型。例如:

function createZoo(): Animal[] {
  return [new Rhino(), new Elephant(), new Snake()];
}

在此示例中,“最佳通用类型”将从以下四个类型中选择:AnimalRhinoElephantSnake。最终,通过“最佳通用类型”算法为 Animal

数组

TypeScript 具有定义数组的特定语法。

const arr: number[] = [1, 2];
const arr2: Array<number> = [1, 2];
const arr: readonly number[] = [1, 2];
// arr.push(3); // Property 'push' does not exist on type 'readonly number[]'.
const numbers = [1, 2, 3]; // 推断为类型 number[]
numbers.push(4); // OK
// numbers.push("2"); // Argument of type 'string' is not assignable to parameter of type 'number'

元组

数组中元素的数据类型都一般是相同的(any[] 类型的数组可以不同),如果存储的元素数据类型不同,则需要使用元组。

let x: [string, number];
x = ['hi', 1];
// x.push(true); // Argument of type 'boolean' is not assignable to parameter of type 'string | number'.
// x = [1, 'hi']; // Type 'number' is not assignable to type 'string'. Type 'string' is not assignable to type 'number'.
let y: readonly [string, number] = ['hi', 1];
// y.push(undefined); // Property 'push' does not exist on type 'readonly [string, number]'.
const graph: [x: number, y: number] = [55.2, 41.3];
const [a, b] = graph;

object

const car: { type: string, model: string, year: number } = {
  type: "Toyota",
  model: "Corolla",
  year: 2009
};

对象类型可以单独写,也可以作为类型别名和接口重用。

const car = {
  type: "Toyota",
};
car.type = "Ford";
// car.type = 2; // Type 'number' is not assignable to type 'string'.
const car: { type: string, mileage?: number } = { // no error  
  type: "Toyota"  
};  
car.mileage = 2000;
const nameAgeMap: { [index: string]: number } = {};
nameAgeMap.Jack = 25; // no error
nameAgeMap.Mark = "Fifty"; // Error: Type 'string' is not assignable to type 'number'.

上述索引签名也可以通过使用工具类型 Record<string, number> 实现。

const sites = {
  site1: "Runoob",
  site2: "Google",
};
sites.sayHello = function() {
  console.log("hello " + sites.site1);
};
sites.sayHello();

上面示例在对象上面没有对应的 sayHello 类型定义,将不能进行属性赋值,会出现编译错误,:Property 'sayHello' does not exist on type '{ site1: string; site2: string; }'.,所以必须在对象上面定义类型模板。

const sites = {
  site1: "Runoob",
  site2: "Google",
  sayHello: function() {}
};

null 和 undefined

默认情况下 nullundefined 处理是禁用的,可以通过在 tsconfig.json 中设置 strictNullCheckstrue 来启用。

let y: undefined = undefined;
console.log(typeof y);
let z: null = null;
console.log(typeof z);
interface House {
  sqft: number;
  yard?: {
    sqft: number;
  };
}
function printYardSize(house: House) {
  const yardSize = house.yard?.sqft;
  if (yardSize === undefined) {
    console.log('No yard');
  } else {
    console.log(`Yard is ${yardSize} sqft`);
  }
}
let home: House = {
  sqft: 500
};
printYardSize(home); // 'No yard'
function printMileage(mileage: number | null | undefined) {
  console.log(`Mileage: ${mileage ?? 'Not Available'}`);
}
printMileage(null); // 'Mileage: Not Available'
printMileage(0); // 'Mileage: 0'
function liveDangerously(x?: number | null) {
  // No error
  console.log(x!.toFixed());
}

就像其他类型断言一样,这不会改变代码的运行时行为,所以只有当您知道该值不能为 nullundefined 时使用 !

let array: number[] = [1, 2, 3];
let value = array[0]; // `number | undefined` "noUncheckedIndexedAccess": true

特殊类型

TypeScript 具有可能不引用任何特定类型数据的特殊类型。

any

any 是一种禁用类型检查并有效地允许使用所有类型的类型。any 类型是一种消除错误的有用方法,因为它禁用了类型检查,但 TypeScript 将无法提供类型安全,并且依赖类型数据的工具(例如自动完成)将无法工作。所以,我们应尽量避免使用它。

以下三种情况可以使用 any 类型。

let x: any = 1; // 数字类型
x = 'I am who I am'; // 字符串类型
x = false; // 布尔类型
let v: any = true;
v = "string"; // 没有错误
v.ifItExists(); // ifItExists 方法在运行时可能不存在而报错,但这里并不会检查
console.log(Math.round(v)); // 没有错误
const arrayList: any[] = [1, false, 'fine'];
arrayList[1] = 100;

unknown

unknown 类型表示任何值,类似于 any 类型,但更安全,因为用未知值做任何事情都是不合法的。由于 any 违背了类型检查的初衷,一般不建议使用,尤其在有了 unknown 类型之后。

let a: any;
let n: number;
let w: unknown = 1; 
w = "string";
w = a;
a = w;
n = a;
// n = w; // Type 'unknown' is not assignable to type 'number'
function f(): unknown {} // A function whose declared type is neither 'void' nor 'any' must return a value
const w = {
  runANonExistentMethod: () => {
    console.log("I think therefore I am");
  }
} as { runANonExistentMethod: () => void };
if(typeof w === 'object' && w !== null) {
  (w as { runANonExistentMethod: Function }).runANonExistentMethod(); 
}

never

never 代表从不会出现的值,在函数中它通常表现为抛出异常或无法执行到终止点(例如无限循环)。never 很少单独使用,它的主要用途是在高级泛型中。

function error(message: string): never {
  throw new Error(message);
}
function loop(): never {
  while (true) {}
}

void

表示函数没有任何返回语句,或者不从这些返回语句返回任何显式值。在 JavaScript 中,不返回任何值的函数将隐式返回值 undefined。但是,void 和返回 undefined 在 TypeScript 中不是一回事。

function hello(): void {
  console.log("Hello");
  return true; // Type 'boolean' is not assignable to type 'void'.
}
hello();

函数类型 type vf = () => void 在实现时可以返回任何其他值,以下类型的实现是有效的:

type voidFunc = () => void;
const f1: voidFunc = () => {
  return true;
};
const f2: voidFunc = () => true;
const f3: voidFunc = function() {
  return true;
};
const v1 = f1();
const v2 = f2();
const v3 = f3();
console.log(v1, v2, v3); // true true true

加载全部内容

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