美文网首页
TypeScript基础

TypeScript基础

作者: 我是小布丁 | 来源:发表于2021-10-24 17:22 被阅读0次

1、静态类型语言 和 动态类型语言

  • 静态类型语言
    在编译阶段确定所有变量的类型
    在编译阶段确定属性偏移量
    用偏移量访问代替属性名访问
    偏移量信息共存

  • 动态类型语言
    在执行阶段确定所有变量的类型
    在程序运行时,动态计算属性偏移量
    需要额外的空间存储属性名
    所有对象的偏移量信息各存一份

静态类型语言 动态类型语言
对类型嫉妒严格 对类型非常宽松
立即发现错误 Bug 可能隐藏数月甚至数年
运行时性能好 运行时性能差
自文档化 可读性差

动态类型语言的支持者认为:

  • 性能是可以改善的,而语言的灵活性更重要(V8引擎)
  • 隐藏的错误可以通过单元测试发现
  • 文档可以通过工具生成

强类型、动态语言:python
弱类型、动态语言:javascript、PHP
强类型、静态语言:Java、c#、Go、C、C++

2、数据类型

ES6的数据类型: undefined、null、Boolean、Number、String、Bigint、Array、Function、Object、Symbol
TS 的数据类型:undefined、null、Boolean、Number、String、Bigint、Array、Function、Object、Symbol、void、any、never、元祖、枚举、高级类型

类型注解作用:相当于强类型语言中的类型声明
语法:(变量/函数):type

1、基础类型

//  元祖
let tuple: [number, string] = [1, '2'];

// 对象,和es6中的object不一样
let obj: object = {x: 3, y: 4};

// symbol
let s1: symbol = Symbol();

// void
let noFun = void 0;

// undefined并不是js中的关键字,所以容易被重置掉,所以建议使用void 0;去生成undefined;
(function(){
    var undefined = 0
})

// never 永远不会返回
let error = () => {
    throw new Error('xxxx');
}
let endless = () => {
    while(true){}
}

2、枚举类型
枚举:一组具有名字的常量集合。

枚举类型:数字枚举、字符串枚举、异构枚举、常量枚举

// 数字枚举
enum Role {
   Weman,
   Man,
}
// 字符串枚举
enum Role {
   Success='1',
   Fail='0',
}
// 异构枚举,容易混淆,不建议使用
enum Answer {
    No,
    YES = 'Yes'
}
// 常量枚举
const enum Month {
    Jan,
    Feb,
    Mar,
}

3、接口
接口定义对象

interface List {
    readonly id: number;
    name: string;
    // 字符串索引签名
    // [key: string]: any;
   // 数字索引签名
   //  [index: number]: string;
    age?: number;
}
interface Names {
    [x: string]: string;
    // [y: number]: number;
    [y: number]: string;
}
// 断言 两种写法
{id: 1, name: 'lili', c:'ssss'} as List
<List>{id: 1, name: 'lili', c:'ssss'}

接口定义函数的方式

// 方式1
function add1(x: number, y: number)=> {
    return x +y;
}

// 方式2
let add2: (x: number, y: number)=> number;
add2 = (x, y)=> x+y;

// 方式3
interface Add {
    (x: number, y: number):number
}

// 方式4 类型别名
type Add = (x: number, y: number) => number;

let add: Add = (x, y)=> x+y;

函数定义参数要求

//  可选参数
function add5(x: number, y?: number) {
    return y ? x + y: x;
}
// 必选参数之后,参数可以不传
function add6(x: number, y=0, z:number, q=1) {
    return x+y+z+q;
}
// 剩余参数
function add7(x: number, ...rest: number[]) {
    return x + rest.reduce((pre, cur)=> pre+cur);
}
// 函数重载,把容易匹配的放前面
function add8(...rest: number[]): number;
function add8(...rest: string[]): string;
function add8(...rest: any[]): any {
    let first = rest[0];
    if (typeof first === 'string') {
        return rest.join(' ');
    }
    if (typeof first === 'number') {
        return rest.reduce((pre, cur)=> pre+cur);
    }
}

