TypeScipt基础教程

目录

一、基础类型

二、变量声明

三、接口

四、类

五、函数

六、泛型

七、枚举

八、类型推断

九、类型兼容性

十、高级类型

十一、Symbols

十二、迭代器和生成器

十三、模块


一、基础类型

//*************************************
// Boolean
let isDone: boolean = false;
//*************************************
// 数字
let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;
let binaryLiteral: number = 0b1010;
let octalLiteral: number = 0o744;
//*************************************
// 字符串
let sname: string = 'bob';
// 模板字符串
let age: number = 37;
let sentence: string = `Hello,My name is ${sname},age is ${age}`
//*************************************
// 数组
let ilist: number[] = [1,2,3]
let ilist2: Array<number> = [1,2,3]
//*************************************
// 元祖
let x:[string,number];
x = ['hello', 2]
console.log(x[0].substr(1))
// console.log(x[1].substr(1))
//*************************************
// 枚举
enum Color {
    Red = 1,
    Green,
    Blue
}
let c:Color = Color.Blue
// 可以获取colorName的名称
let colorName: string = Color[2]
//*************************************
// Any
let notSure:any = 4
notSure = 'maybe a string instead'
notSure = false
// 使用any可以调用方法,但是使用Object不能调用方法
let notSure2: any = 4
notSure2.toFixed()
// 使用Objcet不能调用方法
// let notSure3: Object = 4
// notSure3.toFixed()
//*************************************
// void
function warnUser() :void{
    console.log('This is mt warning message!')
}
// void可以被赋值成undefined和null
let unusable: void = undefined
//*************************************
// NUll和Undefined
let u: undefined = undefined
let n: null = null
//*************************************
// Never(Never可以赋值给任何类型,但是任何类型不能赋值给never),多用于抛出异常
function error(message:string): never {
    throw new Error(message)
}
//*************************************
// Objcet类型,是排除在基本类型之外的类型
declare function create(o: object | null): void;
create({prop:0})
create(null)
// create(42)
//*************************************
// 类型断言,类似于强制类型转换
let SomeValue: any = 'this is a string'
let stringLength: number = (<string>SomeValue).length
let stringLength2: number = (SomeValue as string).length
 

二、变量声明

//*************************************
// 结构数组
let inputNum: [number,number] = [1,2];
let [first,second] = inputNum;
function f([first,second]:[number,number]) {
    console.log(first);
    console.log(second);
}
f(inputNum);
let [first1,...recond1] = [1,2,3,4];
console.log(first1);
let [first2] = [1,2,3,4];
let [,second3,,forth3] = [1,2,3,4];
console.log(second3);
//*************************************
// 对象结构
let o = {
    a: 'foo',
    b: 12,
    c: 'bar'
};
// let {a,b} = o;
// 获取剩余变量
let {a,...passthrought2} = o;
let total = passthrought2.b + passthrought2.c.length;
// 属性重命名,防止变量重复定义
let {a:newName1,b:newName2} = o;
//*************************************
// 展开,只能够展开数组,不能用于展开对象和类,因为这样会涉及到对象的重写
{
    let first = [1,2]
    let second = [3,4]
    let bothPlus = [0,...first,...second]
}

三、接口

