您现在的位置是:网站首页> 编程资料编程资料

深入了解TypeScript中常用类型的使用_javascript技巧_

2023-05-24 960人已围观

简介 深入了解TypeScript中常用类型的使用_javascript技巧_

原始类型:string,number,boolean

javaScript​ 有三个经常会使用到的原始类型:stirng,number,boolean​。每一个在Typescript​都有一个相对应的类型。 正如你所期望的,你可以得到相同的名称在javascript​中使用typeof​去操作这些类型对应的值:

  • string代表的值,例如"Hello,world"。
  • number​代表的值,例如42。
  • boolean​代表的两个值,true和false。

数组(Arrays)

若要指定类似[1,2,3]的数组类型,你可以使用number[]​语法,这个语法可以声明任何类型的数组(e.g. string[])。或许你也看到过Array​的这种相同含义写法。

请注意[number]是元组(Tuples);请移步到Tuple

Any类型

TypeScript也有一个特殊的类型----any​。任何时候,你不想因为类型问题而造成类型检查报错的时候,你都可以去使用它。当你在一个值上使用​any​的时候,你可以在这个值上访问任何属性​(访问的属性也是any​类型),像function一样调用它,把任意类型的值都赋值给它。只要在合法的语法内,可以做相当多的事情:

let obj: any = { x: 0 }; // None of the following lines of code will throw compiler errors. // Using `any` disables all further type checking, and it is assumed // you know the environment better than TypeScript. obj.foo(); obj(); obj.bar = 100; obj = "hello"; const n: number = obj;

当你不想只是用写一长串类型去使TypeScript​相信一行代码时,any类型非常有用。

noImplicitAny

当你不指定一个类型,并且TypeScript​无法从上下文推断除类型的话,编译器​一般会默认推断为any​。通常情况下,如果你需要避免​这种情况的话,因为any​不会类型检查​,这就需要使用编译器​上的配置noImplicitAny​去标识任何隐藏的any​类型为错误(让编译器报错)。

在变量上使用类型注释

当你使用const,var,let去声明变量的时候,你可以选择直接指定类型:

let myName: string = "Alice";

TypeScript​不使用"左侧类型(types on the left)"的风格,就像int x = 0;类型注释往往放在被注释的对象后面。

然而通常情况下,这并不是必要的。尽可能的情况下,TypeScirpt会在你的代码上尝试自动推断类型。举个例子,变量的类型会被基于它的初始化类型进行推断:

// No type annotation needed -- 'myName' inferred as type 'string' let myName = "Alice";

在大多数情况下,你不需要刻意的去学习推断规则,尝试使用更少的类型注释。

函数(Functions)

Functions​是JavaScript传递数据的主要工具。TypeScript​允许你指定function的输入输出类型。

参数类型注释(Parameter Type Annotations)

当你定义了一个function​ ,你可以在function​的每个参数后面添加类型注释,参数的类型定义在参数名称后面:

// Parameter type annotation function greet(name: string) { console.log("Hello, " + name.toUpperCase() + "!!"); }

当参数添加了类型注释​,调用function传递参数时,将会被检查:

// Would be a runtime error if executed! greet(42);

甚至你没有在你的参数后面进行类型声明,TypeScript仍然会检查你传递的参数数量是否正确。

返回类型注释(Return Type Annotations)

你也可以添加返回类型注释​ 。返回类型注释出现在参数列表之后:

function getFavoriteNumber(): number { return 26; }

很类似变量类型注释​,你通常不需要显式的添加一个返回类型注释​,因为TypeScript​会基于function的return​语句,自动推导function​的返回类型。这个类型注解上述的类型注解的例子并没有改变任何东西。有一些代码库会为了文档的目的显式的返回一个类型,去防止意外的更改,或者只是个人的喜好。

之后,我们将看到更多关于上下文影响其类型的例子。

匿名函数(Anonymous Functions)

匿名函数有略微不同于函数声明,当一个函数出现在TypeScript可以明确的知道它怎么被调用的地方,那么它的参数会自动推到类型。

举个例子:

// No type annotations here, but TypeScript can spot the bug const names = ["Alice", "Bob", "Eve"]; // Contextual typing for function names.forEach(function (s) { console.log(s.toUppercase()); // 被string[]类型的数组调用,自动推导为string类型 // Property 'toUppercase' does not exist on type 'string'. Did you mean 'toUpperCase'? }); // Contextual typing also applies to arrow functions names.forEach((s) => { console.log(s.toUppercase()); // 被string[]类型的数组调用,自动推导为string类型 // Property 'toUppercase' does not exist on type 'string'. Did you mean 'toUpperCase'? });

上述例子中,甚至参数s​都没有类型注释,TypeScript​使用了forEach​函数的类型,和数组的推导类型​一起明确了参数s的类型。

这种处理方式被称为上下文类型,因为函数的上下文通知参数s应该有什么类型。

类似于推到规则,你不需要特别学习它是怎么发生的。但是需要明白这种情况下,它会发生,这样可以帮助你确认什么时候不需要类型注解

对象类型(Object Types)

