typescript之旅
1.TypeScript-Basic
2.TypeScript interface
3.Typescript-module(1)
4.TypeScript Modules(2)
5.Typescript tsconfig
6.TypeScript Functions
7.Typescript Class
Interfaces
今天来说说接口,首先说明如果你是java程序员,请一定忘记interface,此处的接口和彼处接口完全不是一个思想。
首先来一个最简单的接口
字面量接口
不使用interface关键字就定义了一个接口
function printLabel(labelledObj: {label: string}) {
console.log(labelledObj.label);
}
var myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);
上面没有interface关键字,哪个是接口呢?
{label: string}
你说这个玩意不是变量labelledObj的类型吗?我知道typescript说白了就是js的类型系统,前面也介绍了如:Boolean,Number,String,Array,Enum,Any,Void
其实接口就是定义了一个对象有哪些属性,并且属性值是什么类型
好了,来个高级点的(interface关键词上场)
interface LabelledValue {
label: string;
}
function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
}
let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);
OK,懂了吗,自定义类型
啊,太棒了,以后再也不用判断某个属性是否un
可选属性
interface SquareConfig {
color?: string;
width?: number;
}
function createSquare(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 = createSquare({color: "black"});
好处:
预定义属性
编译器可以捕获对不存在属性引用的错误
interface SquareConfig {
color?: string;
width?: number;
}
function createSquare(config: SquareConfig): { color: string; area: number } {
let newSquare = {color: "white", area: 100};
if (config.color) {
// Error: Property 'collor' does not exist on type 'SquareConfig'
newSquare.color = config.collor; // Type-checker can catch the mistyped name here
}
if (config.width) {
newSquare.area = config.width * config.width;
}
return newSquare;
}
let mySquare = createSquare({color: "black"});
对于这个错误例子,我们引出了下一节
额外的属性检查
上面的例子也许有人会争辩(js的忠实用户者),js对象是灵活的,你现在搞得跟JAVA一样了!
反对~反对!
是的,typescript对对象字面量会特殊对待(即经过额外属性检查),当将他们赋值给变量或作为函数参数时。
因此你会得到一个错误
// error: 'colour' not expected in type 'SquareConfig'
let mySquare = createSquare({ colour: "red", width: 100 });
解决办法
1.类型断言法(类似于c语言的强制类型转换,告诉编译器,我就要转,别给我报错啊!)
let mySquare = createSquare({ colour: "red", width: 100 } as SquareConfig);
2.钻空子法(我们了解编译器的检查方式了,我绕过去就行了)
let squareOptions = { colour: "red", width: 100 };
let mySquare = createSquare(squareOptions);
函数类型
首先我们要肯定interface使我们定义了各种对象外形。
现在我们把string,number,boolean,object类型都定义了,完工了!
且慢,等等~对于其他语言是够了,但js~~~
你想,js的函数是一等公民,你能忘了它~
当当当当,来了!
interface SearchFunc {
(source: string, subString: string): boolean;
}
demo:
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
let result = source.search(subString);
if (result == -1) {
return false;
}
else {
return true;
}
}
好处:
1.检查参数类型
2.返回值类型检查,上例,如果你返回字符串或数字,就报错了
数组类型
数组可以想象成一种特殊函数,只有一个参数(index)的函数
interface StringArray {
[index: number]: string;
}
let myArray: StringArray;
myArray = ["Bob", "Fred"];
OK,没有问题吗?index只能是number类型吗?我还知道一种叫关联数组的玩意(index是string)
我们经常这样用obj.property和obj[“property”]
目前支持两种index类型:number,string
可以同时使用两种索引类型
限制:数字索引返回值的类型必须是字符串索引返回值的类型的子类型
demo
interface NumberDictionary {
[index: string]: number;
length: number; // 可以,length是number类型
name: string // 错误,`name`的类型不是索引类型的子类型
}
类类型(肩负重任的inteface关键字)
与C#或Java里接口的基本作用一样,TypeScript也能够用它来明确的强制一个类去符合某种契约。
interface ClockInterface {
currentTime: Date;
}
class Clock implements ClockInterface {
currentTime: Date;
constructor(h: number, m: number) { }
}
interface ClockInterface {
currentTime: Date;
setTime(d: Date);
}
class Clock implements ClockInterface {
currentTime: Date;
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number) { }
}
接口描述了类的公共部分,而不是公共和私有两部分。 它不会帮你检查类是否具有某些私有成员。
类静态部分与实例部分的区别
这部分比较冷~
类是具有两个类型的:静态部分的类型和实例的类型
构造函数是静态部分,而一个类去实现一个带有构造器签名的接口时会报错
interface ClockConstructor {
new (hour: number, minute: number);
}
class Clock implements ClockConstructor {
currentTime: Date;
constructor(h: number, m: number) { }
}
那如何才能使用接口对构造器类型检查呢
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);
拓展接口
和类一样,接口也可以相互扩展。 这让我们能够从一个接口里复制成员到另一个接口里,可以更灵活地将接口分割到可重用的模块里
interface Shape {
color: string;
}
interface Square extends Shape {
sideLength: number;
}
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
多继承
interface Shape {
color: string;
}
interface PenStroke {
penWidth: number;
}
interface Square extends Shape, PenStroke {
sideLength: number;
}
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;
混合类型
还是JS的特殊语法
function demo(){
...
}
demo.attr1 = '1';
demo.fun = function(){
...
}
这是什么情况,函数类型,对象类型,额,混合类型
interface Counter {
(start: number): string;
interval: number;
reset(): void;
}
function getCounter(): Counter {
let counter = <Counter>function (start: number) { };
counter.interval = 123;
counter.reset = function () { };
return counter;
}
let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;
接口继承类
还不是很明白