TypeScript基础用法(未完成)

一、基础类型

1.void

使用void表示没有任何返回值的函数

function alertName(): void {
    
    
    alert('My name is Tom');
}

2.null和underfinde

undefined 类型的变量只能被赋值为 undefined,null 类型的变量只能被赋值为 null

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

3.void的区别,null和underfinde

与 void 的区别是,undefined 和 null 是所有类型的子类型。也就是说 undefined 类型的变量,可以赋值给 number 类型的变量:

let u: undefined;
let num: number = u;
let num2:number = undefined;
//编译合法 undefined是number的子类型

let unm2: void;
let num3: number = unm2;
//=> 不合法 (void不是number的子类型)

4.any

允许赋值为任意类型

let anyType:any = 'seven';
anyType = 7;

//在任意值上访问任何属性和方法都是允许的,即不做类型检查
let anyType:any = 'seven';

下面代码 => 允许编译,但是js执行会报错
console.log(anyType.name().age) 

//变量如果在声明的时候,未指定其类型, 也没有赋值, 那么它会被推断(类型推论)为任意值类型而完全不被类型检查

let something; 
// 等价于 let something: any;
something = 'seven';
something = 7;

二、数组

相同类型的一组数据,数组类型有多种定义方式

1.类型 + 方括号( type [ ] )

let list: number[] = [1, 2, 3];
//下面写法即会报错
let list: number[] = ['a', 2, 3];

2.数组泛型 Array < type >

let list: Array<number> = [1, 2, 3];

//编译报错,但依然会生成js
let list: Array<number> = [1, 'a', 3];

三、元组

组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同,简单理解为可定义一组不同类型的数据

let arr:[string, number] = ['name', 20];
 console.log(arr[0]); 
// // => 'name' 
//越界元素:当访问超出元祖长度的元素时,它的类型会被限制为元祖中每个类型的联合类型

let arr:[string, number] = ['name', 20];
arr[0] = 'age';
arr[2] = 'string'; // 编译不报错
arr[3] = 40; // 编译不报错
arr[4] = true; // 编译报错

四、枚举

TypeScript 支持 数字 的和基于字符串的枚举。
枚举类型用于取值被限定在一定范围内的场景,如一周只有7天,一年只有4季等。
枚举初始化可以理解为给枚举成员赋值。每个枚举成员都需要带有一个值,

//在未赋值的情况下, 枚举成员会被赋值为从 0 开始, 步长为 1 递增的数字:
enum Weeks {
    
    Mon, Tue, Wed, Thu, Fri, Sat, Sun};

console.log(Weeks['Mon']); // => 0
console.log(Weeks[0]); // => 'Mon'
console.log(Weeks.Tue); // => 1
//手动赋值时, 未赋值的枚举成员会接着上一个枚举项递增(初始化):

enum Weeks {
    
    
    Mon, Tue, Wed, Thu = 2, Fri, Sat = -1.5, Sun
};

console.log(Weeks['Mon']); // => 0
console.log(Weeks['Tue']); // => 1
console.log(Weeks.Wed); // => 2
console.log(Weeks.Thu); // => 2
console.log(Weeks.Fri); // => 3
console.log(Weeks.Sat); // => -1.5
//因为Weeks.Sat = -1.5, Weeks.Sun递增加1, 所以为-0.5
console.log(Weeks.Sun); // => -0.5

//上例中,未手动赋值的 Wed 和手动赋值的 Thu 取值重复了,但是 TypeScript 并不会报错,该种情况可能会引起取值错误,所以使用的时候最好避免出现取值重复的情况
// An highlighted block
var foo = 'bar';

五、never

永远不存在值的类型,一般用于错误处理函数

// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
    
    
    throw new Error(message);
}

六、symbol

symbol成为了一种新的原生类型,就像 number 和 string 一样

// 通过Symbol构造函数创建的,Symbols是不可改变且唯一的。
let sym2 = Symbol("key");
let sym3 = Symbol("key");
sym2 === sym3; // false, symbols是唯一的

七、object

object表示非原始类型,也就是除number,string,boolean,symbol,null或undefined之外的类型。

function create(o: object | null): void;

create({
    
     prop: 0 }); // OK
create(null); // OK

create(42); // Error
create("string"); // Error
create(false); // Error
create(undefined); // Error

八、内置对象

object表示非原始类型,也就是除number,string,boolean,symbol,null或undefined之外的类型。

// ECMAScript 的内置对象
// Boolean、Error、Date、RegExp 等。更多的内置对象,可以查看 MDN 的文档。

let b: Boolean = new Boolean(1);
let e: Error = new Error('Error occurred');
let d: Date = new Date();
let r: RegExp = /[a-z]/;
// DOM 和 BOM 的内置对象
// Document、HTMLElement、Event、NodeList 等。

let body: HTMLElement = document.body;
let allDiv: NodeList = document.querySelectorAll('div');
document.addEventListener('click', function(e: MouseEvent) {
    
    
  // Do something
});

九、类型推理

