1. 目标
1). 了解typescript是什么
TypeScript是JavaScript的一个超集, 主要提供了类型系统和对ES6的支持,由
Microsoft
开发,开源。
2). 学会typeScript的基本使用
3). 理解typeScript的基本概念
2. 安装TypeScript
npm install -g typescript
编译TypeScript文件
tsc hello.ts
3. 基础
1). 原始数据类型
布尔值、数值、字符串、空值、Null和Undefined
/**
* 布尔值
*/
let isDone: boolean = false;
// 使用构造函数Boolean创建的对象不是布尔值
// let createdByNewBoolean1: boolean = new Boolean(1); // 错误示范
// Type 'Boolean' is not assignable to type 'boolean'.
// 'boolean' is a primitive, but 'Boolean' is a wrapper object. Prefer using 'boolean' when possible.
let createdByNewBoolean2: Boolean = new Boolean(1); // 正确示范
// 或者直接调用Boolean也可以返回一个`boolean`类型:
let createdByNewBoolean3: boolean = Boolean(1);
/**
* 数值
*/
let decLiteral: number = 7;
/**
* 字符串
*/
let myName: string = 'Tom';
let myAge: number = 25;
// 模板字符串
let sentence: string = `Hello, my name is ${myName}.I'll be ${myAge + 1} years old next month.`;
/**
* 空值
*/
function alertName(): void {
alert('Hello typeScript')
}
// 可赋值为undefined或null
let unusable: void = undefined;
/**
* Null和Undefined
*/
let u: undefined = undefined;
let n: null = null;
// 与void的区别是:
// undefined和null是所有类型的子类型。(所有类型皆可如此赋值), 如:
let num: number = undefined;
// 而void类型的变量不能赋值给number类型的变量。
let u1: void;
let num1: number = u;
// Type 'void' is not assignable to type 'number'.
2). 任意值
用来表示允许赋值为任意类型
1> 声明一个变量为任意值之后,对它的任何操作,返回的内容的类型也都是任意值
let anyThing: any = 'Tom';
anyThing.setName('Jerry');
anyThing.setName('Jerry').sayHello();
anyThing.myName.setFirstName('Cat');
2> 若变量在声明时,微指定其类型,也未进行赋值,那么会被识别为任意类型,如:
let something; // 等价于:let something: any
something = 'seven';
something = 7;
something.setName('Eloise');
3). 类型推论
若未明确指定类型,则ts会依据类型推论的规则(当前赋值)推断一个类型
4). 联合类型
1> 当联合类型的变量未赋值时,ts不确定到底是哪个类型的时候,只能访问此联合类型的所有类型里共有的属性或方法:
/* function getLength(st: string | number): number {
return st.length; // length不是string和number的共有属性,因此会导致报错,报错如下:
// index.ts(2,22): error TS2339: Property 'length' does not exist on type 'string | number'.
// Property 'length' does not exist on type 'number'.
} */
// 正确示范:
function getString(st: string | number): string {
return st.toString();
}
2> 当联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型
let b: string | number;
b = 'eloise'; // 推断为string类型
console.log(b.length); // 6
b = 7; // 推断为number类型
// console.log(b.length); // 编译报错,如下:
// index.ts(5,30): error TS2339: Property 'length' does not exist on type 'number'.
5). 对象的类型--接口
在ts中,使用接口(Interfaces)来定义对象的类型
// 例子
// 接口一般首字母大写
// 定义的变量比接口多/少一些属性是不允许的
// 赋值的时候,变量的形状必须是和接口的形状保持一致的
interface Person {
name: string;
age: number;
}
let tom: Person = {
name: 'Tom',
age: 25
};
/**
* 可选属性(该属性可以不存在)
* 不要完全匹配一个形状的时候使用
* 但是仍然不允许添加未在接口中定义的属性
*/
interface Person1 {
name: string;
age?: number;
}
let tom1: Person1 = {
name: 'Tom',
age: 25 // 可以不存在
}
/**
* 任意属性
* 注意:一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集
*/
// ???存在疑问,tsc编译此处并未进行报错,怀疑是ts版本已更新,而我所阅读的文档未进行更新
interface Person2 {
name: string,
age?: number;
[propName: string]: any;
}
let tom2: Person2 = {
name: 'Tom',
age: 15, // 存在疑问,本应报错,实际并没有
gender: 'male',
}
/**
* 只读属性
* 只读的约束存在于第一次给对象赋值的时候, 而不是第一次给只读属性赋值的时候
*/
interface Person3 {
readonly id: number;
name: string,
age?: number,
[propName: string]: any
}
let tom3: Person3 = {
id: 77,
name: 'Tom',
gender: 'male'
}
// tom3.id = 888; // 会报错,如下:
// index.ts(14,5): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.
6). 数组的类型
有多种定义方式:
1> 「类型 + 方括号」表示法
2> 数组泛型
3> 用接口表示数组
4> 类数组
5> any 在数组中的应用
/**
* 「类型 + 方括号」表示法
*/
let fibonacci: number[] = [1, 1, 2, 3, 5];
/**
* 数组泛型(Array Generic)
* Array<elemType>
*/
let fibonacci1: Array<number> = [1, 2, 3, 4, 5];
/**
* 用接口表示数组
*/
interface NumberArray {
// 只要索引的类型是数字时,那么值的类型必须是数字
// 过于复杂,一般少用
// 但是常用来表示类数组
[index: number]: number;
}
let fibonacci2: NumberArray = [1, 2, 3, 4, 5]
/**
* 类数组(Array-like Object)
*/
function sum() {
// let args: number[] = arguments; // 会报错
}
// Type 'IArguments' is missing the following properties from type 'number[]': pop, push, concat, join, and 24 more.
// arguments是类数组,不可用普通数组方式来描述
function sum1() {
let args: {
[index: number]: number;
length: number;
callee: Function;
} = arguments
}
// 内置对象:事实上常用的类数组都有自己的接口定义,如:IArguments, NodeList, HTMLCollection等。
function sum2(){
let args: IArguments = arguments
}
/*
interface IArguments {
[index: number]: any;
length: number;
callee: Function;
}
*/
/**
* any在数组中的应用
* 用any表示数组中允许出现任意类型
*/
let list: any[] = ['eloise', 77, {website: 'http://www.baidu.com'}]
7). 函数的类型
函数是js中的一等公民
// 在JavaScript中,有两种常见的定义函数的方式
// 函数声明(Function Declaration)
function sum(x, y) {
return x + y;
}
// 函数表达式(Function Expression)
let mySum = function (x, y) {
return x + y;
}
// 在ts中,需要对类型做定义,无论输入值还是输出值
function sum1(x: number, y: number): number {
return x + y;
}
// sum1(1, 2, 3); // 输入多余的(或者少于要求的)参数,是不被允许的
// index.ts(4,1): error TS2346: Supplied parameters do not match any signature of call target.
/**
* 函数表达式
*/
// mySum2编译不会有问题。但是,只对等号右侧的匿名函数进行了类型定义
// 而等号左边的mySum2,是通过赋值操作进行类型推论而推测出来的
let mySum2 = function (x: number, y: number): number {
return x + y;
}
// 如果需要手动给mySum2添加类型
// ts的类型定义中,=>用来表示函数的定义,=>左边是输入类型,需要括号括起来,=>右边是输出类型
let mySum3: (x: number, y: number) => number = function (x: number, y: number): number {
return x + y;
}
/**
* 重载
* 重载允许一个函数接受不同数量或类型的参数时,作出不同处理
*/
// 利用联合类型, 缺点是不够精准表达输入类型 === 输出类型
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('');
}
}
// 精确定义
// 使用重载重新定义多个reverse的函数类型
// 函数定义
function reverse1(x: number):number;
function reverse1(x: string):string;
// 函数实现
function reverse1(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('');
}
}
8). 类型断言
可以用来手动指定一个值的类型
语法:
值 as 类型
或
<类型>值
在 tsx 语法(React 的 jsx 语法的 ts 版)中必须使用前者,即值 as 类型
。
类似<Foo>
的语法在tsx中表示的是一个ReactNode
,在ts中除了表示类型断言之外,也表示一个泛型
因此使用类型断言,统一建议使用值 as 类型
的语法。
正常使用情况下,需要彼此一方对另一方有兼容,则可以去进行断言
9). 声明文件
当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能。
-
declare var
声明全局变量 -
declare function
声明全局方法 -
declare class
声明全局类 -
declare enum
声明全局枚举类型 -
declare namespace
声明(含有子属性的)全局对象 -
interface
和type
声明全局类型 -
export
导出变量 -
export namespace
导出(含有子属性的)对象 -
export default
ES6 默认导出 -
export =
commonjs 导出模块 -
export as namespace
UMD 库声明全局变量 -
declare global
扩展全局变量 -
declare module
扩展模块 -
/// <reference />
三斜线指令
// 三斜线指令,使用场景:
// 1. 当我们在书写一个全局变量的声明文件时
// 2. 当我们需要依赖一个全局变量的声明文件时
10). 内置对象
let b: Boolean = new Boolean(1);
let e: Error = new Error('Error occurred');
let d: Date = new Date();
let r: RegExp = /[a-z]/;
4. 未整理笔记
词汇解析
超集:当有集合A、B,
1> 若B中有的元素,A全部都有,元素相同。则:
A为B的超集, B为A的子集 ( B ⊆ A )
2> 若B中有的元素,A全部都有,并有多于B的元素。则:
B为A的真子集( B ⊂ A )
5. 总结
- typeScript是javaScript的超集
- typeScript增加了代码的可读性和可维护性(大部分函数看类型定义就能明了如何使用)
- 方便快速定位错误(如:代码补全,类型错误,返回值问题,接口提示等。)
- 多人/团队开发、或需复用性代码,建议使用typeScript
6. 待解决问题
- typeScript中的泛型、元组等这些是指什么?
- 如何和框架结合使用(如在vue中如何表现)
网友评论