JAvaScript数据类型分为两种:原始数据类型和对象类型
原始数据类型包括:String、Number、Boolean、null、undefined、Symbol
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);
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;
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.";
JavaScript中没有空值的概念,在TypeScript中,可以用void表示没有任何返回值的函数:
function alertName():void{
alert('alert');
}
//声明一个 void 类型的变量没有什么用,因为你只能将它赋值为 undefined 和 null:
let unusable:void = undefined;
let unusable:void = null;
let u:undefined = undefined;
let n:null = null;
与void的区别是,undefined和null是所有类型的子类型。也就是说undefined类型的变量,可以赋值给number类型的变量。
let num:number = undefined;
任意值(Any)用来表示允许赋值为任意类型
如果是一个普通类型,在赋值过成中改变类型是不被允许的
let myFavoriteNumber:string = 'seven';
myFavoritenumber = 1;
//Type '1' is not assignable to type 'string'.
如果是any类型,则允许被赋值为任意类型
let myFavoriteNumber:any = 'seven';
myFavoritenumber = 1;
在任意值上访问任何属性、方法都是被允许的:
let anyThing:any = 'Hello';
console.log(anyThing.myName);
let anyThing: any = 'Tom';
anyThing.setName('Jerry');
anyThing.setName('Jerry').sayHello();
anyThing.myName.setFirstName('Cat');
可以认为,声明一个变量为任意值之后,对它的任何操作,返回的内容的类型都是任意值。
变量如果在声明时,未指定其类型,那么它会被识别为任意值类型:
let sonething;
something = 'string';
something = 1;
something.setName('Tom');
//等价于
let sonething:any;
something = 'string';
something = 1;
something.setName('Tom');
TypeScript会在没有明确指明类型的情况下,推测出一个类型,这就是类型推论
如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成any类型而完全不被类型检查。
联合类型表示取值可以是多种类型中的一种。
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'.
在TypeScript中我们使用接口(Interfaces)来定义对象的类型.
在面向对象的语言中,接口是对行为的抽象,而具体行为是靠类(class)来实现(implement)
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; }'.
如果想让变量的形状和接口的形状不完全一致,需要设置可选属性: age?:number;
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:'female'
}
注意:一旦定义了任意属性,已经确定属性的类型和可选属性的类型必须是任意属属性的类型的子集
如果我们想对象的某些字段只能在创建的时候被赋值,那么可以在接口的属性前加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.
//两个报错一个是说该复赋值的属性,你不赋值,错!
//另一个是说,属性赋值后补是不可以的。
注意:只要我们给对象的某个属性设置了只读属性,在给对象赋值的时候,如果没有及时给只读属性进行赋值,之后单独给只读属性赋值是不被允许的。
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'.
注意:上面已经确定了数组元素的类型,如果元素中数据类型是非定义的则会报错,如果后追加的元素是非定义的同样会报错。
我们也可以使用数组泛型,Array来表示数组:
let arr:Array = [1,2,3,4,5];
interface NumberArray{
[index:number]:number
}
let arr:NumberArray = [1,2,3,4];
NumberArray表示数组的索引是数字类型表示,数组的元素也必须用数字类型表示。
一般情况我们不用这种方式表示数组,但是在表示类数组的情况通常用这种写法。
类数组(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;
}
let arr:any[] = {'1',3,{'h':2}}
在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.
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中的箭头函数
interface SearchFunc{
(source:string,subString:string):boolean;
}
let muSearch:SearchFunc;
mySearch = function(source:string,subString:string):boolean{
return source.search(subString)!==-1;
}
在参数名后面加‘ ?’
function buildName(firstName: string, lastName?: string) {
if (lastName) {
return firstName + ' ' + lastName;
} else {
return firstName;
}
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');
注意:可选参数后面不能有必需参数了
function buildName(firstName: string,lastName: string='hh'){
return firstName+lastName;
}
注意;此时可选参数可以不是在必需参数后面了;
ES6中用…rest来接收剩余参数
function arr(arr,...items){
items.forEach(function(i){
arr.push(i);
});
return arr;
}
arr([],1,2,3);
注意:rest参数,只能是最后一个参数。
重载允许一个函数接受不同数量,不同类型的参数,做出不同处理
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会从最前面的定义开始匹配,所以函数定义有包含关系,要不精确定义写在前面。
类型断言(Type Assertion)可以手动指定一个值的类型。
<类型>值
或 值 as 类型
在 tsx 语法(React 的 jsx 语法的 ts 版)中必须用后一种。
联合类型中,对于参数类型不确定,如果想调用参数的方法或者属性,需要是已经定义的类型的公有方法或属性,使用起来极其不便,所以延伸出断言,就是提前断定该参数是什么类型的。
function reverse(item:string|number):string{
if((item).length){
return (item).length;
}else{
return item.toString().length;
}
}
注意:断言不是类型转换,断言成联合类型中不存在的类型是不允许的。
断言在联合类型中更好的使用了不同类型数据的方法或者属性。
当时用第三方库的时候,我们需要引用他们的声明文件,才能获得对应的代码补全和接口提示等功能。
如果我们想在TypeScript中使用第三方库jQuery,常见方式是通过
declare var jQuery:(selector:string)=>any;
jQuery('#id')
通常我们会把声明语句放在一个单独的文件(jQuery.d.ts)中:
//src/jQuery.d.ts
declare var jQuery:(selector:string):any;
注意:声明文件必须以 ‘.d.ts’ 结尾
jQuery声明文件不需要我们定义,因为社区已经为我们定义好了
我们可以直接下载下来使用,但是更推荐的是使用 @types
统一管理第三方库的声明文件。@types
的使用方式很简单,直接用npm安装对应的声明模块就可以了,以jQuery为例:npm install [@types](#)/jquery --save-dev
可以在这个页面搜索你需要的声明文件。
库的使用场景主要有以下几种:
标签引入第三方库,注入全局变量import foo from 'foo'
导入,符合 ES6 模块规范
标签引入,又可以通过 import
导入
标签引入后,改变一个全局变量的结构
或 import
导入后,改变另一个模块的结构全局变量的声明文件主要有以下几种语法:
declare var
声明全局变量declare function
声明全局方法declare class
声明全局类declare enum
声明全局枚举类型declare namespace
声明(含有子属性的)全局对象interface
和 type
声明全局类型9.5.1.1 declare var 声明全局变量
声明文件:
//src/jquery.d.ts
//声明语句:
declare let jQuery:(selector:string):any;
//src.index.ts
jQuery('#foo');
//使用declare let 定义的jquery类型,允许修改这个全局变量。
jQuery = function(){
return document.querySelector(selector);
}
如果我们使用const定义时,就不能对这个变量进行修改了。
注意:声明语句只能定义变量类型,不能在里面定义具体的实现。
9.5.1.2 declare function 声明全局方法
declare function jQuery(selector:string)=>any;
在函数类型的声明语句中,也是支持重载的:
// src/jQuery.d.ts
declare function jQuery(selector: string): any;
declare function jQuery(domReadyCallback: () => any): any;
// src/index.ts
jQuery('#foo');
jQuery(function() {
alert('Dom Ready!');
});
9.5.1.3 declare class 声明全局类
declare class Animal{
name:string;
constructor(name:string);
sayHi():string;
}
let cat = new Animal('Tom');
同样的,declare class 只能定义类型,不能定义具体的实现。
9.5.1.4 declare enum 声明全局枚举类型
使用declare enum定义的枚举类型也称外部枚举
declare enum Directions{
Up,
Down,
Left,
Right
}
// src/index.ts
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
9.5.1.5 declare namespace 声明(含有子属性的)全局对象
// src/jQuery.d.ts
declare namespace jQuery {
function ajax(url: string, settings?: any): void;
}
// src/index.ts
jQuery.ajax('/api/get_something');
注意,在 declare namespace
内部,我们直接使用 function ajax
来声明函数,而不是使用 declare function ajax
。类似的,也可以使用 const
, class
, enum
等语句:
// src/jQuery.d.ts
declare namespace jQuery {
function ajax(url: string, settings?: any): void;
const version: number;
class Event {
blur(eventType: EventType): void
}
enum EventType {
CustomClick
}
}
// src/index.ts
jQuery.ajax('/api/get_something');
console.log(jQuery.version);
const e = new jQuery.Event();
e.blur(jQuery.EventType.CustomClick);
9.5.1.6 嵌套的命名空间
如果对象有深层次的层级,则需要nameapace来声明深层次的属性的类型
// src/jQuery.d.ts
declare namespace jQuery {
function ajax(url: string, settings?: any): void;
namespace fn {
function extend(object: any): void;
}
}
// src/index.ts
jQuery.ajax('/api/get_something');
jQuery.fn.extend({
check: function() {
return this.each(function() {
this.checked = true;
});
}
});
假如jQuery下面只有fn这一个属性:
// src/jQuery.d.ts
declare namespace jQuery.fn {
function extend(object: any): void;
}
// src/index.ts
jQuery.fn.extend({
check: function() {
return this.each(function() {
this.checked = true;
});
}
});
9.5.1.7 infterface和type
防止命名冲突:将interface放在jQuery下面:
// src/jQuery.d.ts
declare namespace jQuery {
interface AjaxSettings {
method?: 'GET' | 'POST'
data?: any;
}
function ajax(url: string, settings?: AjaxSettings): void;
}
// src/index.ts
let settings: jQuery.AjaxSettings = {
method: 'POST',
data: {
name: 'foo'
}
};
jQuery.ajax('/api/post_something', settings);
jQuery既是一个函数又是一个对象,有多个方法可以被调用:
declare function jQuery(selector:string):any;
declare namespace jQuery{
function ajax(url:string,setting?:any):any;
}
一般我们通过 import foo from 'foo'
导入一个 npm 包,这是符合 ES6 模块规范的。
在我们尝试给一个 npm 包创建声明文件之前,需要先看看它的声明文件是否已经存在。一般来说,npm 包的声明文件可能存在于两个地方:
package.json
中有 types
字段,或者有一个 index.d.ts
声明文件。这种模式不需要额外安装其他包,是最为推荐的,所以以后我们自己创建 npm 包的时候,最好也将声明文件与 npm 包绑定在一起。@types
里。我们只需要尝试安装一下对应的 @types
包就知道是否存在该声明文件,安装命令是 npm install @types/foo --save-dev
。这种模式一般是由于 npm 包的维护者没有提供声明文件,所以只能由其他人将声明文件发布到 @types
里了。假如以上两种方式都没有找到对应的声明文件,那么我们就需要自己为它写声明文件了。由于是通过 import
语句导入的模块,所以声明文件存放的位置也有所约束,一般有两种方案:
node_modules/@types/foo/index.d.ts
文件,存放 foo
模块的声明文件。这种方式不需要额外的配置,但是 node_modules
目录不稳定,代码也没有被保存到仓库中,无法回溯版本,有不小心被删除的风险,故不太建议用这种方案,一般只用作临时测试。types
目录,专门用来管理自己写的声明文件,将 foo
的声明文件放到 types/foo/index.d.ts
中。这种方式需要配置下 tsconfig.json
中的 paths
和 baseUrl
字段。npm 包的声明文件主要有以下几种语法:
export
导出变量export namespace
导出(含有子属性的)对象export default
ES6 默认导出export =
commonjs 导出模块。。。未完待续
Boolean、Error、Date、RegExp
我么可以在TypeScript中将变量定义成这些类型:
let b: Boolean = new Boolean(1);
let e: Error = new Error('Error occurred');
let d: Date = new Date();
let r: RegExp = /[a-z]/;
Document、HTMLElement、Event、NodeList:
let body: HTMLElement = document.body;
let allDiv: NodeList = document.querySelectorAll('div');
document.addEventListener('click', function(e: MouseEvent) {
// Do something
});
npm install @types/node --save-dev
你可能感兴趣的:(TypeScript)