TypeScript学习之二——基础

TypeScript学习之二——基础

  • 原始数据类型
  • 任意值
  • 类型推论
  • 联合类型
  • 对象的类型——接口
  • 数组的类型
  • 函数的类型
  • 类型断言
  • 声明文件
  • 内置对象

1. 原始数据类型

JAvaScript数据类型分为两种:原始数据类型和对象类型
原始数据类型包括:String、Number、Boolean、null、undefined、Symbol

1.1 布尔值

let isDone:boolean = false;

注意:使用构造函数创建的是对象类型不是布尔类型

let isDone: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 s:Boolean = new Boolean(1);
//这种写法就是正确得了,new Boolean()返回的是一个Boolean对象

直接调用Boolean也可以返回一个boolean类型。

let s:boolean = Boolean(1);

1.2 数值

let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;
// ES6 中的二进制表示法
let binaryLiteral: number = 0b1010;
// ES6 中的八进制表示法
let octalLiteral: number = 0o744;
let notANumber: number = NaN;
let infinityNumber: number = Infinity;

编译结果:

var decLiteral = 6;
var hexLiteral = 0xf00d;
// ES6 中的二进制表示法
var binaryLiteral = 10;
// ES6 中的八进制表示法
var octalLiteral = 484;
var notANumber = NaN;
var infinityNumber = Infinity;