object表示非原始类型,也就是除number,string,boolean,symbol,null或undefined之外的类型。

//变量申明如果没有明确的指定类型,那么 TypeScript 会依照类型推论的规则推断出一个类型

let string = 'seven';
 等价于 let string: string = 'seven';
 string = 4;
//变量声明但是未赋值,会推论为 any

 let x;
 x = 1;
 x = 'aaa'

十、联合类型

// 表示取值可以为多种类型中的一种,使用 | 分隔每个类型

let stringOrNumber:string | number;
 stringOrNumber = 'seven';
//当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候, 我们只能访问此联合类型的所有类型里共有的属性或方法

function getString(something: string | number): string {
    
    
  // toString 是 string类型 和 number类型 的共有属性
  return something.toString();
}

function getLength(something: string | number): number {
    
    
  return something.length;
  // => 编译报错: length 不是 string类型 和 number类型 的共有属性, 所以报错
}

十一、类型断言

=========================================================1,<类型>值 ( 尖括号语法 )
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
=========================================================2,值 as 类型 ( as 语法 )
// 当使用 tsx 时,只有 as语法断言是被允许的
let someValue: any = "this is a string";

let strLength: number = (someValue as string).length;
// 在上述 联合类型 的例子中, getLength 方法会编译报错,此时我们可以使用类型断言,将 something 断言成 string 就不会报错了:

function getLength(something: string | number): number {
    
    
    if ((<string>something).length) {
    
    
        // 将 something 断言为 string类型
        return (<string>something).length;
    } else {
    
    
        return something.toString().length;
    }
}

十二、类型别名

类型别名用来给一个类型起个新名字,多用于联合类型

type Name = string;
type GetName = () => string;
type NameOrGetter = Name | GetName;
function getName(n: NameOrGetter): Name {
    
    
    if (typeof n === 'string') {
    
    
        return n;
    } else {
    
    
        return n();
    }
}

type 声明可以定义联合类型,基本类型等多种类型,而 interface 只能定义对象类型

十三、字符串字面量类型

字符串字面量类型用来约束取值只能是某几个字符串中的一个

type EventNames = 'click' | 'scroll' | 'mousemove';
function handleEvent(ele: Element, event: EventNames) {
    
    
    // do something
}

handleEvent(document.getElementById('hello'), 'scroll');  // 没问题
handleEvent(document.getElementById('world'), 'dbclick'); // 报错,event 不能为 'dbclick'

十四、接口 Interfaces

/1、接口(Interfaces)是一个很重要的概念,可以理解为一种规范或者约束
2、用来描述 对象(object) 的形状 或者对 类(class) 的行为 进行抽象。

//使用 interface 定义接口, 接口名称一般首字母大写,定义接口的时候,只定义声明即可,不包含具体内容:

=========================================================定义一个接口 Person
interface Person {
    
    
  name: string;
  age: number;
}

\\实现接口的时候,要实现里面的内容,定义的变量比接口少了或多了属性都是不允许的:
let tom: Person = {
    
    
  name: 'tom'
}
//=> 编译报错,少了age属性

//定义一个变量,它的类型是 Person
let tom: Person = {
    
    
  name: 'Tom',
  age: 25
};
=========================================================可选属性
//使用 ? 代表可选属性, 即该属性可以不存在, 但不允许添加未定义的属性

interface Person {
    
    
name: string;
age?: number;
}
let tom: Person = {
    
    
name: 'tom'
}
//age是可选属性
//定义了任意属性后可以添加未定义的属性,并可以指定属性值的类型

interface Person03 {
    
    
    name: string;
    age?: number;
    [propName: string]: any;
}
let tom04: Person03 = {
    
    
    name: 'Tom',
    age: 25,
    gender: 'male'
};
\\//=========================================================只读属性 readonly

interface Person {
    
    
    readonly id: number;
    name: string;
    age?: number;
    [propName: string]: any;
}
// 只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候
let person: Person = {
    
    
    id: 100,
    name: 'tom',
}
person05.id = 90;
// => 编译报错:id为只读, 不可修改

let person2: Person = {
    
    
    name: 'welson',
    age: 2
}
// => 编译报错:给对象 person2 赋值,未定义只读属性id
person2.id = 1;
  // => 编译报错:id为只读, 不可修改

十五、函数

//========================================================= 函数声明
function sum(x: number, y: number): number {
    
    
    return x + y;
}
// 输入多余的(或者少于要求的)参数,是不被允许的
sum(1, 2, 3);
// 编译报错:多了1个参数
//=========================================================匿名函数(函数表达式)
let mySum = function (x: number, y: number): number {
    
    
    return x + y;
};
//上面的代码只对等号右侧的匿名函数进行了类型定义,
//而等号左边的 mySum, 是通过赋值操作进行类型推论而推断出来的。

//如果需要我们手动给 mySum 添加类型,则应该是这样:

let mySum: (x: number, y: number) => number = function (x: number, y: number): number {
    
    
    return x + y;
};
//注意不要混淆了 TypeScript 中的 => 和 ES6 中的 =>

