为了使程序有用,我们需要能够处理一些最简单的数据单位:数字、字符串、结构、布尔值等。在TypeScript中,我们支持的类型与你在JavaScript中期望的类型相同,还有一个额外的枚举类型来帮助我们。
布尔
最基本的数据类型是简单的真/假值,JavaScript和TypeScript称之为布尔值。
let isDone: boolean = false;
数字
在JavaScript中,TypeScript中的所有数字要么是浮点值,要么是BigIntegers。这些浮点数得到类型为number,而BigIntegers得到类型为bigint。除了十六进制和十进制字元,TypeScript还支持ECMAScript 2015中引入的二进制和八进制字元。
let decimal: number = 6;let hex: number = 0xf00d;let binary: number = 0b1010;let octal: number = 0o744;let big: bigint = 100n;
字符串
在JavaScript中为网页和服务器创建程序的另一个基本部分是处理文本数据。在其他语言中,我们使用字符串类型来引用这些文本数据类型。就像JavaScript一样,TypeScript也使用双引号(“)或单引号(‘)来包围字符串数据。
let color: string = "blue";color = 'red';
您还可以使用模板字符串,它可以跨越多行,并具有嵌入式表达式。这些字符串由反引号/反引号 (`) 字符包围,嵌入式表达式的形式为 ${ expr }。
let fullName: string = `Bob Bobbington`;let age: number = 37;let sentence: string = `Hello, my name is ${fullName}.I'll be ${age + 1} years old next month.`;
这就相当于这样声明句。
let sentence: string ="Hello, my name is " +fullName +".\n\n" +"I'll be " +(age + 1) +" years old next month.";
数组
TypeScript,像JavaScript一样,允许你使用数组的值。数组类型可以用两种方式之一来写。在第一种情况下,你使用元素的类型,然后用[]表示该元素类型的数组。
let list: number[] = [1, 2, 3];
第二种方式使用通用数组类型Array
let list: Array<number> = [1, 2, 3];
元组
元组类型允许你表达一个具有固定数量元素的数组,这些元素的类型是已知的,但不需要是相同的。例如,您可能希望将一个值表示为一对字符串和一个数字。
// Declare a tuple typelet x: [string, number];// Initialize itx = ["hello", 10]; // OK// Initialize it incorrectlyx = [10, "hello"]; // Error// Type 'number' is not assignable to type 'string'.// Type 'string' is not assignable to type 'number'.
当访问一个具有已知索引的元素时,会检索到正确的类型。
// OKconsole.log(x[0].substring(1));console.log(x[1].substring(1));// Property 'substring' does not exist on type 'number'.
访问已知索引集之外的元素会出错。
x[3] = "world";// Tuple type '[string, number]' of length '2' has no element at index '3'.console.log(x[5].toString());// Object is possibly 'undefined'.// Tuple type '[string, number]' of length '2' has no element at index '5'.
枚举
在JavaScript的标准数据类型集中,一个有用的补充就是枚举。就像在C#语言中一样,枚举是一种为数值集赋予更友好名称的方式。
enum Color {Red,Green,Blue,}let c: Color = Color.Green;
默认情况下,枚举从0开始编号,你可以通过手动设置其中一个成员的值来改变这一情况。例如,我们可以将前面的例子从1开始,而不是从0开始。
enum Color {Red = 1,Green,Blue,}let c: Color = Color.Green;
或者,甚至可以手动设置枚举中的所有值。
enum Color {Red = 1,Green = 2,Blue = 4,}let c: Color = Color.Green;
枚举的一个方便的特性是,你也可以从一个数值到枚举中该值的名称。例如,如果我们的值是2,但不确定它在上面的Color枚举中映射到什么,我们可以查找相应的名称。
enum Color {Red = 1,Green,Blue,}let colorName: string = Color[2];// Displays 'Green'console.log(colorName);
未知
我们可能需要描述我们在编写应用程序时不知道的变量类型。这些值可能来自动态内容—例如来自用户—或者我们可能希望有意接受我们的API中的所有值。在这些情况下,我们希望提供一个类型,告诉编译器和未来的读者,这个变量可能是任何东西,所以我们给它未知类型。
let notSure: unknown = 4;notSure = "maybe a string instead";// OK, definitely a booleannotSure = false;
如果你有一个未知类型的变量,你可以通过做typeof检查、比较检查或者更高级的类型防护来缩小它的范围,这些将在后面的章节中讨论。
declare const maybe: unknown;// 'maybe' could be a string, object, boolean, undefined, or other typesconst aNumber: number = maybe;// Type 'unknown' is not assignable to type 'number'.if (maybe === true) {// TypeScript knows that maybe is a boolean nowconst aBoolean: boolean = maybe;// So, it cannot be a stringconst aString: string = maybe;// Type 'boolean' is not assignable to type 'string'.}if (typeof maybe === "string") {// TypeScript knows that maybe is a stringconst aString: string = maybe;// So, it cannot be a booleanconst aBoolean: boolean = maybe;// Type 'string' is not assignable to type 'boolean'.}
任意
在某些情况下,并不是所有的类型信息都是可用的,或者它的声明会花费不适当的精力。这些情况可能发生在没有TypeScript或第三方库编写的代码中。在这些情况下,我们可能希望选择不进行类型检查。为了做到这一点,我们将这些值标记为任意类型。
declare function getValue(key: string): any;// OK, return value of 'getValue' is not checkedconst str: string = getValue("myString");
Any类型是一种强大的方式来使用现有的JavaScript,允许你在编译过程中逐渐选择加入或退出类型检查。
与未知类型不同,any类型的变量允许你访问任意属性,甚至是那些不存在的属性。这些属性包括函数,TypeScript不会检查它们的存在或类型。
let looselyTyped: any = 4;// OK, ifItExists might exist at runtimelooselyTyped.ifItExists();// OK, toFixed exists (but the compiler doesn't check)looselyTyped.toFixed();let strictlyTyped: unknown = 4;strictlyTyped.toFixed();Object is of type 'unknown'.
任何将继续通过你的对象传播。
let looselyTyped: any = {};let d = looselyTyped.a.b.c.d;// ^ = let d: any
毕竟,请记住,任何的便利都是以失去类型安全为代价的。类型安全是使用TypeScript的主要动机之一,在没有必要的时候,你应该尽量避免使用任何。
空
void有点像any的反义词:没有任何类型。你可能通常会把它看作是不返回值的函数的返回类型。
function warnUser(): void {console.log("This is my warning message");}
声明void类型的变量是没有用的,因为你只能将null(只有在没有指定—strictNullChecks的情况下,见下一节)或undefined分配给它们。
let unusable: void = undefined;// OK if `--strictNullChecks` is not givenunusable = null;
Null and Undefined
在TypeScript中,undefined和null实际上都有自己的类型,分别命名为undefined和null。就像void一样,它们本身并不是非常有用。
// Not much else we can assign to these variables!let u: undefined = undefined;let n: null = null;
默认情况下,null和undefined是所有其他类型的子类型。这意味着你可以将null和undefined赋值给像number这样的类型。
然而,当使用—strictNullChecks标志时,null和undefined只能分配给unknown、any和它们各自的类型(一个例外是undefined也可以分配给void)。这有助于避免许多常见的错误。在你想传入字符串或null或undefined的情况下,你可以使用联合类型string | null | undefined。
联合类型是一个高级话题,我们将在后面的章节中介绍。
需要注意的是:我们鼓励在可能的情况下使用 —strictNullChecks,但在本手册中,我们将假定它是关闭的。
never
never类型表示永远不会出现的值的类型。例如,never是一个函数表达式的返回类型,或者一个总是抛出异常的箭头函数表达式,或者一个永不返回的函数表达式。变量在被任何类型守卫缩小时,也会获得never类型,即永远不能为真。
never类型是每一个类型的子类型,并且可以分配给每一个类型;但是,没有任何类型是never的子类型,或者可以分配给never(除了never本身)。即使是 any 也不能分配给 never。
一些函数返回never的例子。
// Function returning never must not have a reachable end pointfunction error(message: string): never {throw new Error(message);}// Inferred return type is neverfunction fail() {return error("Something failed");}// Function returning never must not have a reachable end pointfunction infiniteLoop(): never {while (true) {}}
object
object是一种代表非原生类型的类型,即任何不是number、string、boolean、bigint、符号、null或undefined的类型。
有了对象类型,像Object.create这样的API就可以更好地表示。比如说
declare function create(o: object | null): void;// OKcreate({ prop: 0 });create(null);create(undefined); // Remember, undefined is a subtype of nullArgument of type 'undefined' is not assignable to parameter of type 'object | null'.create(42);Argument of type '42' is not assignable to parameter of type 'object | null'.create("string");Argument of type '"string"' is not assignable to parameter of type 'object | null'.create(false);Argument of type 'false' is not assignable to parameter of type 'object | null'.
一般来说,你不需要使用这个。
类型断言
有时候,你会在一个你比TypeScript更了解一个值的情况下结束。通常,当你知道某个实体的类型可能比它的当前类型更具体时,就会发生这种情况。
类型断言是一种告诉编译器 “相信我,我知道我在做什么 “的方式。类型断言就像其他语言中的类型转换一样,但它不会执行特殊的检查或数据重组。它对运行时没有影响,纯粹由编译器使用。TypeScript假设你,程序员,已经执行了任何你需要的特殊检查。
类型断言有两种形式。
一种是as-syntax。
let someValue: unknown = "this is a string";let strLength: number = (someValue as string).length;
另一个版本是 “角括号 “语法。
let someValue: unknown = "this is a string";let strLength: number = (<string>someValue).length;
这两个样本是等价的。使用一个而不是另一个主要是偏好的选择;然而,当使用TypeScript与JSX时,只允许使用as-style assertions。
关于让的说明
你可能已经注意到,到目前为止,我们一直在使用let关键字,而不是你可能更熟悉的JavaScript的var关键字。let关键字实际上是TypeScript提供的一个较新的JavaScript结构。你可以在Handbook Reference on Variable Declarations中阅读更多关于let和const如何解决var的很多问题。
关于Number、String、Boolean、Symbol和Object。
人们很容易认为Number、String、Boolean、Symbol或Object等类型与上面推荐的小写版本相同。然而,这些类型并不是指语言基元,几乎永远都不应该被用作类型。
function reverse(s: String): String {return s.split("").reverse().join("");}reverse("hello world");
取而代之的是使用数字、字符串、布尔、对象和符号等类型。
function reverse(s: string): string {return s.split("").reverse().join("");}reverse("hello world");
