学习TypeScript 12 个基本类型
1、Number数字类型
整数、浮点数、正负数
和JavaScript一样,TypeScript里的所有数字都是浮点数。 这些浮点数的类型是 number。 除了支持十进制和十六进制字面量,TypeScript还支持ECMAScript 2015中引入的二进制和八进制字面量。
2、String字符串类型
“hello”,’hello’,hello(反引号可以创建一个字符串模板,分段、分行、填充变量)
模版字符串,它可以定义多行文本和内嵌表达式(${ }嵌入表达式)。
let name1:string=Gene;
let age:number=37;
// let sentence:string="Hello,my name is"+name1+".\n\n"+"I'll be"+(age+1)+"years old next month.";
let sentence:string=Hello,my name is ${name1}.I'll be ${age+1} years old next month.;
console.log(sentence) //Hello,my name is Gene.I'll be 38 years old next month.
3、Boolean布尔类型
4、数组(array)
两种定义方式
let list:number[]=[1,2,3];
let list1:Array=[1,2,3]; //数组泛型Array<元素类型>
5、元组(tuple)(固定长度固定类型)
元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。
定义一对值分别为string和number类型的元组
let x:[string,number];
x=['hello',10];
当访问一个越界的元素,会使用联合类型替代??????????????????
就是说后面的元素可以为前面已经有过的元素类型。
6、枚举(enum)
enum Color{Red,Green,Blue}
let c:Color=Color.Green;
enum Color{Red=1,Green,Blue} //改成从1开始编号
let c:Color=Color.Green;
枚举类型提供的一个便利是你可以由枚举的值得到它的名字。 例如,我们知道数值为2,但是不确定它映射到Color里的哪个名字,我们可以查找相应的名字:
let colorName:string=Color[2];
console.log(colorName); //'Green'
7、Any
有时候,我们会想要为那些在编程阶段还不清楚类型的变量指定一个类型。这种情况下,我们不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。 那么我们可以使用 any类型来标记这些变量。
let notSure:any=4;
notSure ="maybe a string instead";
notSure =false;
Object(对象或变量)有相似的作用,就像它在其它语言中那样。 但是 Object类型的变量只是允许你给它赋任意值,但是却不能够在它上面调用任意的方法,即便它真的有这些方法。
8、Void
某种程度上来说,void类型像是与any类型相反,它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是 void。声明一个void类型的变量没有什么大用,因为你只能为它赋予undefined和null。
function warnUser():void{
console.log("This is my warning message");
}
let unusable:void=undefined;
9、Null
let n:null=null;
10、Undefined
let u:undefined=undefined;
11、Never
never类型表示的是那些永不存在的值的类型。 never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型;
function error(message:string):never{
throw new Error(message);
}
12、Object(对象)
object表示非原始类型,也就是除number,string,boolean,symbol(象征,符号)(表示独一无二),null或undefined之外的类型。使用object类型,就可以更好的表示像Object.create这样的API。
declare function create(o:object|null):void;
create({prop:0}); //ok
create(null); //ok
// create("string"); //Error
// create(false); //Error
// create(undefined); //Error
深入理解TypeScript 重要高级类型
联合类型
联合类型(Union Types)表示取值可以为多种类型中的一种。联合类型使用 | 分隔每个类型。
字面量类型
字面量 给变量赋值时,等号右边都可以认为是字面量。
字面量分为字符串字面量(string literal )、数组字面量(array literal)、对象字面量(object literal),函数字面量(function literal)。
类型适配(断言);类型断言
TypeScript会假设我们已经进行了必须的检查。类型断言有两种形式。1、“尖括号”语法:
let SomeValue:any="this is a string";
let strLength:number=(SomeValue).length;
2、as语法:
let SomeValue1:any="this is a string";
let strLength1:number=(SomeValue1 as string).length;
两种形式是等价的。当你在TypeScript里使用JSX时,只有 as语法断言是被允许的。
关于let
很多常见的问题都可以通过使用 let来解决,所以尽可能地使用let来代替var。
function f(input:boolean){
let a=100;
if (input){
let b=a+1;
return b;
}
// return b; //报错 找不到名称“b”。
}
Const声明(常量)
它们拥有与 let相同的作用域规则,但是不能对它们重新赋值。它们引用的值是不可变的。
const变量的内部状态是可修改的。
const numLivesForCat=9;
const kitty={
name:"Aurrora",
numLives:numLivesForCat,
}
// kitty={
// name:"Danielle";
// numLives:numLivesForCat
// }; //报错 无法分配到 "kitty" ,因为它是常数。
kitty.name="Rory";
kitty.name="Kitty";
kitty.name="Cat";
kitty.numLives--;
解构数组
可以在数组里使用...语法创建剩余变量:
let[first1,...rest]=[1,2,3,4];
console.log(first1); //1
console.log(rest); //[2,3,4]
对象解构
let o={
a:"foo",
b:12,
c:"bar"
}
属性重命名
let {a:newName1,b:newName2}=o;
展开操作符
1展开数组
let first3=[1,2];
let second1=[3,4];
let bothPlus=[0,...first3,...second1,5];
console.log(bothPlus) //[ 0, 1, 2, 3, 4, 5 ]
2展开对象
let defaults={food:"spicy",price:"$$",ambiance:"noisy"};
let search={...defaults,food:"rich"};
console.log(search) //{ food: 'rich', price: '$$', ambiance: 'noisy' }
对象展开仅包含对象自身的可枚举属性,当你展开一个对象实例时,你会丢失其方法。对象里的方法丢了。
class C{
p=12;
m(){
}
}
let c=new C();
let clone={...c};
clone.p;
clone.m(); //报错 类型“{ p: number; }”上不存在属性“m”。
接口
TypeScript的核心原则之一是对值所具有的结构进行类型检查,接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约。类型检查器不会去检查属性的顺序,只要相应的属性存在并且类型也是对的就可以。
interface LabelledValue{
label:string;
}
function printLabel(labelledObj:LabelledValue){
console.log(labelledObj.label);
}
let myObj={size:10,label:"Size 10 Object"};
printLabel(myObj); //Size 10 Object
LabelledValue接口就好比一个名字,用来描述上面例子里的要求。 它代表了有一个 label属性且类型为string的对象。
可选属性(option bags),接口里的属性不全都是必须的。在可选属性名字定义的后面加一个?符号。通过?来使属性变成选填。但是不能多项。
interface SquareConfig{
color?:string;
width?:number;
}
function creatSquare(config:SquareConfig):{color:string;area:number}{
let newSquare={color:"white",area:100};
if(config.color){
newSquare.color=config.color;
}
if (config.width){
newSquare.area=config.width*config.width;
}
return newSquare;
}
let mySquare=creatSquare({color:"black"});
console.log(mySquare) //{ color: 'black', area: 100 }
只读属性(readOnly)
interface Point{
readonly x:number;
readonly y:number;
}
赋值一个字面量来构造一个Point,赋值后x和y不能被改变
let p1:Point={x:10,y:20};
// p1.x=5; //无法分配到 "x" ,因为它是只读属性。
TypeScript具有ReadonlyArray类型(只读)
let a1:number[]=[1,2,3,4];
let ro:ReadonlyArray=a1;
// ro[0]=12; //报错 类型“readonly number[]”中的索引签名仅允许读取。
// a1=ro; //报错
但可以用类型断言重写
a1=ro as number[];
readonly vs const
最简单判断该用readonly还是const的方法是看要把它做为变量使用还是做为一个属性。 做为变量使用的话用 const,若做为属性则使用readonly。
额外的属性检查
interface SquareConfig{
color?:string;
width?:number;
}
function createSquare(config:SquareConfig):{ color:string;area:number}{
}
let mySquare1=createSquare({colour:"red",width:100});
createSquare的参数拼写为colour而不是color,ts会认为存在bug,
对象字面量会被特殊对待而且会经过额外检查。对象文字只能指定已知的属性,但“colour”中不存在类型“SquareConfig”。
对象字面量存在“目标类型”不包含的属性。
解决方法
1、添加一个字符串索引签名????????????????????????
要表示的是SquareConfig可以有任意数量的属性,并且只要它们不是color和width,那么就无所谓它们的类型是什么。
interface SquareConfig{
color?:string;
width?:number;
[propName:string]:any;
}
2、将这个对象赋值给一个另一个变量
因为 squareOptions不会经过额外属性检查,所以编译器不会报错。
let squareOptions={colour:"red",width:100};
let mySquare=createSquare(squareOptions);
接口描述函数类型
接口能够描述JavaScript中对象拥有的各种各样的外形。 除了描述带有属性的普通对象外,接口也可以描述函数类型。为了使用接口表示函数类型,我们需要给接口定义一个调用签名。它就像是一个只有参数列表和返回值类型的函数定义。参数列表里的每个参数都需要名字和类型。
可索引的类型
与使用接口描述函数类型差不多,比如a[10]或ageMap["daniel"]。 可索引类型具有一个 索引签名,它描述了对象索引的类型,还有相应的索引返回值类型。
interface StringArray{
[index:number]:string;
}
let myArray:StringArray;
myArray=["Bob","Fred"];
let myStr:string=myArray[0];
索引签名
TypeScript支持两种索引签名:字符串和数字。
可以同时使用两种类型的索引,但是数字索引的返回值必须是字符串索引返回值类型的子类型。 这是因为当使用 number来索引时,JavaScript会将它转换成string然后再去索引对象。 也就是说用 100(一个number)去索引等同于使用"100"(一个string)去索引,因此两者需要保持一致。
字符串索引签名
interface NumberDictionary{
[index:string]:number;
length:number;
// name:string //报错 类型“string”的属性“name”不能赋给“string”索引类型“number”。
可以将索引签名设置为只读,这样就防止了给索引赋值
interface ReadonlyStringArray{
readonly [index:number]:string;
}
let myArray1:ReadonlyStringArray=["Alice","Bob"];
// myArray1[2]="Mallory"; //报错,只读
类接口
可以在接口中描述一个方法,在类里实现它。
interface ClockInterface{
currentTime:Date;
setTime(d:Date);
}
class Clock implements ClockInterface{
currentTime: Date;
setTime(d:Date){
this.currentTime=d;
}
constructor(h:number,m:number){}
}
类是具有两个类型的:静态部分的类型和实例的类型。??????????????
静态方法是操作类型的,实例方法是操作具体实例的。静态方法不能调用实例方法和变量,实例方法可以调用静态方法和变量。
当一个类实现了一个接口时,只对其实例部分进行类型检查。 constructor存在于类的静态部分,所以不在检查的范围内。
因此,我们应该直接操作类的静态部分。下面的例子定义了两个接口, ClockConstructor为构造函数所用和ClockInterface为实例方法所用。 为了方便我们定义一个构造函数 createClock,它用传入的类型创建实例。
因为createClock的第一个参数是ClockConstructor类型,在createClock(AnalogClock, 7, 32)里,会检查AnalogClock是否符合构造函数签名。
interface ClockConstructor{
new (hour:number,minute:number):ClockInterface;
}
interface ClockInterface{
tick();
}
function createClock(ctor:ClockConstructor,hour:number,minute:number):ClockInterface{
return new ctor(hour,minute);
}
class DigitalClock implements ClockInterface{
constructor(h:number,m:number){}
tick() {
console.log("beep beep");
}
}
class AnalogClock implements ClockInterface{
constructor(h:number,m:number){}
tick(){
console.log("tick tock");
}
}
let digital=createClock(DigitalClock,12,17);
let analog=createClock(AnalogClock,7,32);
console.log(digital)
console.log(analog)
继承接口
接口也可以相互继承,一个接口可以继承多个接口
interface Shape{
color:string;
}
interface PenStroke{
penWidth:number;
}
interface Square extends Shape,PenStroke{
sideLength:number;
}
let aquare={};
aquare.color="blue";
aquare.sideLength=10;
aquare.penWidth=5.0;
混合类型
一个对象可以同时作为函数和对象使用
interface Counter{
(start:number):string;
interval:number;
reset():void;
}
function getCounter():Counter{
let counter=function (start:number){};
counter.interval=123;
counter.reset=function(){};
return counter;
}
let c=getCounter();
c(10);
c.reset();
c.interval=5.0;
接口继承类???????????????????
接口可以对类实现继承,但只能继承类的成员,不会继承类成员的实现。
实现(implement)
类
继承
派生类通常被称作子类,基类通常被称作超类。
在TypeScript里,成员都默认为 public(公有)。
当成员被标记成 private时,它就不能在声明它的类的外部访问。
protected修饰符与 private修饰符的行为很相似,但有一点不同,protected成员在派生类中仍然可以访问。
class Person{
protected name:string;
protected constructor(theName:string){this.name=theName;}
}
class Employee extends Person{
private department:string;
constructor(name:string,department:string){ //??????????
super(name);
this.department=department;
}
public getElevatorPitch(){
return Hello,my name is ${this.name} and I work in ${this.department}.;
}
}
let howard=new Employee("Howard","Sales");
// let john=new Person("John"); //类“Person”的构造函数是受保护的,仅可在类声明中访问。
constructor方法是Class类的默认方法,通过new命令,创建一个新的实例对象时,会自动调用此方法。一个类必须有constructor()方法,如果创建类的时候,没有显示的定义该方法,一个空的 constructor()方法会被默认添加。类必须使用 new 命令调用,否则会报错。
Readonly修饰符
可以使用 readonly关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化。
class Octopus{
readonly name:string;
readonly numberOfLegs:number=8;
constructor(theName:string){
this.name=theName;
}
}
let dad=new Octopus("Man with the 8 strong legs");
// dad.name="Man with the 3-poece suit"; //无法分配到 "name" ,因为它是只读属性。
参数属性
// 下面的例子是对之前 Octopus类的修改版,使用了参数属性,舍弃了theName.
class Octopus1{
readonly numberOfLegs:number=8;
constructor(readonly name:string){
}
}
存取器?????????????????????????
TypeScript支持通过getters/setters来截取对对象成员的访问。它能帮助你有效的控制对对象成员的访问。
let passcode="secret passcode";
class Employee1{
private _fullName:string;
get fullName():string{
return this._fullName;
}
set fullName(newName:string){
if(passcode && passcode="secret passcode"){
this._fullName=newName;
}else{
console.log("Error:Unauthorized update of employee!");
}
}
}
let employee=new Employee1();
employee.fullName="Bob Smith";
if(employee.fullName){
alert(employee.fullName);
}
静态属性????????????????
这些属性存在于类本身上面而不是类的实例上面。
如同在实例属性上使用 this.前缀来访问属性一样,这里我们使用 Grid.来访问静态属性。
class Grid{
static origin={x:0,y:0};
calculateDistanceFromOrigin:(point:{x:number;y:number;}){
let xDist=(point.x-Grid.origin.x);
let yDist=(point.y-Grid.origin.y);
return Math.sqrt(xDistxDist+yDistyDist)/this.scale;
}
constructor(public scale:number){ }
}
let grid1=new Grid(1.0);
let grid2=new Grid(5.0);
console.log(grid1.calculateDistanceFromOrigin({x:10,y:10}));
console.log(grid2.calculateDistanceFromOrigin({x:10,y:10}));
抽象类(abstract)
抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化。
abstract关键字是用于定义抽象类和在抽象类内部定义抽象方法。 抽象方法的语法与接口方法相似。 两者都是定义方法签名但不包含方法体。 然而,抽象方法必须包含 abstract关键字并且可以包含访问修饰符。
访问控制修饰符
四种访问级别:public、protected、默认、private
private只能在同一个类中访问
默认,只能在同一个类,同一个包中访问
protected,可以在统一各类,同一个包,子类(子类可以不在同一个包中)访问
public,不限制访问
类可用修饰符: abstract、public、final
构造方法:public、protected、private
局部变量:仅仅final
abstract class Department{
constructor(public name:string){
}
printName():void{
console.log('Deparment name:'+this.name);
}
abstract printMeeting():void; //必须在派生类中实现
}
class AccountingDeparment extends Department{
constructor(){
super('Accounting and Auditing'); //在派生类的构造函数中必须调用super()
}
printMeeting():void{
console.log('The Accounting Department meets each Monday at 10am.');
}
generateReports():void{
console.log('Generating accounting reports...');
}
}
let department:Department; //允许创建一个对抽象类型的引用
// department=new Department(); //报错 无法创建抽象类的实例
department=new AccountingDeparment(); //允许创建一个抽象子类进行实例化和赋值
department.printName();
department.printMeeting();
// department.generateReports();
//报错 类型“Department”上不存在属性“generateReports”。方法在声明的抽象类中不存在。
构造函数
let greeter: Greeter,意思是 Greeter类的实例的类型是 Greeter。
class Greeter{
greeting:string;
constructor(message:string){
this.greeting=message;
}
greet(){
return"Hello,"+this.greeting;
}
}
let greeter:Greeter; //Greeter类的实例的类型是 Greeter。
greeter=new Greeter("world");
console.log(greeter.greet());
把类当作接口使用
class Point{
x:number;
y:number;
}
interface Point3d extends Point{
z:number;
}
let point3d:Point3d={x:1,y:2,z:3};
函数
函数类型包含两部分:参数类型和返回值类型
可选参数和默认参数
TypeScript里的每个函数参数都是必须的。JavaScript里,每个参数都是可选的,可传可不传。
在TypeScript里我们可以在参数名旁使用 ?实现可选参数的功能。可选参数必须跟在必须参数后面。
带默认值的参数不需要放在必须参数的后面。
function buildName(firstName="Will",lastName:string){
return firstName+" "+lastName;
}
// let result1=buildName("Bob"); //应有 2 个参数,但获得 1 个。
// let result2=buildName("Bob","Adams","Sr."); //应有 2 个参数,但获得 3 个。
let result3=buildName("Bob","Adams");
let result4=buildName(undefined,"Adams"); //放前面的话需要加undefined
剩余参数
Js里可以使用arguments访问所有传入的参数,ts里可以把所有参数收集到一个变量里,例如参数数组名字是restOfName,
function buildName1(firstName:string,...restOfName:string[]){
return firstName+" "+restOfName.join(" ");
}
let employeeName=buildName1("Joseph","Samuel","Lucas","Mackinzie");
// 这个省略号也会在带有剩余参数的函数类型定义上使用到:
let buildNameFun:(fname:string,...rest:string[])=>string=buildName1;
This参数?????????????????????????教程上看不懂
this参数是个假的参数,它出现在参数列表的最前面,this: void意味着addClickListener期望传入的onclick方法不需要this,这个是给TypeScript编译器看的。而箭头函数的this就是它所在上下文的this值, 作为自己的this值。并且在箭头函数中,是没法使用this参数的。箭头函数不会捕获this,可以用this:void;
重载
多个函数函数名相同,函数的参数类型,顺序,个数不同。方法是为同一个函数提供多个函数类型定义来进行函数重载。
// 重载pickCard函数,重载的pickCard函数在调用的时候会进行正确的类型检查。
// 红心。黑桃。梅花。方块。
let suits=["hearts","spades","clubs","diamonds"];
function pickCard(x:{suit:string;card:number;}[]):number;
function pickCard(x:number):{suit:string;card:number;};
function pickCard(x):any{
// 检查我们是否正在使用对象/数组。如果是,他们给了我们一副牌,我们将挑选牌
if(typeof x=="object"){
let pickedCard=Math.floor(Math.random()*x.length);
return pickedCard;
}
// 否则,就让他们选牌吧
else if(typeof x=="number"){
let pickedSuit=Math.floor(x/13);
return {suit:suits[pickedSuit],card:x%13};
}
}
let myDeck=[{suit:"diamonds",card:2},{suit:"spades",card:10},{suit:"hearts",card:4}];
let pickedCard1=myDeck[pickCard(myDeck)];
alert("card:"+pickedCard1.card+"of"+pickedCard1.suit);
let pickedCard2=pickCard(15);
alert("card:"+pickedCard2.card+"of"+pickedCard2.suit);
泛型
不用泛型的样子
function identity(arg:number):number{
return arg;
}
用泛型 给identity添加了类型变量T,identity函数叫做泛型,因为它可以适用于多个类型。
不同于使用 any,它不会丢失信息。
function identity1(arg:T):T{
return arg;
}
两种使用方式
let output=identity1("myString"); //第一种
let output1=identity1("myString"); //第二种 编译器会自动确定类型
使用泛型变量
实现使用长度属性
function loggingIndentity(arg:T):T{
// console.log(arg.length); //报错,类型“T”上不存在属性“length”。
return arg;
改进方式:
如果我们传入数字数组,将返回一个数字数组,因为此时 T的的类型为number。 这可以让我们把泛型变量T当做类型的一部分使用,而不是整个类型,增加了灵活性。
function loggingIdentity(arg:T[]):T[]{
console.log(arg.length);
return arg;
}
泛型类型
function identity2(arg:T):T{
return arg;
}
let myIdentity:(arg:T)=>T=identity2;
let myIdentity1:(arg:U)=>U=identity2;
使用带有调用签名的对象字面量((arg: T): T)来定义泛型函数
let myIdentity2:{(arg:T):T}=identity2;
泛型接口
interface GenericIdentityFn{
(arg:T):T;
}
function identity3(arg:T):T{
return arg;
}
let myIdentity3:GenericIdentityFn=identity3;
创建泛型类
泛型类指的是实例部分的类型,所以类的静态属性不能使用这个泛型类型。
class GenericNumber{
zeroValue:T;
add:(x:T,y:T)=>T;
}
let myGenericNumber=new GenericNumber();
myGenericNumber.zeroValue=10;
myGenericNumber.add=function(x,y){return x+y;};
console.log(myGenericNumber.add(myGenericNumber.zeroValue,30)) //40
// 或者
let stringNumberic=new GenericNumber();
stringNumberic.zeroValue=" ,";
stringNumberic.add=function(x,y){return x+y;};
console.log(stringNumberic.add(stringNumberic.zeroValue,"test")); // ,test
泛型约束???????????????????
定义一个接口来描述约束条件,创建一个包含 .length属性的接口,使用这个接口和extends关键字来实现约束。
interface Lengthwise{
length:number;
}
function LoggingIndengtity(arg:T):T{
console.log(arg.length);
return arg;
}
// loggingIndentity1(3); //报错 必须包含必须的属性
console.log(loggingIdentity1({length:10,value:3}));
在泛型约束中使用类型参数
// 在泛型约束中使用类型函数
function getProperty(obj: T,key: K){ //???????????????为啥会报错?
return obj[key]; //找不到名称“T”
}
let x={a:1,b:2,c:3,d:4};
console.log(getProperty(x,"a"))
getProperty(x,"m"); //这个应该报错
在泛型里使用类类型
使用泛型创建工厂函数时,需要引用构造函数的类类型。
function creat(c:{new():T;}):T{
return new c();
}
枚举enum
enum Direction{
Up=1,
Down,
Left,
Right
}
每个枚举成员的值都是不同的。
字符串枚举
enum Direction{
Up1="UP",
Down1="DOWN",
Left1="LEFT",
Right1="RIGHT",
}
异构枚举 枚举可以混合字符串和数字成员,但一般不这样做。
Const枚举(const enum)
常量枚举只能使用常量枚举表达式,并且不同于常规的枚举,它们在编译阶段会被删除。 常量枚举成员在使用的地方会被内联进来。 之所以可以这么做是因为,常量枚举不允许包含计算成员。
外部枚举
外部枚举用来描述已经存在的枚举类型的形状。外部枚举和非外部枚举之间有一个重要的区别,在正常的枚举里,没有初始化方法的成员被当成常数成员。 对于非常数的外部枚举而言,没有初始化方法时被当做需要经过计算的。
declare enum Enum{
A=1,
B,
C=2
}
模块
TypeScript 1.5里术语名已经发生了变化。 “内部模块”现在称做“命名空间”。 “外部模块”现在则简称为“模块”,这是为了与 ECMAScript 2015里的术语保持一致,(也就是说 module X 相当于现在推荐的写法 namespace X )。一个模块里可能会有多个命名空间。
TS任何包含顶级import或者export的文件都被当成一个模块。相反地,如果一个文件不带有顶级的import或者export声明,那么它的内容被视为全局可见的。
导出声明
任何声明(比如变量,函数,类,类型别名或接口)都能够通过添加export关键字来导出。
export interface StringValidator{
isAcceptable(s:string):boolean;
}
export const numberRegexp=/^[0-9]+$/;
export class ZipCodeValidator implements StringValidator{
isAcceptable(s: string) {
return s.length===5 && numberRegexp.test(s);
}
}
导出语句 改写 as??????????????????
class ZipCodeValidator1 implements StringValidator{
isAcceptable(s: string) {
return s.length===5 && numberRegexp.test(s);
}
}
export {ZipCodeValidator1};
// as关键字用于修改变量名,语法为“export {新变量名 as 旧变量名}”。
export {ZipCodeValidator as mainValidator};
重新导出
方法1、
export class ParseIntBasedZipCodeValidator{
isAcceptable(s:string){
return s.length===5 && parseInt(s).toString()===s;
}
}
//导出原先的验证器但做了重命名
export {ZipCodeValidator as RegExpBasedZipCodeValidator} from "./ZipCodeValidator"; //文件名
方法2、:export * from "module"
export*from "./StringValidator";
export*from "./LettersOnlyValidator";
export*from "./ZipCodeValidator";
导入
import {ZipCodeValidator} from "./ZipCodeValidator";
let myValidator=new ZipCodeValidator();
可以重命名导入部分
import {ZipCodeValidator as ZCV} from "./ZipCodeValidator";
let myValidator=new ZCV();
默认导出(default导出)
每个模块都可以有一个default导出,一个模块只能够有一个default导出,
类和函数声明可以默认导出
export defult class ZipCodeValidator{
static numberRegexp=/^[0-9]+$/;
isAcceptable(s:string){
return s.length===5 && ZipCodeValidator.numberRegexp.test(s);
}
}
import validator from "./ZipCodeValidator";
let myValidator=new validator();
导出值也可以是一个值
export defult "123";
import num from "./OneTwoThree";
console.log(num); //"123"
export = 和 import = require()
为了支持CommonJS和AMD的exports, TypeScript提供了export =语法。
export =语法定义一个模块的导出对象。 这里的对象一词指的是类,接口,命名空间,函数或枚举。
若使用export =导出一个模块,则必须使用TypeScript的特定语法import module = require("module")来导入此模块。
let numberRegexp=/^[0-9]+$/;
class ZipCodeValidator{
isAcceptable(s:string){
return s.length===5 && numberRegexp.test(s);
}
}
export = ZipCodeValidator;
//另一个文件
import zip=require("./ZipCodeValidator");
let strings=["Hello","98052","101"];
let validator=new zip();
string.forEach(s=>{
console.log("${s}"-${validator.isAcceptable(s)?"matches":"does not match"});
});
命名空间(namespace)??????????????
“内部模块”现在称做“命名空间”。 “外部模块”现在则简称为“模块”,这是为了与 ECMAScript 2015里的术语保持一致,(也就是说 module X { 相当于现在推荐的写法 namespace X {)。任何使用 module关键字来声明一个内部模块的地方都应该使用namespace关键字来替换。
命名空间中的所有内容都局限于该命名空间中,在命名空间之外不能直接调用。
我们把验证器包裹到一个命名空间内,而不是把它们放在全局命名空间下。
因为我们想让这些接口和类在命名空间之外也是可访问的,所以需要使用 export。 相反的,变量 lettersRegexp和numberRegexp是实现的细节,不需要导出,因此它们在命名空间外是不能访问的。 在文件末尾的测试代码里,由于是在命名空间之外访问,因此需要限定类型的名称,比如 Validation.LettersOnlyValidator。
namespace Validation{
export interface StringValidator{
isAcceptable(s:string):boolean;
}
const lettersRegexp=/^[A-Za-z]+$/;
const numberRegexp=/^[0-9]+$/;
export class LetterOnlyValidator implements StringValidator{
isAcceptable(s: string) {
return lettersRegexp.test(s);
}
}
export class ZipCodeValidator implements StringValidator{
isAcceptable(s: string){
return s.length===5&&numberRegexp.test(s);
}
}
}
let strings=["Hello","98052","101"];
let validators: { [s: string]: Validation.StringValidator; } = {};
validators["ZIP code"] = new Validation.ZipCodeValidator();
validators["Letters only"] = new Validation.LettersOnlyValidator();
for (let s of strings) {
for (let name in validators) {
console.log("${ s }" - ${ validators[name].isAcceptable(s) ? "matches" : "does not match" } ${ name });
}
}
分离到多文件
在不同文件里的同一个命名空间的文件,用这个引用标签调用(ts里)
///
当涉及到多文件时,我们必须确保所有编译后的代码都被加载了。 我们有两种方式。(html里)
1、tsc --outFile sample.js Test.ts 把所有的输入文件编译为一个输出文件
2、
命名空间和模块
1、使用import引用模块文件。
2、模块里不要使用命名空间。
.d.ts文件?????????????
在.d.ts文件中声明的变量或者模块,在其他文件中不需要使用import导入,可以直接使用。
.d.ts文件中我们常常可以看到declare, declare左右就是告诉TS编译器你担保这些变量和模块存在,并声明了相应类型,编译的时候不需要提示错误。
date-fns日期工具的使用方法
import { isToday, format } from 'date-fns';
1、differenceInDays(): 获得两个时间相差几天,
disabledDate = (current: Date): boolean => {
return differenceInCalendarDays(current, this.today) > 0 || differenceInCalendarDays(current, new Date('2022')) < 0;
};
2、isToday():判断所传入日期是否为今天