//*************************************
// 接口初探(可以检测接口中是否有label)
function printLabel(labelledObj:{label:string}) {
    console.log(labelledObj.label)
}
let myObj = {size:10,label:'Size 10 Objcet'}
printLabel(myObj)
interface LabelledValue {
    label: string;
}
function printLable2(labelledObj:LabelledValue) {
    console.log(labelledObj.label)
}
printLable2(myObj)
//*************************************
// 可选属性(有些属性可能未定义)
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;
}
//*************************************
// 只读属性
interface Point {
    readonly x: number;
    readonly y: number;
}
let p1: Point = {x:10,y:20}
// p1.x = 5
//*************************************
// 接口的使用
interface MyPoint {
    x: number;
    y: number;
}
​
class Point2 implements MyPoint{
    x: number;
    y: number;
    name: string;
}
​
function LogMyPoint(point: MyPoint) {
    console.log(point.x,point.y)
}
​
var pointer2 = new Point2()
pointer2.x = 2
pointer2.y = 3
pointer2.name = 'zhangsan'
//*************************************
// 使用继承创建的接口是可以的,但是使用接口直接对象是不可以传入多于接口的类型的
LogMyPoint(pointer2)
​
// LogMyPoint({
//     x: 10,
//     y: 10,
//     iy: 10
// })
​
// 简单的方法是通过类型转换
LogMyPoint({
    x: 10,
    y: 10,
    name: 'zhangsan'
} as Point)
// 还可以通过签名
interface SquareConfig2 {
    color?: string;
    width?: number;
    [propName:string]: any
}
//函数类型
// 可索引接口
//*************************************
// 类类型
interface Animal {
    name: string;
    eat():void;
}
​
class Cat implements Animal{
    name: string;
    eat(): void {
        console.log('Cat',name,'is eat')
    }
}
​
class Dog implements Animal{
    name: string;
    eat(): void {
        console.log('Dog',name,'is eat')
    }
}
//*************************************
//实现了简单工厂模式(没有多态的概念,但是却可以通过传递类的本身来模拟多态)
//接口不会对构造函数进行分析,因此任何的类都可以是认为直接转换为这个接口,从而实现不同类的多态
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(public h: number,public m: number) { }
    tick() {
        console.log("beep beep",this.h,this.m);
    }
}
class AnalogClock implements ClockInterface {
    constructor(public h: number,public m: number) { }
    tick() {
        console.log("tick tock",this.h,this.m);
    }
}
​
let digital = createClock(DigitalClock, 12, 17);
let analog = createClock(AnalogClock, 7, 32);
digital.tick()
analog.tick()
//*************************************
// 继承接口(一个空的对象可以直接被转换成对应类型)
interface Shape {
    color: string
}
interface Square extends Shape{
    sideLength: number
}
let square = <Square>{}
square.color = 'blue'
square.sideLength = 10
//*************************************
// 接口可以多继承
interface PenStroke {
    penWidth: number
}
​
interface Square extends Shape,PenStroke{
    slideLength: number
}

四、类

//*************************************
// 可以使用public、protected、private,同C++一样
class Animal{
    protected name: string;
    public constructor(theName:string){
        this.name = theName
    }
}
​
class Rhino extends Animal{
    public constructor() {
        super('Rhino');
    }
​
    printName():void{
        console.log(this.name)
    }
}
//*************************************
// 声明只读类型,只读类型只能在构造函数中被赋值
class Octopus{
    private readonly name:string
    private readonly numberOfLegs: number = 8
    public constructor(theName:string){
        this.name = theName
    }
}
// get、set
//*************************************
// 静态变量
class People{
    static peopleSize = 0
    public constructor(){
        People.peopleSize += 1
    }
    static getPeopleSize(): number{
        return People.peopleSize
    }
}
​
new People()
new People()
console.log(People.getPeopleSize())
//*************************************
// set\get
class Employee{
    private m_fullname:string;
    get fullName():string{
        return this.m_fullname;
    }
​
    set fullName(newName:string){
        this.m_fullname = newName;
    }
}
​
let employ = new Employee();
employ.fullName = "zhangsan";
console.log(employ.fullName)
​
//*************************************
// 抽象类
abstract class abstractAnimal {
    abstract makeSound(): void;
    move(): void{
        console.log('Animal')
    }
}

五、函数

