Appearance
一、特点
- TypeScript 是添加了类型系统的 JavaScript,适用于任何规模的项目。
- TypeScript 是一门静态类型、弱类型的语言。
- TypeScript 是完全兼容 JavaScript 的,它不会修改 JavaScript 运行时的特性。
- TypeScript 可以编译为 JavaScript,然后运行在浏览器、Node.js 等任何能运行 JavaScript 的环境中。
- TypeScript 拥有很多编译选项,类型检查的严格程度由你决定。
- TypeScript 可以和 JavaScript 共存,这意味着 JavaScript 项目能够渐进式的迁移到 TypeScript。
- TypeScript 增强了编辑器(IDE)的功能,提供了代码补全、接口提示、跳转到定义、代码重构等能力。
- TypeScript 拥有活跃的社区,大多数常用的第三方库都提供了类型声明。
- TypeScript 与标准同步发展,符合最新的 ECMAScript 标准(stage 3)。
二、运行
- 安装 TypeScript
npm install -g typescript
- 编译 TypeScript 文件
tsc helloworld.ts
helloworld.ts => helloworld.js
三、优化编译
- ts 编译成 js 函数名重复报错
tsc --init
生成一个 tsconfig.json 的配置文件
json
/* Type Checking */
"strict": true, // 严格模式,可以注掉或者设置为false
- 自动编译成 js 文件
tsc --watch
- 出现错误问题时不进行编译成 js
tsc --noEmitOnError --watch
- 降级编译 tsconfig.json
json
// 修改配置文件
"target": "es2016", // es7
//可自行改为es5 默认情况下以es3作为目标编译
- 严格模式(3 种)
json
"strict": true, //所有的类型都检验
"noImplicitAny": true, //对any的类型检验
"strictNullChecks": true, //对undefined和null的类型检验
四、TypeScript 基础类型
String 类型
ts
let name: string = "Peter";
Number 类型
ts
let count: number = 10;
Boolean 类型
ts
let isDone: boolean = false;
Array(两种)
ts
let list: number[] = [1, 2, 3];
let list: Array<number> = [1, 2, 3]; // Array<type>泛型语法
Tuple 类型-元组
明确数组每个成员值类型的数组为元组
ts
let tom: [string, number] = ["Tom", 25];
Any 类型(任意类型/全局超级类型)
ts
let notSure: any = 666;
notSure = "Peter";
notSure = false;
//无论怎么赋值都不会报错
由于 any
类型太过于宽松,设置 any
类型完全背离了 typeScript 的思想,所以不建议使用 为了解决 any
带来的问题,TypeScript 3.0 引入了 unknown
类型。
Unknown 类型
就像所有类型都可以赋值给 any
,所有类型也都可以赋值给 unknown
。 这使得 unknown
成为 TypeScript 类型系统的另一种顶级类型(另一种是 any
)。
ts
let value: unknown;
value = true; // OK
value = 42; // OK
value = "Hello World"; // OK
value = []; // OK
value = {}; // OK
value = Math.random; // OK
value = null; // OK
value = undefined; // OK
value = new TypeError(); // OK
value = Symbol("type"); // OK
对 value 变量的所有赋值都被认为是类型正确的。 但是,将类型为 unknown
的值赋值给其他类型的变量时会报错
ts
let value: unknown;
let value1: unknown = value; // OK
let value2: any = value; // OK
let value3: boolean = value; // Error
let value4: number = value; // Error
let value5: string = value; // Error
let value6: object = value; // Error
let value7: any[] = value; // Error
let value8: Function = value; // Error
unknown
类型只能被赋值给 any
类型和 unknown
类型本身。
ts
let value: unknown;
value.foo.bar; // Error
value.trim(); // Error
value(); // Error
new value(); // Error
value[0][1]; // Error
将 value 变量类型设置为 unknown
后,这些操作都不再被认为是类型正确的。 通过将 any
类型改变为 unknown
类型,我们已将允许所有更改的默认设置,更改为禁止任何更改。
Enum 类型
- 使用枚举可以定义一些带名字的常量。
- 使用枚举可以清晰地表达意图或创建一组有区别的用例。
- TypeScript 支持数字的和基于字符串的枚举。
(1). 数字枚举
ts
enum color {
red = 10,
green,
yellow,
}
console.log(color.green); //11
console.log(color.yellow); //12
(2).字符串枚举
ts
enum sex {
male = "男",
female = "女",
unknown = "未知",
}
(3).异构枚举
异构枚举的成员值是数字和字符串的混合:
ts
enum obj {
up = "上",
green = 10,
}
Void 类型
表示没有任何类型 通常会见到其返回值类型是 void
:
ts
// 声明函数返回值为void
function warnUser(): void {
console.log("This is my warning message");
}
声明一个 void 类型的变量没有什么作用,因为它的值只能为 undefined 或 null:
ts
let unusable: void = undefined;
Null 和 Undefined 类型
ts
let u: undefined = undefined;
let n: null = null;
默认情况下 null 和 undefined 是所有类型的子类型。 就是说你可以把 null 和 undefined 赋值给 number 类型的变量。
然而,如果你指定了--strictNullChecks 标记,null 和 undefined 只能赋值给 void 和它们各自的类型。
Never 类型
永不存在的值的类型。
例如,never 类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型。
ts
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}
function infiniteLoop(): never {
while (true) {}
}
对象类型(接口)
ts
interface Person {
name: string;
age: number;
age?: number; //(可选属性)
[propName: string]: any; //任意属性
[propName: string]: string | number; //任意属性+联合类型
readonly id: number; //只读属性
}
let tom: Person = {
name: "Tom",
age: 25,
};
五、TypeScript 断言
有时候你会遇到这样的情况,你会比 TypeScript 更了解某个值的详细信息。 通常这会发生在你清楚地知道一个实体具有比它现有类型更确切的类型。 通过类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么”。 类型断言好比其他语言里的类型转换,但是不进行特殊的数据检查和结构。 它没有运行时的影响,只是在编译阶段起作用。
“尖括号” 语法
ts
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
as 语法
ts
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
非空断言
在上下文中当类型检查器无法断定类型时,一个新的后缀表达式操作符!
可以用于断言操作对象是非 null 和非 undefined 类型。 具体而言,x! 将从 x 值域中排除 null 和 undefined 。
使用场景:
- 忽略 undefined 和 null 类型
ts
function myFunc(maybeString: string | undefined | null) {
//类型'string | null | undefined'不能赋值给类型'string'
//类型'undefined'不能赋值给类型'string'
const onlyString: string = maybeString; // Error
const ignoreUndefinedAndNull: string = maybeString!; // Ok
}
- 调用函数时忽略 undefined 类型
ts
type NumGenerator = () => number;
function myFunc(numGenerator: NumGenerator | undefined) {
//对象可能是'undefined'。
//无法调用可能为'undefined'的对象。
const num1 = numGenerator(); // Error
const num2 = numGenerator!(); //OK
}
注意:
因为 ! 非空断言操作符会从编译生成的 JavaScript 代码中移除,所以在实际使用的过程中,要特别注意。
- 确定赋值断言 在 TypeScript 2.7 版本中引入了确定赋值断言,即允许在实例属性和变量声明后面放置一个 ! 号,从而告诉 TypeScript 该属性会被明确地赋值。
ts
let x: number;
initialize();
//变量'x'在赋值之前被使用。
console.log(2 * x); // Error
function initialize() {
x = 10;
}
很明显该异常信息是说变量 x 在赋值前被使用了,要解决该问题,可以使用确定赋值断言:
ts
let x!: number;
initialize();
console.log(2 * x); // Ok
function initialize() {
x = 10;
}
六、TypeScript 类型守卫
类型保护是可执行运行时检查的一种表达式,用于确保该类型在一定的范围内。 换句话说,类型保护可以保证一个字符串是一个字符串,尽管它的值也可以是一个数值。 类型保护与特性检测并不是完全不同,其主要思想是尝试检测属性、方法或原型,以确定如何处理值。 目前主要有四种的方式来实现类型保护:
in 关键字
ts
interface Admin {
name: string;
privileges: string[];
}
interface Employee {
name: string;
startDate: Date;
}
type UnknownEmployee = Employee | Admin;
function printEmployeeInformation(emp: UnknownEmployee) {
console.log("Name: " + emp.name);
if ("privileges" in emp) {
console.log("Privileges: " + emp.privileges);
}
if ("startDate" in emp) {
console.log("Start Date: " + emp.startDate);
}
}
typeof 关键字
ts
function padLeft(value: string, padding: string | number) {
if (typeof padding === "number") {
return Array(padding + 1).join(" ") + value;
}
if (typeof padding === "string") {
return padding + value;
}
throw new Error(`Expected string or number, got '${padding}'.`);
}
typeof
类型保护只支持两种形式:typeof v === "typename"
和 typeof v !== typename
, typename
必须是 number
, string
, boolean
或 symbol
。
但是 TypeScript 并不会阻止你与其它字符串比较,语言不会把那些表达式识别为类型保护。
instanceof 关键字
ts
interface Padder {
getPaddingString(): string;
}
class SpaceRepeatingPadder implements Padder {
constructor(private numSpaces: number) {}
getPaddingString() {
return Array(this.numSpaces + 1).join(" ");
}
}
class StringPadder implements Padder {
constructor(private value: string) {}
getPaddingString() {
return this.value;
}
}
let padder: Padder = new SpaceRepeatingPadder(6);
if (padder instanceof SpaceRepeatingPadder) {
// padder的类型收窄为 'SpaceRepeatingPadder'
}
自定义类型保护的类型谓词
ts
function isNumber(x: any): x is number {
return typeof x === "number";
}
function isString(x: any): x is string {
return typeof x === "string";
}
七、TypeScript 联合类型
联合类型通常与 null 或 undefined 一起使用:
ts
const sayHello = (name: string | undefined) => {
/* ... */
};
例如,这里 name 的类型是 string | undefined 意味着可以将 string 或 undefined 的值传递给sayHello 函数。
八、TypeScript 泛型
泛型(Generics)是允许同一个函数接受不同类型参数的一种模板。相比于使用 any 类型,使用泛型来创建可复用的组件要更好,因为泛型会保留参数类型。