WdBly Blog

懂事、有趣、保持理智

周维的个人Blog

懂事、有趣、保持理智

站点概览

周维 | Jim

603927378@qq.com

推荐阅读

Typescript笔记

Typescript笔记

Typescript工程

ts和React+Webpack结合使用

webpack只会打包js文件,webpack的作用是从入口文件,找到依赖图,最终将所有chunk打包到一个js文件中,当然有很多其它方法拆分文件,这里不细说

使用了ts后,文件都变成了.ts,webpack无法识别打包,这里就需要ts-loader/awesome-typescript-loader,在webpack打包前,将ts全部编译成js文件。

当使用Eslint时,需要配置ts的支持

配置tsconfig.json文件,ts在编译的配置文件,放在项目根目录

类型

  • boolean、string、number
  • 数组:number[]、Array<number>
  • 元组 Tuple:let x:[string, number] = [‘a’, 1]
  • 枚举 Enum:enum Color {Red = 1, Green, Blue}

枚举默认是以0开始,当然可以手动指定值,并且是双向的
let c: Color = Color.Green; // 2,因为会从1开始计数
let c: Color = Color[3]; // Blue,可以双向锁定

  • any:any可以是任何类型、并且可以给任何类型赋值

  • void:和any相反,代表无类型,如函数无返回

  • null undefined:所有类型的子类型,不在strictNullChecks下时,可以赋值给其他类型变量

  • never:类型表示的是那些永不存在的值的类型

  • object:const a: object = {}

boolean、string、number、Array、Tuple、Enum、any、void、null undefined、never、object、unknow、ReadonlyArray

类型断言

通过类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么”

const someValue: any = 'this is a string' const strLength: number = (someValue as string).length const strLength: number = (<string>someValue).length // 两种形式是等价的。 至于使用哪个大多数情况下是凭个人喜好;然而,当你在TypeScript里使用JSX时,只有 as语法断言是被允许的

接口

接口定义了一组数据结构的形状

// 1、描述对象 interface LabelledValue { label: string; readonly width: number; other?: any [propName: string]: any; } // 2、描述函数类型 interface SearchFunc { (source: string, subString: string): boolean; } // 3、描述数组 interface StringArray { [index: number]: string; } let myArray: StringArray; myArray = ["Bob", "Fred"]; let myStr: string = myArray[0]; // 4、描述类 interface ClockInterface { currentTime: Date; setTime(d: Date); } class Clock implements ClockInterface { currentTime: Date; setTime(d: Date) { this.currentTime = d; } constructor(h: number, m: number) { } }

readonly vs const
最简单判断该用readonly还是const的方法是看要把它做为变量使用还是做为一个属性。 做为变量使用的话用 const,若做为属性则使用readonly。

接口也可以继承

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;

  • 派生类的constructor中调用super(),是为了继承超类constructor中的属性和方法。
  • private属性只能在类里访问,不能在类的外部访问,如实例中访问、派生类中访问
  • protected和private的区别在于protected可以在派生类中访问
  • 构造函数也可以被标记成 protected。 这意味着这个类不能在包含它的类外被实例化,但是能被继承。
  • 可以为类属性设置 readonly。
  • 可以创建类的静态成员,这些属性存在于类本身上面而不是类的实例上
  • 抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化,类似于ts的接口interface
abstract class Animal { // 定义一个抽象方法,子类必须去实现此方法 abstract makeSound(): void; move(): void { console.log('roaming the earch...'); } }
  • 通过抽象类继承的派生类内部实现的私有方法不能被实例化
  • 类的constructor内部定义的属性和方法相当于定义在构造函数内部的属性方法,需要使用寄生组合继承中的,原型链混入方法,也就是子类需要调用super的原因。
  • ts的interface可以直接继承类

函数

  • 箭头函数能保存函数创建时的 this值,而不是调用时的值

泛型

// 我们给identity添加了类型变量T。 T帮助我们捕获用户传入的类型 // 后续我们可以使用此类型T,保证用户输入的类型和输出类型相同 function identity<T>(arg: T): T { return arg; } // 1、直接指定T的类型为string let output = identity<string>("myString"); // 2、使用类型推论 let output = identity("myString");

泛型类型

function identity<T>(arg: T): T { return arg; } let myIdentity: <U>(arg: U) => U = identity; // 泛型接口 interface GenericIdentityFn { <T>(arg: T): T; } function identity<T>(arg: T): T { return arg; } let myIdentity: GenericIdentityFn = identity;
  • 接口也可设置泛型: interface GenericIdentityFn<T> {}

  • 泛型类:class GenericNumber<T> {}let myGenericNumber = new GenericNumber<number>();

泛型约束

// 我们知道T有.length属性,但是编译器不知道,所以报错 // 通过泛型约束解决 function loggingIdentity<T>(arg: T): T { console.log(arg.length); // Error: T doesn't have .length return arg; } interface Lengthwise { length: number; } function loggingIdentity<T extends Lengthwise>(arg: T): T { console.log(arg.length); // Now we know it has a .length property, so no more error return arg; } // 现在这个泛型函数被定义了约束,因此它不再是适用于任意类型: loggingIdentity(3); // Error

类型兼容

变量的类型是由结构决定,而非类型名称

interface Named { name: string; } interface Named2 { name: string; } let p:Named = { name: 'a' } let b:Named2 = p

交叉类型

  • Type1 & Type2

联合类型

  • string | number

用户自定义的类型保护

类型保护就是一些表达式,它们会在运行时检查以确保在某个作用域里的类型。 要定义一个类型保护,我们只要简单地定义一个函数,它的返回值是一个 类型谓词:

// parameterName is Type这种形式, function isFish(pet: Fish | Bird): pet is Fish { return (<Fish>pet).swim !== undefined; } // typeof // instanceof

类型别名

type Name = string; type NameResolver = () => string; type NameOrResolver = Name | NameResolver; type MessageDataRow = { id: number } // 然而,类型别名不能出现在声明右侧的任何地方。区别于接口 type Yikes = Array<Yikes>; // error

接口创建了一个新的名字,可以在其它任何地方使用。 类型别名并不创建新名字—比如,错误信息就不会使用别名

类型别名会给一个类型起个新名字。 类型别名有时和接口很像,但是可以作用于原始值,联合类型,元组以及其它任何你需要手写的类型。

别名不能被 extends和 implements

映射类型

一个常见的任务是将一个已知的类型每个属性都变为可选的

interface Person { name: string; age: number; } // 使用类型映射 type Readonly<T> = { readonly [P in keyof T]: T[P]; } type Partial<T> = { [P in keyof T]?: T[P]; } type PersonPartial = Partial<Person>; type ReadonlyPerson = Readonly<Person>;

Symbols

  • 可以利用Symbols唯一性和不变性实现Class的private

模块

  • 任何声明(比如变量,函数,类,类型别名或接口)都能够通过添加export关键字来导出。
提交

全部评论0

暂时没有评论...