前端学习日记 (一) --TypeScript基础篇

501 阅读5分钟
  • 摘要:本文是作者(前端小菜鸟一枚)的学习总结,仅用于记录自己的学习理解,故文章内容技术性水平较低,请多包涵,如有错误请多指点,谢谢~

1. JavaScript 和 TypeScript

  • JavaScript:弱类型语言,入手较容易,易学易用,即想即写,较灵活,开发效率较高,但是维护成本高,严谨性较低,没有变量类型,面向对象和抽象性实现起来较为麻烦,较适用于小型项目,一次性项目。

  • TypeScript: JavaScript的超集、扩展,变量具有类型,严谨性较高,能降低开发的错误率,面向对象和抽象性实现较容易,开发效率没有JavaScript快,但代码异常可能性和维护成本比较低,适用于大型项目。

2. TypeScript 基础类型表

  • 基础类型是复杂类型的基础,需要熟练掌握。
类型例子描述
number let a: number = 1任意数字
stringlet a: string = 'a'任意字符串
boolean let a: boolean = true布尔值 true 或 false
字面量let a : 1;
let b : 1 | 2
变量值就是本身, 使用场景较少
anylet a: any = 1;
a = 'hello'
a = true
任意类型,等同于关闭了TS的类型检测,
变量声明不赋值,则默认为any类型,
且any类型的变量可以赋值给任意变量,
建议尽量避免使用 any。
unknownlet a: unkown = 1;
a = 'hello'
a = true
未知类型,类型安全的any ,
但unkown类型的变量不可以赋值
给其他变量
void空值 (undefined || null)
function fn(msg):void {
console.log(msg)
}
常用于函数设置无返回值,无 return
或 return null || undefined
never没有值
function fn():never {
throw new Error()
}
永远无返回值,不能是任何值,
常见于抛错,死循环等操作
object let bar : {name: string, age?: number}
bar = {name: 'b', age: 18}
let foo:{[key: string]: number | string}
foo = { num: 1, say: 'hello'}
let fn: (f: number, g: number) => number
let mix : {name: string} & {age: number} = {name: 'a', age: 18}
任意JS对象,具体对象类型根据
需求设定,使用灵活度较高,需
要多掌握
array let a: number[] = [1, 2, 3]
let b: Array<string> = ['a', 'b']
任意JS数组
tuple let a : [number, string] = [1, 'a']元组,TS新增类型,固定长度的数组
enum enum Gender { man = 1, woman = 0}
let a: {sex: Gender} = { sex: Gender.man }
枚举, TS新增类型,常用于已知值、且值有范围
的的类型,类型定义时属性默认从0开始
undefined
null
两者各自有自己的类型
分别叫做undefinednull,默认
情况下nullundefined是所有
类型的子类型。 就是说你可以把
nullundefined赋值给number类型的变量

3. 面向对象

程序中所有的操作都需要通过对象来完成,程序中一切皆是对象。

1. 类 ( class )

  • ES6新特性,基于类的面向对象的方式 。

  • 定义类

class 类名 {
	属性名: 类型;
	constructor(参数: 类型) {
		this.属性名 = 参数
	}
	方法名() {
		...
	}
}
  • 示例
 abstract class Person {   // abstract 抽象类,无法通过这个类创建实例
     private name: string; 	// private定义私有属性,只能在内部进行修改
     public age: number; 	// public 默认修饰符,公有属性,任意在任何位置访问修改
     constructor(name: string, age: number) {
         this.name = name;
         this.age = age;
     }
     // abstract 抽象方法只能定义在抽象类中,子类必须对抽象方法进行重写,没有方法体
     abstract dosomething() :void; 
     sayHello(): void{
         console.log(`Hello, I am ${this.name}, ${this.age} years old.`)
     }
     setName(name: string): void {
         // 内部控制属性修改更为严谨
         if(name.length < 2) throw new Error()
         this.name = name
	 }
 }

enum Gender { man = 'Man', woman = 'Woman', other}

class Man extends Person {
    readonly sex: Gender; // readonly 只读属性,无法修改 sex 属性值
    // static 静态属性 只有这个类可以访问,这个类创建的实例是无法使用的
    static dosomething() {  
        console.log('Man dosomething')
    };
    constructor(name: string, age: number) {
        super(name, age)
        this.sex = Gender.man
 	}
}

