目标
- 基础
- 原理
- 常见面试题与实践
知识要点
安装
npm install -g typescript
hello.ts
function sayHello(person:string){
return 'hello'+person;
}
编译
tsc hello.ts
输出
function sayHello(person) {
return 'hello' + person;
}
TypeScript 简介
添加了类型系统的JavaScript,适用于任何规模的项目
特性
- 类型系统
- 适用于任何规模
Javascript 灵活
- 没有类型约束,可以转我字符串,数字
- 存在隐式转换,变量类型运行前无法确定
- 原型上的属性或者方法可以在运行时被修改
- 函数可以赋值给变量,参数或者返回值
- 解析语言,没有编译阶段
双刃剑
- 无所不能
- 常见就是隐式转换导致判断错误
- 代码质量残差不齐,维护成本高,运行时错误多
- 语言的类型错误,导致运行时的错误
TypeScript 是静态类型,编译阶段就能确定每个变量的类型,编译阶段进行类型检查
可以类型自动推论出没有定义的类型的变量
原始数据类型
//boolean
let isDone:boolean = false;
let booleanObject:Boolean = new Boolean(1);//调用构造函数
let booleanObject:boolean = Boolean(1)//调用函数
//number
let decLiteral:number =6;
// ES6 中的二进制表示法
let binaryLiteral: number = 0b1010;
// ES6 中的八进制表示法
let octalLiteral: number = 0o744;
let notANumber: number = NaN;
let infinityNumber: number = Infinity;
//string
let myName:string ='Tom';
// 模板字符串
let sentence: string = `Hello, my name is ${myName}.
I'll be ${myAge + 1} years old next month.`;
//空值,声明一个 void 类型的变量没有什么用,因为你只能将它赋值为 undefined 和 null
//1.没有返回任何值的函数
function setName():void{
}
let unusable: void = undefined;//没有任何意义
//Null 和 Undefined
let u:undefined=undefined;
let n:null = null;
let num:number = undefined;
let u:undefined;
let num:number = u;
任意值
用来表示允许赋值为任意类型
let myFavoriteNumber:any = 'seven';//可以被改变类型,赋予任何值
变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型:
let something;
something = 'seven';
something = 7;
something.setName('Tom');
类型推论
如果没有明确的指定类型,那么 TypeScript 会依照类型推论 (Type Inference)的规则推断出一个类型。
let myFavoriteNumber = 'seven';
//它等价于
let myFavoriteNumber: string = 'seven';
如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查:
let myFavoriteNumber;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
联合类型
取值可以为多种类型中的一种
let myV: string | number;
myV='seven';
myV=7;
访问联合类型的属性或方法
当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候, 我们只能访问此联合类型的所有类型里共有的属性或方法:
function getLength(something: string | number): number {
return something.length;
}
// 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(something: string | number): string {
return something.toString();
}
对象的类型---接口
使用接口定义对象的类型
interface Person{
name:string;
age:number;
}
let tom:Person={
name:'Tom',
age:25,
}
定义的变量比接口少了一些属性是不允许的,多一些属性也是不允许的
interface Person {
name: string;
age: number;
}
let tom: Person = {
name: 'Tom'
};
// index.ts(6,5): error TS2322: Type '{ name: string; }' is not assignable to type 'Person'.
// Property 'age' is missing in type '{ name: string; }'.
interface Person {
name: string;
age: number;
}
let tom: Person = {
name: 'Tom',
age: 25,
gender: 'male'
};
// index.ts(9,5): error TS2322: Type '{ name: string; age: number; gender: string; }' is not assignable to type 'Person'.
// Object literal may only specify known properties, and 'gender' does not exist in type 'Person'.
可选属性
仍然不允许添加未定义的属性
interface Person{
name:string,
age?:number;
}
let tom:Person = {
name:'Tom'
}
任意属性
一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集:
interface Person{
name:string;
age?:number;
[propName:string]:any;
}
let tom:Person={
name:'Tom',
gender:'male'
}
// index.ts(3,5): error TS2411: Property 'age' of type 'number' is not assignable to string index type 'string'.
// index.ts(7,5): error TS2322: Type '{ [x: string]: string | number; name: string; age: number; gender: string; }' is not assignable to type 'Person'.
// Index signatures are incompatible.
// Type 'string | number' is not assignable to type 'string'.
// Type 'number' is not assignable to type 'string'.
任意属性的值允许是 string,但是可选属性 age 的值却是 number,number 不是 string 的子属性,所以报错了。 //使用联合类型
interface Person {
name: string;
age?: number;
[propName: string]: string | number;
}
let tom: Person = {
name: 'Tom',
age: 25,
gender: 'male'
};
只读属性
只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候
interface Person{
readonly id:number;
name:string;
age?:number;
[propName:string]:any;
}
let tom:Person={
id:89797,
name:'Tom',
gender:'male'
}
tom.id=9527
// index.ts(14,5): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.
数组的类型
let fibonacci:number[]=[1,1,2,3,5];
数组的项中不允许出现其他的类型 数组的一些方法的参数也会根据数组在定义时约定的类型进行限制
let fibonacci: number[] = [1, '1', 2, 3, 5];
// Type 'string' is not assignable to type 'number'.
let fibonacci: number[] = [1, 1, 2, 3, 5];
fibonacci.push('8');
// Argument of type '"8"' is not assignable to parameter of type 'number'.
数组泛型
let fib:Array<number>=[1,1]
类数组
类数组(Array-like Object)不是数组类型,比如 arguments 常用的类数组都有自己的接口定义,如 IArguments, NodeList, HTMLCollection 等
function sum(){
let args:{
[index:number]:number;
length:number;
callee:Function;
}=arguments;
}
function sum1() {
let args: IArguments = arguments;
}
interface IArguments{
[index:number]:any;
length:number;
callee:Function;
}
any 在数组中的应用
let list: any[] = ['xcatliu', 25, { website: 'http://xcatliu.com' }];
函数的类型
- 函数声明
function sum(x,y){
return x+y;
}
2.函数表达式
let mySum = function(x,y) {
return x+y;
}
一个函数有输入和输出,要在 TypeScript 中对其进行约束
function sum(x:number,y:number):number{
return x+y;
}
let mySum = function(x:number,y:number):number {
return x+y;
}
let mySum1:(x:number,y:number)=>number = function(x:number,y:number):number{
return x+y;
}
输入多余的参数,少于是不被允许的
function sum(x: number, y: number): number {
return x + y;
}
sum(1, 2, 3);
// index.ts(4,1): error TS2346: Supplied parameters do not match any signature of call target.
function sum(x: number, y: number): number {
return x + y;
}
sum(1);
// index.ts(4,1): error TS2346: Supplied parameters do not match any signature of call target.
用接口定义函数的形状
采用函数表达式|接口定义函数的方式时,对等号左侧进行类型限制,可以保证以后对函数名赋值时保证参数个数、参数类型、返回值类型不变。
interface SearchFunc{
(source:string,subString:string):boolean;
}
let mySearch:SearchFunc;
mySearch = function(source:string,subString:string) {
return -1;
}
可选参数
可选参数后面不允许再出现必需参数了
function buildName(firstName:string,lastName?:string){
if(lastName){
return firstName +''+lastName;
}else{
return firstName;
}
}
let tomcat = buildName('tom','cat');
let tom = buildName('tom');
参数默认值
TypeScript 会将添加了默认值的参数识别为可选参数, 此时就不受「可选参数必须接在必需参数后面」的限制了
function buildName(firstName:string,lastName:string='Cat'){
return firstName+' '+lastName;
}
let tomcat = buildName('tom','cat');
let tom = buildName('Tom');
剩余参数
function push(array,...items){
items.forEach(function(item) {
array.push(item);
})
}
let a:any[] =[];
push(a,1,2,3);
重载
重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。
function reverse(x:number|string):number|string|void {
if(typeof x ==='number'){
return Number(x.toString().split('').reverse().join(''));
}else if(typeof x ==='string'){
return x.split('').reverse().join('')
}
}
然而这样有一个缺点,就是不能够精确的表达,输入为数字的时候, 输出也应该为数字,输入为字符串的时候,输出也应该为字符串。
这时,我们可以使用重载定义多个 reverse 的函数类型
function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string | void {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}
类型断言
值 as 类型 <类型>值 报错
interface Cat {
name: string;
run(): void;
}
interface Fish {
name: string;
swim(): void;
}
function isFish(animal: Cat | Fish) {
if (typeof animal.swim === 'function') {
return true;
}
return false;
}
// index.ts:11:23 - error TS2339: Property 'swim' does not exist on type 'Cat | Fish'.
// Property 'swim' does not exist on type 'Cat'.
正确断言
interface Cat {
name: string;
run(): void;
}
interface Fish {
name: string;
swim(): void;
}
function isFish(animal: Cat | Fish) {
if (typeof (animal as Fish).swim === 'function') {
return true;
}
return false;
}
声明文件
ts.xcatliu.com/basics/decl… 当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能
什么是声明文件
假如我们想使用第三方库 jQuery,一种常见的方式是在 html 中通过 <script> 标签引入 jQuery,然后就可以使用全局变量 $ 或 jQuery 了。
我们通常这样获取一个 id 是 foo 的元素:
$('#foo');
// or
jQuery('#foo');
但是在 ts 中,编译器并不知道 $ 或 jQuery 是什么东西1:
jQuery('#foo');
// ERROR: Cannot find name 'jQuery'.
这时,我们需要使用 declare var 来定义它的类型2:
declare var jQuery: (selector: string) => any;
jQuery('#foo');
上例中,declare var 并没有真的定义一个变量,只是定义了全局变量 jQuery 的类型,仅仅会用于编译时的检查,在编译结果中会被删除。它编译结果是:
jQuery('#foo');
- declare var 声明全局变量-----
declare var并没有真的定义一个变量,只是定义了全局变量jQuery的类型 - declare function 声明全局方法
- declare class 声明全局类
- declare enum 声明全局枚举类型
- declare namespace 声明(含有子属性的)全局对象
- interfance 和type
- export 导出变量
- export namespace 导出(含有子属性的)对象
- export default ES6默认导出
- export = commonjs导出模块
- export as namespace UMD库声明全局变量
- declare global扩展全局变量
- declare module 扩展模块
- /// 三斜线指令
第三方声明文件
可以在这个网址搜索到 www.typescriptlang.org/dt/search?s…=