//=========================================================用接口定义函数的形状
interface FuncAdd {
    
    
    (value: number, increment: number): number
}

let add: FuncAdd;
add = function (value: number, increment: number): number {
    
    
    return value + increment;
}
//函数的参数名不需要与接口里定义的名字相匹配

let add2: FuncAdd;
add2 = function (a: number, b: number) {
    
    
    return a + b;
}

//函数的参数顺序需要与接口里定义的参数顺序相匹配
interface FuncAdd {
    
    
    (value: string, increment: number): number
}
let add2: FuncAdd;

add2 = function (a: number, b: string) {
    
    
    return a + b;
}
//报错,因为value对应的a,必须是一个string
//========================================================= 可选参数
//可选参数必须接在必需参数后面,换句话说,可选参数后面不允许再出现必须参数了
//========编译成功
function addNum(a: number, b: number, c? :number): number {
    
    
    if(c) {
    
    
        return a + b + c;
    } else {
    
    
        return a + b;
    }
}
console.log(addNum(1, 2));

//=========编译错误 ,因为必需参数在可选参数后
function addNum(a: number,  c? :number, b: number): number {
    
    
    if(c) {
    
    
        return a + b + c;
    } else {
    
    
        return a + b;
    }
}
console.log(addNum(1, 2));
//========================================================== 默认参数
//类似 ES6 中的默认值

function add(a: number = 1, b: number): number {
    
    
    return a + b;
}
console.log(add(undefined, 1));

//==========================================================剩余参数
//类似 Es6 中对象展开

interface AddFunc {
    
    
    (num1: number, ...rest: number[]): number
}
let add: AddFunc;
add = function (a: number, ...rest: number[]): number {
    
    
    let result = a;
    rest.map(v => result += v);
    return result;
}
console.log(add(1, 2, 3, 4));

十六、类

//================================================================== 静态属性和方法
//ES7 提案中,可以使用 static 定义一个静态属性或方法。静态方法不需要实例化,而是直接通过类来调用:

//ts
class Animal {
    
    
    static num = 42;
    static isAnimal(a) {
    
    
        return a instanceof Animal; //obj instanceof Object;//true 实例obj在不在Object构造函数中
    }
}

console.log(Animal.num); // 42
let a = new Animal('Jack');
Animal.isAnimal(a); // true
a.isAnimal(a); // TypeError: a.isAnimal is not a function

//================================================================== 访问修饰符
//public
//公有属性或方法,可以在任何地方被访问到,默认所有的属性和方法都是 public的

//private
//私有属性或方法,不能在声明它的类的外部访问,也不可以在子类中访问

//protected
//受保护的属性或方法,它和 private 类似,区别是它可以在子类中访问

class Person {
    
    
    public name: string;
    private idCard: number;
    protected phone: number;
    constructor(name, idCard, phone) {
    
    
        this.name = name;
        this.idCard = idCard;
        this.phone = phone;
    }
}

let tom = new Person('tom', 420000, 13811110000);
console.log(tom.name) // tom

console.log(tom.idCard)
// error:Property 'idCard' is private and only accessible within class 'Person'.

console.log(tom.phone)
// error:Property 'phone' is protected and only accessible within class 'Person' and its subclasses

class Teacher extends Person {
    
    
    constructor(name, idCard, phone) {
    
    
        super(name, idCard, phone);
        console.log(this.name)
        console.log(this.phone)
        console.log(this.idCard) //报错
        // error:Property 'idCard' is private and only accessible within class 'Person'.
    }
}
let amy = new Teacher('Amy','2002','68888888')
console.log(amy.name)
console.log(amy.phone) //报错
console.log(amy.idCard) //报错

//================================================================多态
//同一个父类的多个子类,可以有不同结果的同名方法:

class Person {
    
    
    eat() {
    
     console.log('eat') }
}
class A extends Person {
    
    
    eat() {
    
     console.log('A eat') }
}
class B extends Person {
    
    
    eat() {
    
     console.log('B eat') }
}
let a = new A();
let b = new B()
a.eat(); // A eat
b.eat(); // B eat
//=============================================================7、抽象类/抽象方法 //abstract
//abstract 用于定义抽象类和其中的抽象方法。

//抽象类是提供给其他类继承的基类(父类),是不允许被实例化
//抽象方法只能包含在抽象类中
//子类继承抽象类,必须实现抽象类中的抽象方法

abstract class Animal {
    
    
    abstract eat(); // 抽象方法
    // 普通方法
    sleep(){
    
    
      console.log('sleep')
    }
}

// let a = new Animal(); // 报错,抽象类不能被实例化

class Cat extends Animal {
    
    
    eat(){
    
     
        // 父类的eat方法必须被实现
      console.log('eat')
    }
}
let cat = new Cat();
cat.sleep()
cat.eat()
cat.sound() // 报错

猜你喜欢

转载自blog.csdn.net/MISS_zhang_0110/article/details/120826240
今日推荐