文档章节

TypeScript学习笔记

fzyz_sb
 fzyz_sb
发布于 2017/08/28 20:25
字数 1822
阅读 169
收藏 0

基础类型

以冒号开头后跟类型名称.

let isDone: boolean = false;
let num: number = 6;
let color: string = "blue";
let list: number[] = [1, 2, 3];
let list2: Array<number> = [1, 2, 3];

集合是特殊的数组类型, 它允许不同类型的元素存在于同一个数组中:

let x: [string, number]
x = ["hello", 10]
x[3] = "world"
// [ 'hello', 10, , 'world' ]
console.log(x)

枚举类型:

enum Color {Red, Green, Blue}
let c: Color = Color.Green
// 1
console.log(c)

通用类型any:

let notSure: any = 4
notSure = 'hello'

let list: any[] = [1, true, 'free']
list[1] = 100

void: 在声明函数则代表无返回值; 声明变量则代表只能赋值undefined, null

function warnUser(): void {
    //
}

let unusable: void = undefined;

null和undefined: 一般很少使用, 直接用any即可. 如果非要声明变量为undefined, null, 也可直接使用void:

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

类型转换:

let someValue: any = 'this is a string'
let strLength: number = (<string>someValue).length
let strLength1: number = (someValue as string).length

 

变量声明

var不推荐使用, 因为ES5中没有块级作用域:

// 10 10 10 10 10 10 10 10 10 10
for (var i = 0; i < 10; i++) {
    setTimeout(() => console.log(i), 100 * i)
}

一般遇到这种情况, 只能修改成如下代码:

// 0 1 2 3 4 5 6 7 8 9
for (var i = 0; i < 10; i++) {
    ((i) => {
        setTimeout(() => console.log(i), 100 * i)
    })(i)
}

let具有块级作用域, 所以用let来替换var.

let语法可用于数组/对象的解析:

let [first, second] = [1, 2]
// 1 2
console.log(first, second)
let [first1, ...rest] = [1, 2, 3, 4]
// 1 [2, 3, 4]
console.log(first1, rest)
let o = {
    a: 'foo',
    b: 12,
    c: 'bar'
}
let {a, b} = o
// foo 12
console.log(a, b)
let {c, ...passthrough} = o
// bar {a: 'foo', b: 12}
console.log(c, passthrough)

也可以指定别名:

let {a: newName1, b: newName2} = o
// equal to
let newName1 = o.a
let newName2 = o.b

也可以指定默认值:

let {a, b = 1001} = o

const专门用于定义常量.

ES6中新引入的"..."用于解构数组或变量:

let first: number[] = [1, 2]
let second: number[] = [3, 4]
let both = [0, ...first, ...second, 5]
// [0, 1, 2, 3, 4, 5]
console.log(both)

let defaults = {a: 1, b: 2}
let search = {...defaults, c: 3}
// { a: 1, b: 2, c: 3 }
console.log(search)

 

接口

编写一个函数, 指定参数类型, 之前可以这么写:

function func(obj: {label: string}) {
    console.log(obj.label)
}

let obj = {size: 10, label: 'object'}
func(obj)

而使用接口, 代码可修改如下:

interface Obj {
    label: string
}
function func(obj: Obj) {
    console.log(obj.label)
}

let obj = {size: 10, label: 'object'}
func(obj)

可选属性"?"

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'})
console.log(mySquare)

这里"color?"表明color属性为可选, 而{color: string; area: number}表明函数返回值的类型.

只读属性readonly

interface Point {
    readonly x: number,
    readonly y: number,
}

let p1: Point = {x: 10, y: 20}
// error
p1.x = 5

使用ReadonlyArray<T>为只读数组:

let a: number[] = [1, 2, 3, 4]
let ro: ReadonlyArray<number> = a
// error
ro[0] = 12
// error
a = ro

可使用as将只读数组赋值给一般数组:

a = ro as number[]

属性检查

针对上例函数中, 我们调用:

let mySquare = createSquare({colour: 'red', width: 100})

这里TS会直接报错, 因为它认定需要传入的参数为color/width, 没有colour属性.

