typescript基本使用笔记
安装typescript
npm install -g typescript
全局安装ts
tsc *.ts
编译ts文件编译成js文件,如果ts有语法错误,则会编译报错,但是仍然会创建编译好的js文件并且编译执行
基础类型
定义变量或者参数的时候通过 :
号指定类型
-
boolean 布尔型
-
number 数字型:包括各种进制的数值型,浮点型
-
string 字符串类型:可以使用模板字符串
-
number[]/Array
数组类型:写法有两种一种是number后面加 []
,一种是通过数组Array 泛型
-
tuple :一个已知元素长度和类型的数组,且类型不能重复,
属于联合类型
-
enum 枚举类型:使用枚举类型可以为一组数值赋予友好的名字,一种类似数组的引用类型形式,可以通过下标访问和赋值,也可以指定下标
-
any :任意类型,不会进行类型检查,任意类型都可以通过,可以组和,比如
any[]
表示任意元素类型的数组 -
void : 空类型,通常用来表示无返回值,
只能够赋值为:undefined和null
-
null和undefined :默认是所有类型的子集,意思是所有其他类型都可以赋值成null和undefined类型
-
never :不应该运行到此处的类型,
-
object :非原始类型,除了
string,number,boolean,null,undefined,symbol
这几个js的基本类型 类型断言(类型转换):语法为 let someValue :any = 'Word' 可以强行将右边转为左边 ;另一个方法是'as'语法,let strLength: number = (someValue as string).length;
变量声明
-
let和var的区别(略)
-
解构 --快速的变量赋值
//---------------数组解构---------------------
// 数组解构
let input = [1, 2];
let [first, second] = input;
console.log(first); // outputs 1
console.log(second); // outputs 2
//剩余变量的数组解构
let [first, ...rest] = [1, 2, 3, 4];
console.log(first); // outputs 1
console.log(rest); // outputs [ 2, 3, 4 ]
//对应下标的数组解构
let [, second, , fourth] = [1, 2, 3, 4];
//------------------对象解构---------------
let o = {
a: "foo",
b: 12,
c: "bar"
};
let { a, b } = o;
//快速的将o对应的键值赋给a,b
let { a, ...passthrough } = o;
let total = passthrough.b + passthrough.c.length;
//剩余变量的对象解构
let { a: newName1, b: newName2 } = o;
//变量重命名,此处相当于{a,b}=0 newName1 = a,newName2 = b;
//此处的:相当于赋值符号
//为什么这里的:不是类型声明符号?
//因为:解构时如果需要类型声明需要完整的写类型模式
//例如:let {a, b}: {a: string, b: number} = o;
function keepWholeObject(wholeObject: { a: string, b?: number }) {
let { a, b = 1001 } = wholeObject;
//解构时的默认值,如果不存在b这个键值时,b=1001
}
//--------------函数声明-----------------------
type C = { a: string, b?: number }
function f({ a, b }: C): void {
// ...
}
//将解构元素当作参数传递
function f({ a="", b=0 } = {}): void {
// ...
}
f();
//解构传参带默认值
function f({ a, b = 0 } = { a: "" }): void {
// ...
}
f({ a: "yes" }); // ok, default b = 0
f(); // ok, default to {a: ""}, which then defaults b = 0
f({}); // error, 'a' is required if you supply an argument
//解构+默认赋值,默认传入{a:""}如果啥也不传,默认参数为{a:''},那么a='',b=0
-
展开 --与解构相反将数组展开或者将对象展开
//所有的展开都是浅拷贝!!
//将数组展开并且插入新数组
let first = [1, 2];
let second = [3, 4];
let bothPlus = [0, ...first, ...second, 5];
//将对象展开
let defaults = { food: "spicy", price: "$$", ambiance: "noisy" };
let search = { ...defaults, food: "rich" };
//对象展开会丢失对象方法
class C {
p = 12;
m() {
}
}
let c = new C();
let clone = { ...c };
clone.p; // ok
clone.m(); // error!
接口
接口的作用就是为这些类型命名和代码进行绑定,接口一般用来做函数参数的预定义
-
关键字 interface
interface LabelledValue {
//定义一个接口
label: string;
//接口中定义了label这个字段必须是字符串类型
}
function printLabel(labelledObj: LabelledValue) {
//参数labelledObj 套用这个接口,所以参数必须有label字段并且为string类型
console.log(labelledObj.label);
}
let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);
-
可选参数接口
interface SquareConfig {
color?: string; //只是在类型声明符前面增加了一个问号
width?: number;
}
-
只读属性
只能在对象刚创建的时候对其值进行修改,可以在属性名前面增加
readonly
来指定只读属性 -
额外的属性检查
interface SquareConfig {
color?: string;
width?: number;
[propName: string]: any;
//使用propName内置属性获取接口的其他参数传值,并且对其进行单独的检查
}
-
函数类型 接口也能用来描述函数类型
interface SearchFunc {
(source: string, subString: string): boolean;
//定义了一个函数接口,参数为source和substring类型为string类型,返回值为boolean类型
}
//以下两种调用方式都符合逻辑
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
let result = source.search(subString);
return result > -1;
}
let mySearch: SearchFunc;
mySearch = function(src: string, sub: string): boolean {
let result = src.search(sub);
return result > -1;
}
-
可索引的类型 可以自定义接口用来限定可索引类型的类型解构
//基础的引用类型接口
interface StringArray {
[index: number]: string;
//定义一个索引类型的接口:
//":"左边表示索引的类型定义,右边表示值的类型定义
//所以上面的意思是定义了一个索引类型的接口,index必须是number类型,值必须是string类型
//嵌套设计
interface NumberDictionary {
[index: string]: number;
//定义了该索引类型的index是string类型,值是number类型
length: number; // 可以,length是number类型
//legth字段定义成number类型,length也属于该索引类型的index,其值也要是number类型
name: string // 错误,`name`的类型与索引类型返回值的类型不匹配
//同理,name也是index,该值也必须是number类型
}
}
let myArray: StringArray;
myArray = ["Bob", "Fred"];
let myStr: string = myArray[0];
//只读索引的接口设计
interface ReadonlyStringArray {
readonly [index: number]: string;
//设定index的类型为只读类型,值为string类型
}
let myArray: ReadonlyStringArray = ["Alice", "Bob"];
//由于设置了index的只读类型,所以无法进行修改
myArray[2] = "Mallory"; // error!
-
类类型 与C#或Java里接口的基本作用一样,TypeScript也能够用它来明确的强制一个类去符合某种契约。
interface ClockInterface {
currentTime: Date;
//定义了一个类型型的接口,其currentTime属性必须是一个Date类型
}
class Clock implements ClockInterface {
currentTime: Date;
constructor(h: number, m: number) { }
}
//类类型使用方法如下
interface ClockInterface {
currentTime: Date;
setTime(d: Date);
}
class Clock implements ClockInterface {
//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) { }
//constructor构造函数里面的参数为类的静态属性所以不会适用上面那个接口的检测方法
}
//--------------------复杂的类类型例子--------------------------------------
interface ClockConstructor {
new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {
tick();
}
function createClock(ctor: ClockConstructor, hour: number, minute: number):
//声明一个函数
//函数的参数接口定义是 ctor的接口是ClockConstructor,hour是number类型,minute是number
//ClockConstructor又是一个函数接口,表示构造函数参数hour和minute的类型都是number,且必须具有属性ClockInterface接口,也就是必须有这个tick属性或者方法
//通过这样嵌套,达到对构造函数静态参数的接口定义
ClockInterface {
//函数的返回值是ClockInterface这个接口定义的,必须有tick这个属性或者方法
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 {
//关键字extend Square继承自Shape
sideLength: number;
}
let 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.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;
-
混合类型 一个接口可以同时拥有多种类型接口的特性,实现该接口的多类型
interface Counter {
//定义一个接口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;
-
接口继承类 当一个接口继承一个类,会继承其类的成员,但是不包括其实现,
class Control {
private state: any;
}
interface SelectableControl extends Control {
//该接口继承自类Control,所以也会继承其属性,包括私有属性
//所以再次使用该接口的时候,会继承该私有属性的定义
select(): void;
}
class Button extends Control implements SelectableControl {
select() { }
}
class TextBox extends Control {
select() { }
}
// 错误:“Image”类型缺少“state”属性。
class Image implements SelectableControl {
select() { }
}
class Location {
}
//在上面的例子里,SelectableControl包含了Control的所有成员,包括私有成员state。 因为 state是私有成员,所以只能够是Control的子类们才能实现SelectableControl接口。 因为只有 Control的子类才能够拥有一个声明于Control的私有成员state,这对私有成员的兼容性是必需的。
//在Control类内部,是允许通过SelectableControl的实例来访问私有成员state的。 实际上, SelectableControl接口和拥有select方法的Control类是一样的。 Button和TextBox类是SelectableControl的子类(因为它们都继承自Control并有select方法),但Image和Location类并不是这样的。