// TypeScript可以根据return语句自动推断返回值类型,因此经常省略它
​
function add(x:number,y:number){
    return x+y;
}
​
// 可选参数和默认参数
function buildName(firstName:string,lastName?:string) {
    if(lastName)
        return firstName + " " + lastName;
    else
        return firstName;
}
​
function buildName2(firstName:string,lastName = "Smith") {
    return firstName + " " + lastName;
}
​
// 可选参数可以不出现在程序的最后,但是如果默认参数出现在前面,必须要指定到所有非可选参数
// 当传入的值为undefine时,默认传入的就是默认参数
function buildName3(firstName = "Will",lastName:string){
    return firstName + " " + lastName;
}
let result = buildName3(undefined,"Adams");
// 剩余参数
function buildName4(firstName:string,...restofName:string[]){
    return firstName + " " + restofName.join(" ");
}
​
// this
// let deck = {
//     suits: ["hearts","spades","slubs","diamonds"],
//     cards: Array(52),
//     createCardPicker(){
//         return ()=>{
//             let pickedCard = Math.floor(Math.random() * 52);
//             let pickedSuit = Math.floor(pickedCard / 13);
//             return {suit: this.suits[pickedSuit], card: pickedCard % 13};
//         }
//     }
// };
// let cardPicker = deck.createCardPicker();
// let pickedCard = cardPicker();
//
// alert("card: " + pickedCard.card + " of " + pickedCard.suit);
​
// 改进
// 以面向对象的思路去改进,所有的Object都是对象,都需要定义一个类去规范接口的具体规范。
interface Card {
    suit: string;
    card: number;
}
​
interface Deck {
    suits: string[];
    cards: number[];
    createCardPicker(this: Deck):()=>Card;
}
​
let deck: Deck = {
    suits: ["hearts", "spades", "clubs", "diamonds"],
    cards: Array(52),
    // 类似于Python,所有的函数都需要传递this指针作为自己的内部成员
    createCardPicker: function(this: Deck) {
        return () => {
            let pickedCard = Math.floor(Math.random() * 52);
            let pickedSuit = Math.floor(pickedCard / 13);
​
            return {suit: this.suits[pickedSuit], card: pickedCard % 13};
        }
    }
};
// 重载
// 重载是JS的特性,重载并不是定义不同的函数,而是通过同一个函数,去判断类型,从而有不同的执行逻辑
// 注意function pickMyCard(x):any并不是函数的重载
let suits = ["hearts","spades","clubs"];
function pickMyCard(x:{suit:string;card:number}[]):number;
function pickMyCard(x:number):{suit:string;card:number;};
function pickMyCard(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 };
    }
}
​

六、泛型

// 使用泛型
// 使用泛型,可以不丢失类的信息
import enumerate = Reflect.enumerate;
​
function identity<T>(arg: T):T{
    return arg;
}
let output = identity<string>("Hello World");
// 也可以不使用类型,而是使用类型推断
let output2 = identity("myString");
​
function loggingIdentity<T>(arg: T[]):T[] {
    console.log(arg.length);
    return arg;
}
​
// 泛型类型
let myIdentitys:<U>(arg:U)=>U = identity;
// 泛型接口
interface GeneraicIdentityFn {
    <T>(arg:T):T;
}
​
let ImyIdentitys:GeneraicIdentityFn = identity;
// 前面一个例子可以看出来,当接口中只有一个函数时,函数本身也可以被转换成接口
// 定义泛型接口时,可以将类型指定在类的本体上
interface GeneraicIdentityFn2<T> {
    (arg:T):T;
}
// 泛型类
class GenericNumber<T>{
    zeroValue:T;
    add:(x:T,y:T)=>T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x,y) {
    return x+y;
};
// 类的静态成员不能使用泛型
// 约束泛型
// 描述某种泛型一定需要包含某种接口
interface Lengthwise {
    length: number;
}
function loggingIdentity2<T extends Lengthwise>(arg: T) {
    console.log(arg.length);
    return arg;
}
​
// 在泛型中使用类类型
// 在工厂函数中使用比较普遍
class BeeKeeper {
    hasMask: boolean;
}
​
class ZooKeeper {
    nametag: string;
}
​
class Animal {
    numLegs: number;
}
​
class Bee extends Animal {
    keeper: BeeKeeper;
}
​
class Lion extends Animal {
    keeper: ZooKeeper;
}
​
function createInstance<A extends Animal>(c: new () => A): A {
    return new c();
}
​
createInstance(Lion).keeper.nametag;  // typechecks!
createInstance(Bee).keeper.hasMask;   // typechecks!
​

七、枚举

enum Direction {
    Up = 1,
    Down,
    Left,
    Right
}
function SetDirection(dir:Direction) {
    if(dir == Direction.Down){
        console.log("Down")
    }
}
// 字符串枚举
// 字符串枚举需要全部被初始化
enum DirectionStr {
    Up = "Up",
    Down = "Down",
    Left = "Left",
    Right = "Right"
}
​
enum E {
    Foo,
    Bar
}
function f(x:E) {
    // TS能够判断不能够让x不等于任何类型
    // if(x!=E.Foo||x!=E.Bar){
    //
    // }
}
​
// 枚举是运行时存在的对象
enum E2 {
    X,Y,Z
}
function f1(obj:{X:number}) {
    return obj.X;
}
f1(E2);
​
// 反向映射
enum Enum {
    A
}
let a = Enum.A;
let nameOfA = Enum[a];//"A"
// 常量枚举,在编译阶段会被删除
const enum Directions {
    Up,
    Down,
    Left,
    Right
}
​
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right]
// 外部枚举
declare enum Enum3 {
    A = 1,
    B,
    C = 2
}
​
​