假定我们程序里要求允许有其它的属性, 则需要修改interface:

interface SquareConfig {
    color?: string,
    width?: number,
    [propName: string]: any,
}

函数类型

我们可定义函数的参数和返回值:

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

let mySearch: SearchFunc
mySearch = function(src: string, sub: string): boolean {
    let result = src.search(sub)
    return result > -1
}

let search: SearchFunc
search = function(src, sub) {
    let result = src.search(sub)
    return result > -1
}

这一般适用于大量参数相同的函数的设定.

索引类型

数组的索引, 默认为整数, 但实际上会被转换为字符串. 我们可设定索引类型, 并可设定为只读:

interface StringArray {
    readonly [index: number]: string
}

let myArray: StringArray
myArray = ['Alice', 'Bob']

let myStr: string = myArray[0]
console.log(myStr)
// error
// myStr[2] = 'Mallory'

class类型

我们可以为class定义一个接口:

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) {}
}

如果我们为构造函数实现check:

interface ClockInterface {
    new (hour: number, minute: number);
}

class Clock implements ClockInterface {
    currentTime: Date;
    constructor(h: number, m: number) {}
}

这将报错! 因为TS的class中, 检查的是具体实例. 而构造函数属于静态方法, 无法被检查.

如果要检查构造函数, 只能将构造函数当做一个方法来对待:

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 tick");
    }
}

let digital = createClock(DigitalClock, 12, 17);
let analog = createClock(AnalogClock, 7, 32);

接口扩展

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;

console.log(square);

混合类型

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;

 

Classes

我们定义一个简单的class: 属性greeting, 构造函数和方法greet

class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }
    greet() {
        return `Hello, ${this.greeting}`;
    }
}

let greeter = new Greeter("world");
console.log(greeter.greet());

继承

使用extends关键字实现继承操作:

class Animal {
    name: string;
    constructor(theName: string) { this.name = theName; }
    move(distanceInMeters: number = 0) {
        console.log(`${this.name} moved ${distanceInMeters}m.`);
    }
}

class Snake extends Animal {
    constructor(name: string) { super(name); }
    move(distanceInMeters = 5) {
        console.log(`Slithering...`);
        super.move(distanceInMeters);
    }
}

class Horse extends Animal {
    constructor(name: string) { super(name); }
    move(distanceInMeters = 45) {
        console.log(`Galloping...`);
        super.move(distanceInMeters);
    }
}

let sam = new Snake(`Sammy the Python`);
let tom: Animal = new Horse(`Tommy the Palomino`);

sam.move();
tom.move(34);

public, private和protected

默认情况下, class的属性/构造函数/方法, 均为public.

private的属性/方法, 只能在本class内部调用. 在外部或者继承中, 无法调用private声明的属性和方法.

class Animal {
    private name: string;
    constructor(theName: string) { this.name = theName; }
}

// error
new Animal('cat').name;

private变量/方法是无法进行比较的, 所以下例中animal = employee会报错:

class Animal {
    private name: string;
    constructor(theName: string) { this.name = theName; }
}

class Rhino extends Animal {
    constructor() { super("Rhino"); }
}

class Employee {
    private name: string;
    constructor(theName: string) { this.name = theName; }
}

let animal = new Animal('Goat');
let rhino = new Rhino();
let employee = new Employee('Bob');

animal = rhino;
// error
animal = employee;

protected不仅允许class内部调用, 还允许继承clas调用:

class Person {
    protected name: string;
    constructor(name: string) { this.name = name; }
}

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');
console.log(howard.getElevatorPitch());
// error
console.log(howard.name);

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');
// error
dad.name = 'Man with the 3-piece suit';

Static

静态属性与实例无关, 与类有关.

class Grid {
    static origin = {x: 0, y: 0};
    calc(point: {x: number; y: number;}) {
        let xDist = (point.x - Grid.origin.x);
        let yDist = (point.y - Grid.origin.y);
        return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
    }
    constructor(public scale: number) {}
}

let grid1 = new Grid(1.0);
let grid2 = new Grid(5.0);