4、类
类成员的属性都是实例属性,而不是原型属性。类成员的方式都是原型方法。
类成员的修饰符:public、private、protected、readonly、static
protected受保护的成员只能在类和子类中访问。static可以被继承

class Dog {
    constructor(name: string) {
        this.name = name;
    }
    public name: string;
    run(){ }
    private fun(){ }
    protected pro(){ }
    readonly legs: number = 4;
    static food: string = 'bones';
}
// 继承
class Husky extends Dog{
    constructor(name: string, public color: string){
        super(name);
        this.color = color;
        this.pro();
    }
}

抽象类只能被继承,不能被实例化的类

abstract class Animal {
    eat(){ }
    // 抽象方法,明确子类有其他实现,就没有必要在子类中实现了
    abstract sleep(): void;
}
class Dog extends Animal{
    constructor(public name: string){
        super();
        this.name = name;
    }
    run(){ }
    sleep(): void {
        console.log('dog');
    }
}
// 多态
class Cat extends Animal{
    sleep(): void {
        console.log('cat')
    }
}

链式调用通过返回this实现

// 链式调用
class WorkFlow {
    sleep1(){
        return this;
    }
    sleep2(){
        return this;
    }
}

class MyFlow extends WorkFlow{
    next(){
        return this;
    }
}

let myFlow = new MyFlow();
myFlow.next().sleep1().next().sleep2();

类与接口的关系

// 1、接口之间,是可以相互继承的,实现接口复用
interface Human{
    name: string;
    eat(): void
}
interface Man extends Human{
    run(): void;
}
interface Child{
    cry(): void;
}
interface Boy extends Man, Child{ }

// 2、类之间,是可以相互继承的,实现方法和属性复用
class A {
}
class B extends A{
}

// 3、接口可以通过类来实现,接口只能约束类的公有成员
class Asian implements Human{
    constructor(public name: string){
        this.name = name;
    }
    eat(){

    }
}
// 4、接口可以抽离出类的成员,抽离包括公有、私有、受保护成员
class Auto{
  state = 1;
}
interface AutoInterface extends Auto{
    
}
class Bus implements AutoInterface{
    state = 1;
}

5、泛型
泛型的好处:

  • 函数和类可以轻松的支持多种类型,增强程序的扩展性
  • 不必写多条函数重载,冗余的联合类型声明,增强代码可读性
  • 灵活控制类型之间的约束

泛型函数

// 函数重载
function log(value: string): string;
function log(value: string[]): string[];
function log(value: any): any{
    return value
}
// 联合类型
function log2(value: string | string[]): string | string[]{
    return value;
}  
// 泛型
function log3<T>(value: T): T{
    return value;
}  

泛型接口

// 别名写法
type Log<T=string>  = (value: T)=> T;
// 接口写法
interface Log<T= string> {
    (value: T): T;
}
function log3<T>(value: T): T{
    return value;
} 

let mylog: Log= log3;
let mylog2: Log<number>= log3;
mylog('111');
mylog2(222);

泛型类

class Log<T> {
    run(value: T){
        return value;
    }
}
let log4 = new Log<number>();
log4.run(111);

泛型继承

interface Length{
    length: number;
}
function log6<T extends Length>(value: T): T{
    return value;
}

log6('xxxxx');
log6(['xxxxx']);

3、类型检测机制

类型检测机制指TpyeScript 编译器在做类型检查时,所秉承的一些原则,以及表现出的一些行为。它能辅助开发,提高开发效率。

  • 类型推断
  • 类型兼容性
  • 类型保护:TypeScript 能够在特定的区块中保证变量属于某种确定的类型。可以在此区块中放心的引用此类型的属性,或者调用此类型的方法。
enum LangType {
    Strong,
    Week,
}
class Java {
    java: any;
    helloJava() {
        console.log('java');
    }
}

class JavaScript {
    javaScript: any;
    helloJavaScript() {
        console.log('JavaScript');
    }
}