1.3 字符串

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.`;

编译结果:

var myName = 'Tom';
var myAge = 25;
// 模板字符串
var sentence = "Hello, my name is " + myName + ".\nI'll be " + (myAge + 1) + " years old next month.";

1.4 空值

JavaScript中没有空值的概念,在TypeScript中,可以用void表示没有任何返回值的函数:

function alertName():void{
	alert('alert');
}

//声明一个 void 类型的变量没有什么用,因为你只能将它赋值为 undefined 和 null:
let unusable:void = undefined;
let unusable:void = null;

1.5 Null和Undefined

let u:undefined = undefined;
let n:null = null;

与void的区别是,undefined和null是所有类型的子类型。也就是说undefined类型的变量,可以赋值给number类型的变量。

let num:number = undefined;

2. 任意值

任意值(Any)用来表示允许赋值为任意类型

2.1 什么是任意类型

如果是一个普通类型,在赋值过成中改变类型是不被允许的

let myFavoriteNumber:string = 'seven';
myFavoritenumber = 1;
//Type '1' is not assignable to type 'string'.

如果是any类型,则允许被赋值为任意类型

let myFavoriteNumber:any = 'seven';
myFavoritenumber = 1;

2.2 任意值的属性和方法

在任意值上访问任何属性、方法都是被允许的:

let anyThing:any = 'Hello';
console.log(anyThing.myName);

let anyThing: any = 'Tom';
anyThing.setName('Jerry');
anyThing.setName('Jerry').sayHello();
anyThing.myName.setFirstName('Cat');

可以认为,声明一个变量为任意值之后,对它的任何操作,返回的内容的类型都是任意值。

2.3 未声明类型的变量

变量如果在声明时,未指定其类型,那么它会被识别为任意值类型:

let sonething;
something = 'string';
something = 1;
something.setName('Tom');

//等价于
let sonething:any;
something = 'string';
something = 1;
something.setName('Tom');

3. 类型推论

TypeScript会在没有明确指明类型的情况下,推测出一个类型,这就是类型推论
如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成any类型而完全不被类型检查。

4. 联合类型

联合类型表示取值可以是多种类型中的一种。

let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;

联合类型用 | 分隔不同类型

注意:访问联合类型的属性或者方法需要访问所有已定类型公有的属性或者方法

let myFavoriteNumber: string | number;
console.log(myFavoriteNumber.length)
// Property 'length' does not exist on type 'string | number'.
// Property 'length' does not exist on type 'number'.
// 报错原因是length是string数据类型的属性,但不是number类型的属性

console.log(myFavoriteNumber.toString())  //right
// toString()方法是string和number类型公有的方法

联合类型的变量在被赋值的时候,会根据被赋值的值的类型推断变量的类型。

let myFavoriteNumber: string | number;
myFavoriteNumber = 'GG';
myFavoriteNumber.length; //2
myFavoriteNumber = 6;
myFavoriteNumber.length; // Property 'length' does not exist on type 'number'.

5.对象的类型——接口

在TypeScript中我们使用接口(Interfaces)来定义对象的类型.

5.1 什么是接口

在面向对象的语言中,接口是对行为的抽象,而具体行为是靠类(class)来实现(implement)

5.2 举个栗子:

interface Person{
  name:string;
  age:number;
}
let Tom:Person = {
  name:'Tom',
  age:12
} 

//就目前这个例子,对于接口的理解就是将对像的属性类型提前定义好。
//我们约束了tom的形状必须和Person一致。

定义的变量比接口少一些或者多一些属性都是不被允许的:

interface Person{
  name:string;
  age:number;
}
let Tom:Person = {
  name:'Tom'
}
//Type '{ name: string; }' is not assignable to type 'Person'.
//Property 'age' is missing in type '{ name: string; }'.

5.3 可选属性

如果想让变量的形状和接口的形状不完全一致,需要设置可选属性: age?:number;

interface Person{
  name:string;
  age?:number;
}
let Tom:Person = {
  name:'Tom'
}

5.4 任意属性

interface Person{
  name:string;
  age?:number;
  [propName:string]:any
}
let Tom:Person = {
  name:'Tom',
  gender:'female'
}

注意:一旦定义了任意属性,已经确定属性的类型和可选属性的类型必须是任意属属性的类型的子集

5.5 只读属性

如果我们想对象的某些字段只能在创建的时候被赋值,那么可以在接口的属性前加readonly

interface Person{
  readonly id:number;
}
let tom:Person = {
  id:123456
}

tom.id = 342143;
//Cannot assign to 'id' because it is a read-only property.

注意:只读属性约束的是第一次在给对象赋值的时候,而不是第一次给只读属性赋值的时候:

interface Person{
  readonly id:number;
  name:string;
}
let tom:Person = {
  name:'gg'
}

tom.id = 342143;
//Property 'id' is missing in type '{ name: string; gender: string; }' but required in type 'Person'.
//Cannot assign to 'id' because it is a read-only property.
//两个报错一个是说该复赋值的属性,你不赋值,错!
//另一个是说,属性赋值后补是不可以的。

注意:只要我们给对象的某个属性设置了只读属性,在给对象赋值的时候,如果没有及时给只读属性进行赋值,之后单独给只读属性赋值是不被允许的。

5.6 总结:

  • 接口定义用interface关键字
  • 定义接口属性的时候,如果最初确定了要定义属性的个数,后期在对象中是不能任意加或者减属性的。
  • 如果想更灵活的定义接口属性个数,需要加【propName:string】:any ,这意思是后期对象赋值时,属性随便加,但是有一点,任意属性的类型必须是包含接口其他属性定义的类型。
  • 接口中定义的某个属性,想在对象赋值的时候想赋值就赋值,不想赋值就不赋值,需要在接口属性后加?。
  • 只读属性,在给对象赋值的时候就给该属性赋值,否则后期想加或者想改是没机会了。

6. 数组类型

6.1 「类型 + 方括号」表示法

let arr:number[] = [1,2,3,4,5];
let arr:number[] = ['1',2,3,4,5];
//error TS2322: Type 'string' is not assignable to type 'number'.
arr.push('0');
//error TS2345: Argument of type '"2"' is not assignable to parameter of type 'number'.

注意:上面已经确定了数组元素的类型,如果元素中数据类型是非定义的则会报错,如果后追加的元素是非定义的同样会报错。

6.2 数组泛型

我们也可以使用数组泛型,Array来表示数组:

let arr:Array = [1,2,3,4,5];

6.3 接口表示数组

interface NumberArray{
	[index:number]:number
}

let arr:NumberArray = [1,2,3,4];

NumberArray表示数组的索引是数字类型表示,数组的元素也必须用数字类型表示。
一般情况我们不用这种方式表示数组,但是在表示类数组的情况通常用这种写法。

6.4 类数组

类数组(array-link object)不是数组类型,比如arguments:

function sum(){
    let args:number[] = arguments;
}

sum(1,2,3);
//Type 'IArguments' is missing the following properties from type 'number[]': pop, push, concat, join, and 15 more.
//Expected 0 arguments, but got 3.
//类数组不是数组,所以不能用数组类型表示

arguments是一个类数组,不是普通数组,所以需要用接口表示

function sum(){
    let args:{
        [index:number]:number;
        length:number;
        callee:Function;
    } = arguments;
}

//callee被调用者;被调用函数

事实上,常用的类数组都有自己的接口定义,IArguments、NodeList、HTMLCollection等;

function sum(){
	let args:IArrguments = arguments;
}

其中IArrguments是TypeScript定义好的类型:

interface IArrguments{
	[index:number]:number;
  length:number;
  callee:Function;
}

6.5 any在数组中的应用

let arr:any[] = {'1',3,{'h':2}}

7. 函数类型

7.1 函数声明

在JavaScript中,常见的函数定义的方式——函数声明和函数表达式

//函数声明
function sum(x,y){
	return x+y;
}
//函数表达式
let sum = function(x,y){
	retuen x+y;
}

一个函数有输入有输出,要在TypeScript中对其进行约束,需要把输入和输出都考虑到,其中函数声明的类型定义比较简单:

function sum(x:number,y:number):number{
	return x+y;
}

注意:输入多余或者少于要求的参数,是不被允许的:

function sum(x:number,y:number):number{
	return x+y;
}
sum(1,2,3);
sum(1);
//index.ts(4,1): error TS2346: 
//Supplied parameters do not match any signature of call target.

7.2 函数表达式

let muSum = function (x:number,y:number):number{
	return x+y;
}

这种写法虽然可以编译,但是不完全正确

let muSum:(x:number,y:number)=>number = function (x:number,y:number):number{
	return x+y;
}

注意:上面的=> 不同于ES6中的箭头函数

7.3 用接口定义函数的形状

interface SearchFunc{
  (source:string,subString:string):boolean;
}

let muSearch:SearchFunc;
mySearch = function(source:string,subString:string):boolean{
	return source.search(subString)!==-1;
}

7.3 可选参数

在参数名后面加‘ ?’

function buildName(firstName: string, lastName?: string) {
    if (lastName) {
        return firstName + ' ' + lastName;
    } else {
        return firstName;
    }
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');

注意:可选参数后面不能有必需参数了

7.4 参数默认值

function buildName(firstName: string,lastName: string='hh'){
	return firstName+lastName;
}

注意;此时可选参数可以不是在必需参数后面了;

7.5 剩余参数

ES6中用…rest来接收剩余参数

function arr(arr,...items){
  items.forEach(function(i){
  	arr.push(i);
  });
  return arr;
}
arr([],1,2,3);

注意:rest参数,只能是最后一个参数。

7.6 重载

重载允许一个函数接受不同数量,不同类型的参数,做出不同处理

function reverse(x: number): number;
function reverse(x: string): string;
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函数,前几次都是函数的定义,最后一次是函数的实现,TypeScript会从最前面的定义开始匹配,所以函数定义有包含关系,要不精确定义写在前面。

8. 类型断言

类型断言(Type Assertion)可以手动指定一个值的类型。

8.1 语法

<类型>值  或  值 as 类型 
在 tsx 语法(React 的 jsx 语法的 ts 版)中必须用后一种。

8.2 断言的作用

联合类型中,对于参数类型不确定,如果想调用参数的方法或者属性,需要是已经定义的类型的公有方法或属性,使用起来极其不便,所以延伸出断言,就是提前断定该参数是什么类型的。

function reverse(item:string|number):string{
	if((item).length){
  	return (item).length;
  }else{
    return item.toString().length;
  }
}

注意:断言不是类型转换,断言成联合类型中不存在的类型是不允许的。
断言在联合类型中更好的使用了不同类型数据的方法或者属性。

9. 声明文件

当时用第三方库的时候,我们需要引用他们的声明文件,才能获得对应的代码补全和接口提示等功能。

9.1 新语法索引

  • 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 扩展模块
  • ///  三斜线指令

9.2 什么是声明语句

如果我们想在TypeScript中使用第三方库jQuery,常见方式是通过

declare var jQuery:(selector:string)=>any;
jQuery('#id')

9.3 什么是声明文件

通常我们会把声明语句放在一个单独的文件(jQuery.d.ts)中:

//src/jQuery.d.ts
declare var jQuery:(selector:string):any;

注意:声明文件必须以 ‘.d.ts’ 结尾

9.4 第三方声明文件

jQuery声明文件不需要我们定义,因为社区已经为我们定义好了
我们可以直接下载下来使用,但是更推荐的是使用 @types 统一管理第三方库的声明文件。
@types 的使用方式很简单,直接用npm安装对应的声明模块就可以了,以jQuery为例:
npm install [@types](#)/jquery --save-dev

可以在这个页面搜索你需要的声明文件。

9.5 书写声明文件

库的使用场景主要有以下几种:

  • 全局变量:通过

你可能感兴趣的:(TypeScript)