const someone = new Person('jack', 25);   //报错
Man.dosomething(); 	// Man dosomething
const someone = new Man('jack', 25);
someone.name = 'Tom'; 	// 报错,私有属性不可外部修改
someone.dosomething(); 	// 报错
someone.sayHello();   // Hello, I am jack, 25 years old.
someone.setName('Tome'); // 修改成功

2. 接口 ( interface )

  • TypeScript的核心原则之一是对值所具有的结构进行类型检查。 它有时被称做 鸭式辨型法结构性子类型化。 在TypeScript里,接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约。

​ ——官方原文

interface myInterface { //接口都是抽象属性,类可以有具体属性
    name: string;
    sayHello(): void; // 抽象方法
}

type myType = {  // 定义结果等同于 myInterface
    name: string,
    age?: number | string, // ? 符号可以定义该属性为非必要属性, | 符号可以定义联合类型
    sayHello(): void
}

const obj: myInterface = {
    name: 'jack',
    sayHello() {
        console.log('Hello');
    }
}
// implements: 使 MyClass 这个类执行 myInterface 这个接口,对这个类进行一个限制
class MyClass implements myInterface {
    constructor(name: string) {
		this.name = name
    }
    name: string;
    sayHello():void {
        console.log('This is myclass')
    }
}

3. 泛型

  • 泛型常用于在定义函数或类时,如果遇到类型不明确的,就可以使用泛型。
function fn<T>(value: T): T {
    return value;
}
fn(10);  // T就被指定为 number 类型,系统可以自动推断
fn<string>('hello');  // T被指定为 string 类型,手动指定

interface Inter {
    length: number;
}
function fn2<T extends Inter>(a: T): number {
    return a.length;
}
fn2('123');   // 不报错,字符串有 length 属性
fn2({length: 3}); 	// 不报错,对象具有 length 属性
fn2(123);  	// 报错,数字没有 length 属性

class MyClss<T> {
    name: T;
    constructor(name: T) {
        this.name = name;
    }
}
const mc = new MyClass<string>('jack');

4. 函数类型

1. 函数定义类型

// 完整定义函数类型

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

// 以下定义时,编译器自动推断函数类型, myAdd类型会被定义成 (x: number, y: number) => number

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

// 扩展运算符设置剩余参数,并定义为字符串数组
function buildName(firstName: string, ...restOfName: string[]): string {
  return firstName + " " + restOfName.join(" ");
}

let name = buildName("Jack", "Tom", "Lucas");

2. this 和箭头函数

  • this 值在函数被调用的时候才会指定。

  • 由于TypeScript是JavaScript的超集,TypeScript也需要弄清 this 工作机制,下面借用官方示例。

let deck = {
    suits: ["hearts", "spades", "clubs", "diamonds"],
    cards: Array(52),
    createCardPicker: function() {
        // 可以看到createCardPicker是个函数,它也返回了一个函数,此函数在被调用时
        // this 指向了直接调用者,也就是window,而window并没有定义 suits 属性
        //( 在严格模式下, this为 undefined 而不是 window )
        return function() {
            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(); // 运行这个程序,报错了。
// 因为 createCardPicker 返回的函数里的this被设置成了 window 而不是 deck 对象。
// 因为我们只是独立的调用了 cardPicker()。 顶级的非方法式调用会将 this视为window。


// 下面改一下 createCardPicker 返回的函数形式
let deck = {
    ... // 重复内容
    createCardPicker: function() {
        // 此时返回一个箭头函数,this指向了deck对象,箭头函数具体机制查阅ES6的新特性
        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(); // 运行这个程序,没报错。

// 加上类型定义
interface Card {
    suit: string;
    card: number;
}
interface Deck {
    suits: string[];
    cards: number[];
    // 此处 this 当参数指向参数本身,参数也是 Deck 类型
    createCardPicker(this: Deck): () => Card;
}
let deck: Deck = {
    ... // 重复内容
    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};
        }
    }
}

  • 这就是基础篇的总结,当然并不完整也没啥营养,本人只是总结自身觉得比较深刻的知识,过几天继续总结typeScript的进阶篇,thanks~