作为原始类型的一部分,你最经常遇到的类型是对象类型(Object Type),JavaScript中有属性的值几乎都对应了它!我们可以简单的去列出对象的属性和属性的类型去定义对象类型(Object Type)

举个例子,函数携带了一个坐标对象作为参数:

// The parameter's type annotation is an object type function printCoord(pt: { x: number; y: number }) { console.log("The coordinate's x value is " + pt.x); console.log("The coordinate's y value is " + pt.y); } printCoord({ x: 3, y: 7 });

上面的例子中,我们声明了拥有两个number​类型的属性的参数,属性是x和y​。你可以使用,​或者;(推荐)​去分割属性。并且最后一个分隔符是可选的。

每个属性的类型部分也是可选的​。如果你不显式​指定一个类型,它就会被假定为any。

可选属性(Options Properties)

对象类型也可以指定他们的某些属性是可选的(optional)​,使用`可选时`,需要在属性名称后面加?符号:

function printName(obj: { first: string; last?: string }) { // ... } // Both OK printName({ first: "Bob" }); printName({ first: "Alice", last: "Alisson" });

在javaScript​中,如果你访问一个不存在的属性,它会返回一个undefined​而不是抛出错误​。如此,当你访问可选属性​之前,你必须检查它是否是undefined:

function printName(obj: { first: string; last?: string }) { // Error - might crash if 'obj.last' wasn't provided! console.log(obj.last.toUpperCase()); //Object is possibly 'undefined'. if (obj.last !== undefined) { // OK console.log(obj.last.toUpperCase()); } // A safe alternative using modern JavaScript syntax: console.log(obj.last?.toUpperCase()); }

联合类型(Union Types)

TypeScript的类型系统允许你使用各种各样的运算符从现有类型去创建一个新类型。现在让我们来写一些新类型。是时候开始用一种有趣的方式去组合他们。

定义一个联合类型(Define a Union Type)

第一种组合方式是联合类型。一个联合类型由多个类型组织而成,代表值是这些类型中任意的一个。我们引用每个类型作为联合类型的成员。

让我们写一个可以操作string​或者number类型的函数:

function printId(id: number | string) { console.log("Your ID is: " + id); } // OK printId(101); // OK printId("202"); // Error printId({ myID: 22342 }); // Argument of type '{ myID: number; }' is not assignable to parameter of type 'string | number'.

使用联合类型(Working with Union Types)

去匹配联合类型的值是非常容易的----就是简单的提供联合类型中的一个。如果你有一个联合类型,你将如何使用它。

TypeScript​只允许使用对联合类型的每个成员都有效的操作。举个例子,如果你有一个string | number​的联合类型,那你不能使用只有string类型才有的方法:

function printId(id: number | string) { console.log(id.toUpperCase()); // Property 'toUpperCase' does not exist on type 'string | number'. // Property 'toUpperCase' does not exist on type 'number'. }

解决上述情况的方式是通过代码来收缩联合类型(narrow the union with code )​,和你在javaScript​中不使用类型注释一样。当TypeScript可以根据代码结构推断更具体的类型时,就会发生收缩。

举个例子,TypeScript​知道只有string​的值typeof​的值才是"string":

function printId(id: number | string) { if (typeof id === "string") { // In this branch, id is of type 'string' console.log(id.toUpperCase()); } else { // Here, id is of type 'number' console.log(id); } }

另一个例子是使用函数例如Array.isArray:

function welcomePeople(x: string[] | string) { if (Array.isArray(x)) { // Here: 'x' is 'string[]' console.log("Hello, " + x.join(" and ")); } else { // Here: 'x' is 'string' console.log("Welcome lone traveler " + x); } }

请注意在else分支​中,我们不需要做任何事情,如果x​不是string[]​类型,那它在else​中必定是string类型。

又是你会遇到一个成员拥有公共方法的联合类型。举个例子。数组和字符串这两个都勇敢又slice方法。如果联合类型中的每个成员都有相同的方法,那你可以在不使用收缩(narrowing)的情况下使用这个使用这个属性:

// Return type is inferred as number[] | string function getFirstThree(x: number[] | string) { return x.slice(0, 3); }

联合属性拥有交集(intersection)是有点迷惑的。这不是偶然-这个名称`unio` 来自类型导论。联合类型number | string是由每个类型的并集组成。请注意,给定了两个集合,每个集合都有相应的实现。只有这些交集的实现才适用于集合本身的并集。例如,如果我们有一个房间里的高个子戴着帽子,另一个房间里的讲西班牙语的人戴着帽子,把这两个房间结合起来,我们对每个人的唯一了解就是他们一定戴着帽子。

类型别名(Type Aliases)

我们一般是使用对象类型(object types)和联合类型都是直接他们写成类型注解。这非常方便。但是常见的情况是,不止一次地使用同一个类型,并通过一个名称引用它。

一个类型别名准确的来说,就是一个名称代表了任何类型。类型别名的语法是:

type Point = { x: number; y: number; }; // Exactly the same as the earlier example 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 | strin
                
                

-六神源码网