console.log(grid1.calc({x: 10, y: 10}));
console.log(grid2.calc({x: 10, y: 10}));

Abstract Classes

抽象类不同于接口在于它可实现其方法:

abstract class Animal {
    abstract makeSound(): void;
    move(): void {
        console.log('roaming the earth...');
    }
}

 

函数

一般函数可声明为如下格式:

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

console.log(myAdd(1, 3));

函数中某些参数可选, 或者可指定默认值:

let myAdd = (x: number, y?: number) : number => {
    return x + y;
};

let myAdd1 = (x: number, y = 3) : number => {
    return x + y;
};

剩余参数可使用"..."语法糖:

let func = (x: number, ...rest: any[]) => {
    console.log(rest)
};

func(1, 2, 3, 4);

 

© 著作权归作者所有

共有 人打赏支持
fzyz_sb
粉丝 408
博文 209
码字总数 447144
作品 0
武汉
程序员
TypeScript系列1-简介及版本新特性

简介 随着PC端快速向移动端迁移,移动(体验)优先的概念也越来越响。由于ReactJS目前移动端仅仅支持iOS,因此移动端Web开发框架只能选择: AngularJS/Angula2 + Ionic框架 + Cordova。想要学...

一配
2015/08/15
0
0
Typescript Handbook 精简版之基础类型

简介 Typescript支持与Javascript几乎一样的数据类型:布尔值、数字、字符串,结构体等,此外Typescript还提供了很实用的枚举类型。 Boolean(布尔值) Number(数字) 和Javascript一样,T...

er3456qi
08/27
0
0
TypeScript系列 - 什么是TypeScript

看了很多关于TypeScript的文章,总体说来没有很好的,一个系统的学习TypeScript的资源。 接下来,我将给大家带来TypeScript的系列,让你和我一样,一步一步的学习TypeScript,并且学以致用。...

Hongten
08/02
0
0
TypeScript VS JavaScript 深度对比

TypeScript 和 JavaScript 是目前项目开发中较为流行的两种脚本语言,我们已经熟知 TypeScript 是 JavaScript 的一个超集,但是 TypeScript 与 JavaScript 之间又有什么样的区别呢?在选择开...

powertoolsteam
06/29
0
0
深入理解 TypeScript

此书是 TypeScript Deep Dive 的中文翻译版,感谢作者 Basarat 的付出。 Why 数据来源:npm 包下载量 正如你所见,TypeScript 发展至今,已经成为大型项目的标配,其提供的静态类型系统,大大...

三毛丶
08/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

给MySQL授权远程访问

putty登录服务器; 登录MySQL: mysql -u root -p 新建远程用户: CREATE USER 'myusername' IDENTIFIED BY 'mypassword'; 授权: grant all on *.* to john@'101.102.103.104' identified by......

sweethome
57分钟前
0
0
在t-io老巢造谣,不过有造谣的就会有反造谣的!

只发当事人的截图,不发表评论,以免有引导嫌疑 PS: 截图是由不同的人发过来的 本人已经不在此微信群 图3:有造谣的,就有反造谣的 图4是2018-09-23的t-io官方群的一个发言小统计,有助于让...

talent-tan
今天
99
0
heartbeat 资源

drbd+apache+heartbeat : http://blog.51cto.com/11838039/1827901 heartbeat双机热备的架设 : http://blog.51cto.com/11838039/1827560 对heaetbeat的深一步认识 : http://blog.51cto.co......

寰宇01
今天
4
0
Spring 转换 model 为 json 时增加属性

缘起 目前的项目中有个需求是在附件对象转换成 json 时增加个 url 属性,以前的方式是在返回附件对象或列表时候做一次统一处理,这次想看看 spring 或者 jackson fasterxml 是否自带类似功能...

郁也风
今天
4
0
10大PHP比特币开源项目

如果你是一个Phper,如果你希望学习区块链,那么本文列出的 10个开源的Php比特币项目,将有助于你了解在自己的应用中 如何加入对比特币的支持。 如果你希望快速掌握使用Php对接比特币钱包的方...

汇智网教程
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部