命令
生成 tsconfig.json 文件
tsc --init
联合类型
使用
|
分隔类型
let nameOrAge: string | number = "gauhar";
nameOrAge = 18;
合并类型
使用
&
符号,将多个类型合并
const name: { firstName: string } & { lastName: string } = {
firstName: "gauhar",
lastName: "chan",
};
interface 接口
名称使用大写开头,或者以
I
开头使用
?
说明属性是可选的。
[propName: string]: any
指定该接口有,这个any
说明任意属性可以是任意类型。如果换成string
,则该接口下,必选、可选的属性都必须是string
类型。
readonly
定义属性只读。即初始化赋值,后面不可改。
interface Person {
name: string;
age?: number;
[propName: string]: any;
readonly noChange: string;
}
let tom: Person = {
name: "Tom",
};
数组
number[]
: 数字类型数组
string[]
: 字符串数组
any[]
: 任意类型数组
函数
可选参数
c?: number
,非可选参数缺一不可,类型也要一致
但,如果参数使用默认值,参数就是可选参数,那么限制就不存在了
let add = (a: number = 123, b: number, c?: number): number => a + b;
上面的写法,add 的类型并没有指定,而是推导出来的。下面是指定的写法
左边定义 add 的
=>
并不是es6
中的箭头函数,而是说明是函数,返回number
类型
let add: (a: number, b: number, c?: number) => number = (
a: number,
b: number,
c?: number
): number => a + b;
// 上面的写法不美观,可以使用接口代替
interface Iadd {
(a: number, b: number, c?: number): number;
}
let add: Iadd = (a: number, b: number, c?: number): number => a + b;
剩余参数
...items
就是除了array
的所有参数,而他是一个数组,所以使用数组类型声明。他必须放在参数最后一位
function push(array: any[], ...items: any[]) {
items.forEach(function (item) {
array.push(item);
});
}
let a = [];
push(a, 1, 2, 3);
重载
重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。
多次定义不同类型的函数,这样就可以保证当参数
a
是number
类型的时候返回number
类型
TypeScript 会优先从最前面的函数定义开始匹配,所以多个函数定义如果有包含关系,需要优先把精确的定义写在前面。
function f1(a: number): number;
function f1(a: string): string;
function f1(a: number | string): number | string {
return typeof a === "number" ? 1 : "1";
}
类型断言
我们自己指定一个值的类型。
需要注意的是,类型断言只能够「欺骗」TypeScript 编译器,无法避免运行时的错误,反而滥用类型断言可能会导致运行时错误
let duan: string | number;
(duan as string) = 123; // 报错,类型断言为string类型
当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型中共有的属性或方法
interface Icat {
name: string;
run(): void;
}
interface Ifish {
name: string;
swim(): void;
}
function isCat(animal: Icat | Ifish) {
console.log(animal.name); // 共同拥有name属性
console.log(animal.run); // 报错 run只存在于Icat接口,并不是共同拥有的
}
使用断言,指定为特定的接口,就可以使用
function ifFish(animal: Icat | Ifish) {
(animal as Icat).run();
}
声明文件
.d.ts 文件
全局声明
全局变量的声明文件主要有以下几种语法:
declare var
声明全局变量declare function
声明全局方法declare class
声明全局类declare enum
声明全局枚举类型declare namespace
声明(含有子属性的)全局对象interface
和type
声明全局类型
内置对象
eq:
IArguments
描述arguments
这个类数组常用的类数组都有自己的接口定义,如
IArguments
,NodeList
,HTMLCollection
等
let b: Boolean = new Boolean(1);
let e: Error = new Error("Error occurred");
let d: Date = new Date();
let r: RegExp = /[a-z]/;
类型别名
给类型起一个别的名称,下面
$1
代表number
类型。使用type
定义。建议名称首字母大写
type $1 = number;
type St = string;
const a: $1 = 123;
字符串字面量类型
约束只能取指定的值
type name = "gauhar" | "chan";
let name2: name = "chan";
元组
初始化赋值时(或者是通过下标赋值),必须按照顺序的类型
let tuple: [string, number] = ["string", 123];
越界的元素
使用
push
等方法时,元素的类型会被限制为元组中每个类型的联合类型
let tuple: [string, number];
tuple.push(123);
tuple.push(true); // 报错。 类型“true”的参数不能赋给类型“string | number”的参数。
枚举
定义枚举的时候就要初始化赋值,如果没有指定值,则默认以 0 开始赋值,
0,1,2...
。不能通过属性名修改值 。
enum Week {
SUN,
MON,
TUE = ‘星期二’
}
Week.SUN = 'dsf' // 报错,只读属性
console.log(Week.SUN === 0); // true
未手动赋值的枚举项会接着上一个枚举项递增,下面的TUE
就是 2、接着 3、4 以此类推
enum Week {
SUN = 5,
MON = 1,
TUE, // 2
}
类
静态方法
使用 static
修饰符修饰的方法称为静态方法,它们不需要实例化,而是直接通过类来调用:
class Animal {
static isAnimal(a) {
return a instanceof Animal;
}
}
let a = new Animal("Jack");
Animal.isAnimal(a); // true
a.isAnimal(a); // TypeError: a.isAnimal is not a function
ES7
实例属性
不需要通过
this.xxx
来定义
class Animal {
name = "Jack";
constructor() {
// ...
}
}
let a = new Animal();
console.log(a.name); // Jack
修饰符
public
修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是public
的private
修饰的属性或方法是私有的,不能在声明它的类的外部访问protected
修饰的属性或方法是受保护的,它和private
类似,区别是它在子类中也是允许被访问的
readonly 属性
只读,不可修改
装饰器
方法装饰器
let test = (value?: any) => (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
const method = descriptor.value
descriptor.value = (...args: any[]) => {
console.log(value);
if (value) method.apply(this, args)
}
return descriptor
}
@test('hello test')
public mounted (): void {
console.log('mounted');
}