https://ts.xcatliu.com/introduction/get-typescript 学习笔记
入门
- 安装
npm install -g typescript
- 编译ts
tsc hello.ts
TypeScript 编写的文件以 .ts 为后缀,用 TypeScript 编写 React 时,以 .tsx 为后缀
TypeScript 只会进行静态检查,如果发现有错误,编译的时候就会报错
TypeScript 编译的时候即使报错了,还是会生成编译结果
基础
原始数据类型
boolean
let isDone: boolean = false;
这个会报错,因为返回的是Boolean对象
let createdByNewBoolean: boolean = new Boolean(1);
这个通过,注意boolean,Boolean不一样
let createdByNewBoolean: Boolean = new Boolean(1);
number
let hexLiteral: number = 0xf00d;
// ES6 中的二进制表示法
let binaryLiteral: number = 0b1010;
// ES6 中的八进制表示法
let octalLiteral: number = 0o744;
let notANumber: number = NaN;
let infinityNumber: number = Infinity;
二进制和八进制的都会被编译成十进制的数字
string
let myName: string = 'Tom';
空值
function alertName(): void {
alert('My name is Tom');
}
声明一个 void 类型的变量没有什么用,因为你只能将它赋值为 undefined 和 null:
let unusable: void = undefined;
Null 和 Undefined(这个需要在看看)
在 TypeScript 中,可以使用 null
和 undefined
来定义这两个原始数据类型:
let u: undefined = undefined;
let n: null = null;
与 void
的区别是,undefined
和 null
是所有类型的子类型。也就是说 undefined
类型的变量,可以赋值给 number
类型的变量:
let num: number = undefined;
// 这样也不会报错
let u: undefined;
let num: number = u;
而 void
类型的变量不能赋值给 number
类型的变量:
let u: void;
let num: number = u;
// Type 'void' is not assignable to type 'number'.
任意值: any
- 普通类型,在赋值过程中改变类型是不被允许的
- 如果是
any
类型,则允许被赋值为任意类型
let myFavoriteNumber: string = 'seven';
myFavoriteNumber = 7;//不通过
let myFavoriteNumber: any = 'seven';
myFavoriteNumber = 7;//通过
let anyThing: any = 'Tom';
anyThing.setName('Jerry');//这个我觉得有点神奇,为什么啊?为什么可以用setName()方法
anyThing.setName('Jerry').sayHello();
anyThing.myName.setFirstName('Cat');
- 声明一个变量为任意值之后,对它的任何操作,返回的内容的类型都是任意值。
- 变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型
let some//等价于
let some:any
类型推论
let some = 'a'//等价于
let some:string = 'a'
联合类型
表示取值可以为多种类型中的一种,用 | 分隔
let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法
function getLength(something: string | number): number {
return something.length;//不通过,length只是string的属性
return something.toString();//通过,这是string和number的共有方法
}
联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型
let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
console.log(myFavoriteNumber.length); // 5
myFavoriteNumber = 7;
console.log(myFavoriteNumber.length); // 编译时报错
对象类型
使用接口(Interfaces)来定义对象的类型
interface Person {
name: string;
age: number;
}
let tom: Person = {
name: 'Tom',
age: 25
};//属性不允许多,也不允许少
有时我们希望不要完全匹配一个形状,那么可以用可选属性?:
interface Person {
name: string;
age?: number;
}
let tom: Person = {
name: 'Tom'
};//可选属性意思是这个属性可以少,但是不允许增加自定义属性
任意属性
interface Person {
readonly name: string;//readonly只读,不允许第二次赋值
age?: number;
[propName: string]: any;
// [propName: string]: string;//不通过,string不是string和number的父级
}
let tom: Person = {
name: 'Tom',
gender: 'male'
};
一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集
数组的类型
简单表示
let fibonacci: number[] = [1, 1, 2, 3, 5];
let fibonacci: number[] = ['1', 1, 2, 3, 5];//不通过,数组中不允许出现字符串
数组泛型
let fibonacci: Array
用接口表示数组
interface NumberArray {
[index: number]: number;
}
let fibonacci: NumberArray = [1, 1, 2, 3, 5];
类数组
不能用普通的数组的方式来描述,而应该用接口:
function sum() {
let args: {
[index: number]: number;
length: number;
callee: Function;
} = arguments;
}
内置对象
IArguments, NodeList, HTMLCollection
任意
let list: any[] = ['xcatliu', 25, { website: 'http://xcatliu.com' }];
函数
输入多余的(或者少于要求的)参数,是不被允许的
function sum(x: number, y: number): number {
return x + y;
}
sum(1, 2, 3);//不通过
sum(1);//不通过
函数表达式这样写
let mySum: (x: number, y: number) => number = function (x: number, y: number): number {
return x + y;
};
注意不要混淆了 TypeScript 中的 => 和 ES6 中的 =>。
在 TypeScript 的类型定义中,=> 用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型。
- 可以用接口定义函数形状,
- 可选参数用【?】可选参数必须放在最后面
- 可以设置默认值
interface SearchFunc {
(source: string="lala", subString?: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
return source.search(subString) !== -1;
}
剩余参数
...rest 是个数组,所以可以...rest:any[]
重载
重载允许一个函数接受不同数量或类型的参数时,作出不同的处理
function reverse(x: number | string): number | string {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}
类型断言
<类型>值
或
值 as 类型//react 要求用这种格式
类型断言不是类型转换,断言成一个联合类型中不存在的类型是不允许的:
function toBoolean(something: string | number): boolean {
return something;
}
声明语句
declare var jQuery: (selector: string) => any;
jQuery('#foo');
声明文件
通常我们会把声明语句放到一个单独的文件(jQuery.d.ts)中
第三方声明文件
npm install @types/jquery --save-dev
自己书写声明文件
库的使用场景主要有以下几种:
- 全局变量:通过
标签引入第三方库,注入全局变量
- npm 包:通过
import foo from 'foo'
导入,符合 ES6 模块规范 - UMD 库:既可以通过
标签引入,又可以通过
import
导入 - 直接扩展全局变量:通过
标签引入后,改变一个全局变量的结构
- 在 npm 包或 UMD 库中扩展全局变量:引用 npm 包或 UMD 库后,改变一个全局变量的结构
- 模块插件:通过
或
import
导入后,改变另一个模块的结构
1. 全局变量
全局变量的声明文件主要有以下几种语法:
-
declare var
声明全局变量 -
declare function
声明全局方法 -
declare class
声明全局类 -
declare enum
声明全局枚举类型 -
declare namespace
声明(含有子属性的)全局对象 -
interface
和type
声明全局类型
需要注意的是,声明语句中只能定义类型,切勿在声明语句中定义具体的实现5:
declare const jQuery: (selector: string) => any;
declare const jQuery = function(selector) {
return document.querySelector(selector);
};//会报错
2.
类型别名
type Name = string;
type NameOrResolver = Name | NameResolver;
我们使用 type 创建类型别名,一般用在联合类型
字符串字面量类型
type EventNames = 'click' | 'scroll' | 'mousemove';
function handleEvent(ele: Element, event: EventNames) {
// do something
}
handleEvent(document.getElementById('hello'), 'scroll'); // 没问题
handleEvent(document.getElementById('world'), 'dbclick'); // 报错,event 不能为 'dbclick'
event 只能是'click','scroll','mousemove',其中一个
元组
数组含有不同类型
let tom: [string, number] = ['Tom', 25];
越界的值必须是声明中的联合类型
枚举
enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
枚举成员会被赋值为从 0 开始递增的数字,同时也会对枚举值到枚举名进行反向映射
var Days;
(function (Days) {
Days[Days["Sun"] = 0] = "Sun";
Days[Days["Mon"] = 1] = "Mon";
Days[Days["Tue"] = 2] = "Tue";
Days[Days["Wed"] = 3] = "Wed";
Days[Days["Thu"] = 4] = "Thu";
Days[Days["Fri"] = 5] = "Fri";
Days[Days["Sat"] = 6] = "Sat";
})(Days || (Days = {}));
可以手动赋值
enum Color {Red, Green, Blue = "blue".length};
enum Color {Red= "blue".length, Green, Blue };//计算所得项后面不能有非手动赋值的项
常数枚举
使用 const enum 定义的枚举类型
常数枚举与普通枚举的区别是,它会在编译阶段被删除,并且不能包含计算成员。
外部枚举
declare enum Directions {
Up,
Down,
Left,
Right
}
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];