// 类型谓词 is
function isJava(lang: JavaScript | Java): lang is Java{
    return (lang as Java).helloJava !== undefined;
}

function getLanguage(type: LangType, x: string | number){
    let lang = type === LangType.Strong ? new Java() : new JavaScript();

    if((lang as Java).helloJava) {
        (lang as Java).helloJava();
    } else {
        (lang as JavaScript).helloJavaScript();
    }

    // 类型保护函数
    if(isJava(lang)) {
        lang.helloJava()
    } else {
        lang.helloJavaScript();
    }
 
    // instanceof
    if(lang instanceof Java) {
        lang.helloJava();
    } else {
        lang.helloJavaScript();
    }

    // in
    if('java' in lang) {
        lang.helloJava();
    } else {
        lang.helloJavaScript();
    }

    // typeof 
    if(typeof x === 'string') {
        x.length
    } else {
        x.toFixed();
    }
    return lang;
}

getLanguage(LangType.Strong, 11111);

4、高级类型

交叉类型 比较适合做对象的混入

interface DogInterface {
    run(): void;
}
interface CatInterface {
    jump(): void;
}

let pet: DogInterface & CatInterface = {
    run(){},
    jump(){},
}

联合类型 可以使类型具有一定的不确定性

// 可区分的联合类型 
interface Square {
    kind: 'square';
    size: number;
}
interface Rectangle {
    kind: 'rectangle',
    width: number;
    height: number;
}
interface Circle {
    kind: 'circle',
    r: number;
}

type Shape = Square | Rectangle | Circle;
function area(s: Shape): number {
    switch(s.kind) {
        case 'square': 
            return s.size * s.size;
        case 'rectangle': 
            return s.height * s.width;
        case 'circle':
            return 2 * Math.PI * s.r;
        default:
            // 检测s是不是never类型
            return ((e: never)=> {throw new Error(e)})(s)
    }
}
area({kind: 'circle', r: 2222})

索引类型

// keyof T
interface ObjInterface {
    a: number;
    b: number;
}
let key: keyof ObjInterface = 'b';

// T[K]
let value: ObjInterface['a'] = 22222;

// T extends U

// 应用实例
let obj2 = {
    a: 1,
    b: 2,
    c: 3,
};

function getValue1(obj: any, keys: string[]){
    return keys.map((key => obj[key]));
}
const res1 = getValue2(obj2, ['a', 'b']);


// 改造getValue1,约束keys的传参
function getValue2<T, K extends keyof T>(obj: T, keys: K[]): T[K][]{
    return keys.map((key => obj[key]));
}
const res2 = getValue2(obj2, ['a', 'b']);

映射类型
映射类型是预先定义的泛型接口,通常还会结合索引类型,获取对象的属性

interface ObjInterface2 {
    a: number;
    b: number;
    c: number;
}

type ReadObj = Readonly<ObjInterface2>;
type PartialObj = Partial<ObjInterface2>;
type PickObj = Pick<ObjInterface2, 'a' | 'b'>;
type RecordObj = Record<'x'|'y', ObjInterface2>;

// 例如Pick的定义
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

条件类型

// T extends U ? X : y

type TypeName<T> = 
    T extends string ? 'string' : 
    T extends number ? 'number' :
    T extends boolean ? 'boolean' :
    T extends undefined ? 'undefined' : 
    T extends Function ? 'function' : 
    'object';

type Diff<T, U> = T extends U ? never : T;

type T1 = TypeName<string>;
type T2 = TypeName<string[]>;
type T3 = TypeName<string | string[]>;

// 内置的条件类型
type T4 = Exclude<'a'|'b'|'c', 'a'>;
type T5 = Extract<'a'|'b'|'c', 'a'>;
type T6 = NonNullable<'a'|'b'|'c'| undefined | null>;

相关文章

网友评论

      本文标题:TypeScript基础

      本文链接:https://www.haomeiwen.com/subject/whzwoltx.html