typescript入门
# 什么是 TypeScript
概念
: TypeScript是JavaScript的超集,具有可选的类型并可以编译为纯JavaScript。从技术上讲TypeScript就是具有静态类型的 JavaScript。
特性
: 类型系统、适用于任何规模、与标准同步发展
# 安装
npm install -g typescript
编译一个 TypeScript 文件:
tsc hello.ts
TypeScript 最大的优势之一便是增强了编辑器和 IDE 的功能,包括代码补全、接口提示、跳转到定义、重构等。
# 原始数据类型
JavaScript 的类型分为两种:原始数据类型
和对象类型
。
原始数据类型包括:布尔值
、数值
、字符串
、null
、undefined
、ES6中的新类型 Symbol
和 ES10 中的新类型 BigInt
。
// 布尔值
let boo: boolean = false;
// 数值
let num: number = 100;
// 字符串
let str: string = 'jason';
// null
let n: null = null;
// undefined
let u: undefined = undefined;
// 空值(用 void 表示没有任何返回值的函数),
function sayHello(): void {
alert('hello jason');
}
// 声明一个 void 类型的变量,只能将它赋值为 undefined 和 null
let v: void = undefined;
# 任意值
用any来表示允许赋值为任意类型。
let anyThing: any = 'jason';
变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型:
let anyThing = 'jason';
等价于
let anyThing: any;
anyThing = 'jason';
# 类型推论
如果没有明确的指定类型,那么 TypeScript 会依照类型推论(Type Inference)的规则推断出一个类型。
let name = 'jason';
name = 7;
// Type 'number' is not assignable to type 'string'.
等价于
let name: string = 'jason';
name = 7;
// Type 'number' is not assignable to type 'string'.
如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查:
// 不会报错,name被推断成 any 类型
let name;
name = 'jason';
name = 7
# 联合类型
联合类型(Union Types)表示取值可以为多种类型中的一种。(联合类型使用 |
分隔每个类型。)
// 不会报错,name是联合类型,既是string又是number
let name: string | number;
name = 'seven';
name = 7;
// 访问联合类型的属性或方法
function getLength(something: string | number): number {
return something.length; // 会报错:length 不是 string 和 number 的共有属性。
}
function getString(something: string | number): string {
return something.toString(); // 不会报错:toString方法 是 string 和 number 的共有属性。
}
// 联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型
let name: string | number;
name = 'jason';
console.log(name.length); // 5
name = 7;
console.log(name.length); // 编译时报错,此时name是number类型,没有length属性
# 对象的类型——接口
接口:用于对类的一部分行为进行抽象,也是对「对象的形状(Shape)」进行描述。
使用接口(Interfaces)来定义对象的类型。
interface Person {
name: string;
age: number;
}
let jason: Person = {
name: 'Jason',
age: 18
};
上例:接口一般首字母大写,不能多写或者少些接口中定义的变量。
# 可选属性
interface Person {
name: string;
age?: number; // 可选属性 ?
}
let jason: Person = {
name: 'Jason',
age: 18
};
# 任意属性
interface Person {
name: string;
age: number;
[propAttr: string]: string | number; // 任意属性(propAttr的名称可以随便写)
}
// 正确
let jason: Person = {
name: 'Jason',
age: 18,
xxx: 'xxxx',
ccc: 'cccc',
ddd: 'dddd',
};
一旦定义了任意属性,确定属性和可选属性的类型都必须是它的类型的子集: 上例的name和age只能是任意属性propAttr
中string | number中的某一个类型
interface Person {
name: string;
age: number;
[propAttr: string]: string; // 任意属性(propAttr的名称可以随便写)
}
// 错误写法, 一旦定义了任意属性,age必须是string类型
let jason: Person = {
name: 'Jason',
age: 18,
xxx: 'xxxx',
ccc: 'cccc',
ddd: 'dddd',
};
# 只读属性
interface Person {
name: string;
readonly age: number; // 只读属性
}
let jason: Person = {
name: 'Jason',
age: 18
};
jason.age = 25 // error TS2540: Cannot assign to 'age' because it is a constant or a read-only property.
# 数组的类型
# 「类型 + 方括号」表示法
let arr: number[] = [1, 1, 2, 3, 5];
# 数组泛型
使用数组泛型(Array Generic) Array<elemType>
来表示数组:
let arr: Array<number> = [1, 1, 2, 3, 5];
# 用接口表示数组
interface IArr {
[index: number]: number;
}
let arr: IArr = [1, 1, 2, 3, 5];
# 类数组
类数组(Array-like Object)不是数组类型
// Type 'IArguments' is missing the following properties from type 'number[]'
function sum() {
let args: number[] = arguments; // 错误
}
// 正确
function sum() {
let args: IArguments = arguments;
}
# any数组
let list: any[] = ['jason', 25, true];
# 函数的类型
# 函数声明
function add(a: number, b: number): number {
return a + b;
}
# 函数表达式
const add = function (a: number, b: number): number {
return a + b;
}
# 接口定义函数
interface AddFunc {
(a: number, b: number): number;
}
// 正确
let mySearch: AddFunc = function(a: number, b: number) {
return a + b;
}
// 错误 // a是number类型
let mySearch: AddFunc = function(a: string, b: number) {
return a + b;
}
# 可选参数
function sayHello(name: string, age?: number) {
if (age) {
return name + '----' + age;
} else {
return name;
}
}
let res = sayHello('jason', 18);
let res1 = sayHello('jason');
# 参数默认值
function sayHello(name: string, age: number = 100) {
if (age) {
return name + '----' + age;
} else {
return name;
}
}
let res = sayHello('jason', 18);
let res1 = sayHello('jason');
# 剩余参数
function fn(...items: any[]) {
items.forEach(function(item) {
//items = [1,2,3]
});
}
fn(1, 2, 3);
# 类型断言
类型断言(Type Assertion)可以用来手动指定一个值的类型。
语法: 值 as 类型
或 <类型>值
将一个联合类型断言为其中一个类型
将一个父类断言为更加具体的子类
# 声明文件
当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能。
# 内置对象
JavaScript 中有很多内置对象,它们可以直接在 TypeScript 中当做定义好了的类型。
Boolean、Error、Date、RegExp 等。
DOM 和 BOM 的内置对象: Document、HTMLElement、Event、NodeList 等。
# 类型别名
类型别名用来给一个类型起个新名字。
type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver): Name {
if (typeof n === 'string') {
return n;
} else {
return n();
}
}
# 字符串字面量类型
字符串字面量类型用来约束取值只能是某几个字符串中的一个。
type Events = 'click' | 'scroll' | 'mousemove';
# 元组
数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象。
let name: [string, number] = ['jason', 18];
# 枚举
取值被限定在一定范围内, 使用enum关键字
enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
# 泛型
指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
function createArray<T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
createArray<string>(3, 'x'); // ['x', 'x', 'x']