八、类型推断

// 类型推论
let x = 3;
// 最佳通用类型
let x2 = [0, 1, null];
class Animal{
    name:string
}
class Rhino extends Animal{
    name: 'Rhino'
}
class Elephant extends Animal{
    name: 'Elephant'
}
let zoo:Animal[] = [new Rhino(),new Elephant()];
​
// 上下文类型
window.onmousedown = function(mouseEvent: any) {
    console.log(mouseEvent.button);  //<- Now, no error is given
};
​
function createZoo(): Animal[] {
    return [new Rhino(), new Elephant()];
}

九、类型兼容性

// 类型兼容性:
// 对于接口,只需要对象的类型实现了具体的结构,即使没有显示定义,也是兼容的
interface Named {
    name: string;
}
class Person{
    name:string;
}
let p:Named;
p = new Person();
// 比较两个函数
let x1 = (a:number)=>0;
let y1 = (b:number,s:string)=>0;
y1 = x1;
// x1 = y1;
// 使用比较少的参数可以赋值给比较多的参数,这在JS中是合法的
class TestEvent {
    timestamp: number;
}
class TestMouseEvent extends TestEvent{
    x: number;
    y: number;
}
// 可以通过强制类型转换进行上转型和下转型
function TestEventListener(e: TestEvent) {
    console.log((<TestMouseEvent>e).x);
}

TestEventListener(<TestEvent>{
    timestamp: 123,
    x: 10,
    y: 10
});

// 枚举和数字类型兼容,枚举和枚举不兼容
enum Status{
    Ready,
    Waiting
}
enum Color {
    Red,
    Blue,
    Green
}
let stat = Status.Ready;
// stat = Color.Green;
// 类:只要成员函数相同,类就是可以相互兼容的
class Animal{
    feet: number;
    constructor(name:string,numFeet:number){}
}
class Size{
    feet: number;
    constructor(numFeet:number){}
}
let a:Animal;
let b:Size;
a = b;
b = a;

// 泛型
//只影响内部的类型,因此,如果没有使用到泛型,可以直接赋值
interface Empty<T> {
    data:T;
}
let x: Empty<number>;
let y: Empty<string>;

// x = y;  // OK, because y matches structure of x

十、高级类型
// 高级类型
class Bird {
    fly(){}
    layEggs(){}
}

class Fish {
    swim(){}
    layEggs(){}
}

function getSmallPet(type: string):Fish|Bird {
    if(type === "Fish"){
        return new Fish();
    }else{
        return new Bird();
    }
}

// 交叉类型能够访问成员变量中的所有变量
function getSmallPet2(): Fish & Bird{
    return {
        fly : function (){},
        layEggs : function(){},
        swim : function () {}
    }
}

// 联合类型只能访问成员中的共有变量
let pet = getSmallPet("Fish");
pet.layEggs();
// pet.swim(); ERROR

// 判断联合类型是否具有某个成员
if((<Fish>pet).swim){
    (<Fish>pet).swim();
}

// typeof类型保护
function padLeft(value: string,padding:string|number) {
    if(typeof padding === "number"){
        return Array(padding + 1).join(" ") + value;
    }
    if(typeof padding === "string"){
        return padding + value;
    }
    throw new Error("Expected string or number")
}

let left = padLeft("Hello","Tom");
let right = padLeft("Hello",18);

// instanceof类型保护
interface Padder {
    getPaddingString(): string
}

class SpaceRepeatingPadder implements Padder {
    constructor(private numSpaces: number) { }
    getPaddingString() {
        return Array(this.numSpaces + 1).join(" ");
    }
}

class StringPadder implements Padder {
    constructor(private value: string) { }
    getPaddingString() {
        return this.value;
    }
}

function getRandomPadder() {
    return Math.random() < 0.5 ?
        new SpaceRepeatingPadder(4) :
        new StringPadder("  ");
}

// 类型为SpaceRepeatingPadder | StringPadder
let padder: Padder = getRandomPadder();

if (padder instanceof SpaceRepeatingPadder) {
    padder; // 类型细化为'SpaceRepeatingPadder'
}
if (padder instanceof StringPadder) {
    padder; // 类型细化为'StringPadder'
}

// 类型别名
type Name = string;
type NameResolver = ()=>string;
type NameOrResolver = Name | NameResolver;
// 字符串字面类型
// 字符串字面类型可以作为枚举使用
type Easing = "ease-in"|"ease-out"
function animate(easing:Easing) {
    if(easing === "ease-in"){

    }
    else if(easing === "ease-out"){

    }
}
// 也可以用来区分函数重载
function createElement(tagName:"img");
function createElement(tagName:"input");
function createElement(tagName:"div");
function createElement(tagName:string){
    if(tagName === "img"){

    }
}
createElement("img");
// 数字字面类型(很少使用)
function rollDie(): 1 | 2 | 3 | 4 | 5 | 6 {
    return 1;
}
// 可辨识联合
// 其中kind作为可辨识联合的属性
interface Square {
    kind: "square";
    size: number;
}

interface Rectangle {
    kind: "rectangle";
    width: number;
    height: number;
}
type Shape = Square|Rectangle;
// 可辨识联合可以为代码提供语法自动提示
function area(s:Shape) {
    switch (s.kind) {
        case "square":return s.size*s.size;
        case "rectangle":return s.width*s.height;
    }
}
// 多态的this类型
class BasicCalculator{
    public constructor(protected value:number=0){
    }
    public currentValue():number{
        return this.value;
    }
    public add(operand:number):this{
        this.value += operand;
        return this;
    }
}
// 通过返回this,可以让这个类型得到持续的加工
let v = new BasicCalculator(2).add(3).add(4).currentValue();
// 当新的类继承后,可以使用同样的方法,并且新的对象中this永远是子类的this
class ScientificCalculator extends BasicCalculator{
    public constructor(value=0){
        super(value);
    }
    public sin():this{
        this.value = Math.sin(this.value);
        return this;
    }
}
let v2 = new ScientificCalculator(2).add(2).sin().currentValue();

十一、Symbols

在部分编译器中会报错

十二、迭代器和生成器

let list = [4, 5, 6];
// 其中for...in...获取的是键的集合
for (let i in list) {
    console.log(i); // "0", "1", "2",
}
// for...of...获取的是值的集合
for (let i of list) {
    console.log(i); // "4", "5", "6"
}

十三、模块

// TypeScript中内部模块被称作命名空间
// 导出,任何的声明都可以使用export导出
export interface StringValidator {
    isAcceptable(s:string):boolean;
}
export const numberRegexp = /^[0-9]+$/;
// 对导出的部分重命名
class ZipCodeValidator{

}
// export {ZipCodeValidator}
export {ZipCodeValidator as mainValidator};

// 重新导出
// export {ZipCodeValidator as RegExpBasedZipCodeValidator} from "./ZipCodeValidator";
// export * from "module"

// 导入
// 导入一个模块中的某个导出内容
// import { ZipCodeValidator } from "./ZipCodeValidator";
// let myValidator = new ZipCodeValidator();

// 可以对导入内容重命名
// import { ZipCodeValidator as ZCV } from "./ZipCodeValidator";
// let myValidator = new ZCV();

// 将整个模块导入到一个变量,并通过它来访问模块的导出部分
// import * as validator from "./ZipCodeValidator";
// let myValidator = new validator.ZipCodeValidator();

// 具有副作用的导入模块
// 尽管不推荐这么做,一些模块会设置一些全局状态供其它模块使用。 这些模块可能没有任何的导出或用户根本就不关注它的导出。 使用下面的方法来导入这类模块:
// import "./my-module.js";

// 默认导出
// declare let $:JQuery;
// export default $;

// import $ from "JQuery";
// $("button.continue").html( "Next Step..." );

// 默认导出
// 默认导出后,导入的类为默认导出的重命名
// 可以认为,默认导出的类可以没有类名或者函数名
// export default 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 default "123";
//
// import num from "./OneTwoThree";
// console.log(num); // "123"

// export = 和 import = require()

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值