- npm i --save react react-dom @types/react @types/react-dom @types/前缀表示咱们额外要获取react和react-dom的声明文件。
- npm i --save-dev typescript awesome-typescript-loader source-map-loader ts-loader awesome-typescript-loader可让Webpack使用TypeScript的标准配置文件tsconfig.json编译TypeScript代码。 source-map-loader使用TypeScript输出的sourcemap文件来告诉webpack什么时候生成本身的sourcemaps.这就容许你在调试最终生成的文件时候就好像在调试TypeScript源码同样 ts-loader 将typescript转换成JavaScript;
- 根目录下建立tsconfig.json文件
{
"compilerOptions": {
"outDir": "./dist/", //编译js的输出目录
"sourceMap": true, // 编译是否生成对应的source map文件
"noImplicitAny": true, //强类型检查,没法推断类型时候,提示错误
"module": "commonjs", // 定义遵循的JavaScript模块规范
"target": "es5", //遵循的标准
"jsx": "react",
"experimentalDecorators": true, // 启用实验性的装饰器特性
},
"include": [
"./src/**/*" // 须要包含编译的目录
]
}
复制代码
module.exports = {
entry: "./src/index.tsx",
output: {
filename: "bundle.js",
path: __dirname + "/dist"
},
devtool: "source-map",
resolve:{
extensions: [".ts", ".tsx", ".js", ".json"]
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: "awesome-typescript-loader"
},
{
enforce: "pre",
test: /\.js$/,
loader: "source-map-loader"
}
]
},
externals: {
"react": "React",
"react-dom": "ReactDOM"
}
}
复制代码
ts中的数据类型有:Number数值类型,string字符串类型,Boolean布尔类型,enum枚举类型, any任意类型,void空类型,Array数组类型,Tuple元祖类型,Null空类型。react
- 声明数组 let arr:number = [];
- 给数组赋值
字面量赋值:let arr: number = [1,2,4]
构造函数赋值: let arr:Array<number> = new Array(1,2,3)
复制代码
ts中,指定数据类型的数组只能存贮同一类型的数组元素webpack
- 元祖 元祖是特殊的数组,元祖类型容许表示一个已知元素数量和类型的数组,各元素的类型没必要相同。
let arr:[string,number];
arr = ['12', 2];
arr = [2,'12'] // 报错
复制代码
基本类型字符串:用双引号或者单引号括起来的一串字符串 引用类型字符串:用new实例化的String类型web
let jsan:string = '发就是电话';
let jsanpan:String = new String('1333吃')
console.log(jsan);
console.log(jsanpan); // 打印出的String {'1333吃'}
复制代码
日期对象是Date实例,可用构造函数的方法进行建立,声明这个日期变量时候,也要标明它的类型是Date,eg: let d:Date = new Date('2018/09/09 05:30:00')正则表达式
两种方式:一种是字面量方式,一种是new关键字;经常使用test和exec测试字符串匹配typescript
let str:string = 'abcdefg';
let reg:RegExp = /ab/g;
let result:boolean = reg.test(str);
console.log(result); // true
let str2 = 'dapangzishuai'
let reg2:RegExp = new RegExp("dapang",'gi')
let reg3:RegExp = new RegExp("aaa",'gi')
let result:any = reg2.exec(str2);
let result2 = reg3.exec(str2);
console.log(result) //["dapang", index: 0, input: "dapangzishuai", groups: undefined]
console.log(result2) // null
复制代码
为了让程序之间更有层次,变量之间互不干扰,利用命名空间来区分,成员须要用export导出npm
namespace a {
export class An {
name:string = '安安'
talk() {
console.log('女生安安')
}
}
}
namespace b {
export class An {
name:string='安安'
talk() {
console.log('男生安安')
}
}
}
let an1:a.An = new a.An();
let an2:a.An = new b.An();
console.log(an1.talk(),an2.talk(), '这是啥啊')
复制代码
ts中的数据类型有:Number数值类型,string字符串类型,Boolean布尔类型,enum枚举类型, any任意类型,void空类型,Array数组类型,Tuple元祖类型,Null空类型。json
默认值:默认值可让你在属性为undefined的时候使用缺省值数组
function keepWholeObject(whoeObject: { a: string, b?: number }) {
let { a, b=101 } = whoeObject
console.log(a,b,'123是')
}
keepWholeObject({ a :'12', b : 10 });
复制代码
函数声明:bash
function f({ a, b } = { a: "", b: 0 }): void{
console.log(a, b, 'ab是');
}
f();
复制代码
- 接口-interface eg: interface LabelledValue { label: string; }表明一个label属性类型为string的对象,若是不知足的话直接报错
- 可选属性 与普通的接口定义差很少,只是会在属性名字后面加个?符号 eg:interface LabelledValue { label?: string; color?: string; } 优势:能够对可能存在的属性进行预约义,若是有用到了不存在的属性会报错
- 只读属性-readonly 在属性名前用readonly来指定只读属性
interface Point {
readonly x: number;
readonly y: number;
}
let point : Point = {
x: 10,
y: 10
}
// point.x = 5; 报错,由于是只读属性,不能够进行修改
复制代码
// ReadonlyArray<T>类型,把全部可变方法去掉了,确保数组建立后不再能被修改
let ro: ReadonlyArray<number> = [1,2,3,4];
ro[0] = 12; 报错,属性只读不可修改
ro.push(4) 报错,ReadonlyArray上没有push这个方法
let a: number[] = [1,2,3,4];
let b: ReadonlyArray<number> = a;
a = b //报错
a = b as number[]; //类型断言从新写,不报错
复制代码
判断是用const仍是readonly,看他的用途,若是是变量使用的话用const,属性使用则用readonlydom
- 额外的属性检查
1.避开它的检查,用类型断言的方式 eg: let mySquare = createSquare({colour: "red", width: 100} as SquareConfig) 即便SquareConfig中没有colour这个属性,也不会报错
2.避开它的检查,用索引签名的方式 [propName: string]: any;
3.避开它的检查,将这个对象赋值给另外一个变量,squareOptions不会通过额外属性检查 let squareOptions = { colour: 'red'}; let mysquare = createSquare(squareOptions);
- 函数类型 以下:函数类型时候,函数的参数名能够不与接口里定义的名字匹配,并且定义的属性值也能够不写。
interface SearchFunc {
(source: string, subString: string) : boolean;
}
let mySearch: SearchFunc;
mySearch = function(source, subString) {
let result = source.search(subString);
return result > -1;
}
复制代码
- 可索引的类型 可索引类型具备一个索引签名,描述了对象索引的类型,还有相应的索引返回值类型; 以下,这个索引签名表示当用number去索引StringArray时候会获得string类型的返回值
interface StringArray {
[index: number]: string;
}
let myArray: StringArray;
myArray = ['Bob', 'Fred'];
let myStr: string = myArray[0];
复制代码
- 类类型
静态属性:经过static关键字能够声明类型的静态属性。
- 接口的继承 经过implements关键字继承,接口的继承能够屡次继承
interface Animal {
name: string;
eat(): void;
}
interface Person extends Animal {
use(): void;
}
class Dog implements Person {
name: string;
constructor(theName: string) {
this.name = theName;
}
eat() {
console.log(`${this.name}吃`)
}
use() {
console.log(`${this.name}胖`)
}
}
let dog: Person;
dog = new Dog('筛子');
dog.eat();
dog.use();
复制代码
- 混合类型
- 接口继承类
class Control {
private state: any;
}
interface SelectableControl extends Control {
select(): void;
}
class Button extends Control implements SelectableControl {
select() {
}
}
class TextBox extends Control {};
// SelectableControl包含了Control的全部成员,包括私有成员,因此Control的子类才能够实现SelectableControl内的接口。Image不是SelectableControl的子类,因此以下写法会报错
// class Image implements SelectableControl {
// select(){}
// } //报错
class Image extends Control implements SelectableControl {
select(){}
} //不报错
复制代码
- 以下:Animall是基类,Cat是派生类,Cat派生自基类Animall,经过extends关键字。派生类叫子类,基类一般叫超类。 类的继承
class Animall {
name: string;
constructor(theName: string) {
this.name = theName;
}
eat() {
console.log(`动物叫${this.name}`)
}
}
let animall = new Animall('小狗');
animall.eat();
class Cat extends Animall{
constructor(theName: string) {
super(theName);
}
eat() {
super.eat();
console.log('吃狗粮')
}
}
let cat: Animall;
cat = new Cat('猫');
cat.eat();
class People extends Animall {
constructor(theName: string) {
super(theName);
}
eat() {
super.eat();
console.log(`${this.name}拒绝吃狗粮`);
}
}
let people: Animall;
people = new People('人');
people.eat();
复制代码
子类经过关键字extends继承,经过super方法调用基类的方法,也能够重写基类的方法。 public: 公有属性,可赋值 protected: 受保护属性,没法赋值 private: 私有属性,没法赋值 protected成员在派生类中仍然能够访问,而private成员在派生类中也不能够访问。
eg:class Person {
protected name: string;
constructor (name: string) {
this.name = name;
}
}
class Employ extends Person {
private department: string;
constructor(name: string, department: string) {
super(name)
this.department = department;
}
public getMesage() {
return `hello, my name is ${this.name} 住在${this.department}`
}
}
let em = new Employ('an', 'beijing')
console.log(em.getMesage());
console.log(em.name); // 报错,不能再person类之外使用name属性,可是能够在Employ中使用,由于Employ是Person派生
复制代码
- 抽象类 抽象类做为其余派生类的基类,通常不会直接被实例化。abstract关键字用于定义抽象类和在抽象类内部定义抽象方法。
abstract class Department {
constructor(public name: string) { };
printName(): void {
console.log(`aaa${this.name}`)
};
abstract printMeeting(): void; // 必须在派生类中实现
}
class AccountDeparment extends Department {
printMeeting(): void {
console.log('111')
}
generator(): void {
console.log('222')
}
}
let department: Department; // 容许建立一个对抽象类型的引用
// department = new Department(); // 报错,不能建立一个抽象类的实例
department = new AccountDeparment('an'); // 容许对一个抽象子类进行实例化和赋值
department.printName();
department.printMeeting();
// department.generator(); // 报错,类型Department上不存在generator
复制代码
- 高级技巧
class Greeter {
static standardGreeting = 'hello there';
greeting: string;
greet() {
if (this.greeting) {
return `hello ${this.greeting}`
} else {
return Greeter.standardGreeting
}
}
}
let greet1 : Greeter;
greet1 = new Greeter();
console.log(greet1.greet());
/**建立一个greeterMaker变量,保存了这个类或者说保存了类构造函数。使用typeof Greeter意思是取Greeter类的类型而不是实例的类型。
确切的说就是‘告诉Greeter标识符的类型,也就是构造函数的类型,这个类型包含了类的全部静态成员和构造函数。’而后在greeterMaker上使用new,建立Greeter的实例
* */
let greeterMaker: typeof Greeter = Greeter;
greeterMaker.standardGreeting = 'hello';
let greet2: Greeter = new greeterMaker();
console.log(greet2.greet());
复制代码
- 可选参数 ts中每一个参数都是必须的,多传少传都会报错,当想实现可选参数的时候,在参数名旁边使用?实现可选参数的功能。可是可选参数必须放在必须参数的后面
function add(par1: string, par2: string) {
return `${par1}额${par2}`
}
// let result1 = add('猫'); 报错 少一个参数
// let result2 = add('猫', '狗', '鱼'); 报错,多一个参数
let result3 = add('猫', '狗');
function add2(par1: string, par2?: string) {
return `${par1}额${par2}`
}
// let result1 = add('猫'); 不报错
// let result2 = add('猫', '狗', '鱼'); 报错,应该有1-2个参数,可是出现了3个
let result3 = add('猫', '狗');
复制代码
- 默认参数 在全部必须参数后面的带默认初始化的参数都是可选的,与可选参数同样,在调用函数时候能够省略 带默认值的参数不用必须放在必须参数的后面,若是带默认值的参数要出如今必须参数前面时候,必须明确的传入undefined值。
function person(name: string, age = 18){
return `名字是${name},年龄是${age}岁`
}
let re = person('an');
let re2 = person('an', undefined); // age为18
// let re3 = person('an', 20, 'anm'); //报错
let re4 = person('am', 22);
console.log(re,re2, re4);
复制代码
- 剩余参数 定义:不知道有多少个参数将要传进来,可能0个可能多个,把全部参数收集到一个变量里 编辑器建立参数数组,名字是你在...后面定的名字,能够在函数体内使用这个数组。
function person (name: string, ...params: string[]) {
return params;
}
let re = person('an', '18', 'amy');
console.log(re, 're是') // ['18','amy']
复制代码
- this
- 重载
使用any类型能够接收任何类型的arg参数,传入的类型与返回的类型应该是相同的,可是用了any,咱们传入一个数字,任何类型的值都有可能被返回
function identity(arg: any): any {
return arg;
}
复制代码
类型变量T:一种特殊的变量,只用于表示类型而不是值,使得返回值的类型与传入的参数的类型是相同的
- 泛型函数,适用于多个类型,不会丢失信息,传入数值类型而且返回数值类型
function identity<T>(arg: T): T {
return arg;
}
// 第一种方法明确指定了T的类型,
let outPut = identity<string>('eww');
// 第二种方法,类型推论
let output2 = identity('90');
function a<T>(arg: T) : T {
console.log(arg.length); // 报错,类型T上不存在属性length,由于传入的多是number
return arg;
}
// 泛型函数b,接收类型参数T和参数arg,它是个元素类型是T的数组,并返回元素相似是T的数组
function b<T>(arg: T[]) : T[] {
console.log(arg.length); // 不报错
return arg;
}
复制代码
- 泛型接口
interface Generic {
<T>(arg: T) : T;
}
function identity<U>(arg: U): U {
return arg;
}
let aa: Generic = identity;
复制代码
- 泛型类,使用<>括起泛型类型,跟在类名后面。指的是实例部分的类型,因此类的静态属性不能使用这个泛型类型
class Person<T> {
zeroValue: T;
add: (x: T, y: T) => T
};
let person = new Person<number>();
person.zeroValue = 1;
let a = person.add = function(x,y) {
return x + y;
}
复制代码
- 泛型约束 定义一个接口来描述约束条件,使用这个接口和extends关键字来实行约束
interface len {
length: number
}
function logging<T extends len>(arg: T) : T {
console.log(arg.length);
return arg;
}
// logging(333); //报错,类型‘333’的参数不能赋给类型‘len’的参数;
logging('123');
复制代码
- 枚举经过关键字enum来定义,使用枚举能够定义一些有名字的数字常量,一个枚举类型能够包含零个或者多个枚举成员. 没有初始化函数而且以前的枚举成员是常数,在这种状况下,当前枚举成员的值为上一个成员的值加1,可是第一个若是没有初始化方法那它的初始值为0
enum Enum{
A
}
let a = Enum.A;
let b = Enum[a];
console.log(a,b) // a是0,b是‘A’
复制代码
- 常数枚举 :在enum关键字前使用const修饰符,只能使用常数枚举表达式
const enum Par {
A = 1,
B = A*2
}
复制代码
- 外部枚举:描述已经存在的枚举类型的形状,避免重复的问题
declare enum Enum {
A = 1, // 标识符重复
B = A * 2,
}
复制代码
- symbol类型的值是经过Symbol构造函数建立,并且是不可改变的唯一的,能够被用做对象属性的键
模块是自声明的,两个模块之间的关系是经过在文件级别上使用imports和exports创建的。
- 导出声明 任何声明,好比变量,函数,类,类型别名或接口都可以添加export关键字来导出。
- 导出语句 可能须要对导出的部分重命名 eg:export { ZipCode }; export { ZipCode as main };
- 从新导出 从新导出功能并不会在当前模块导入那个模块或者定义一个新的局部变量 或者一个模块能够包裹多个模块,并把他们导出的内容联合在一块儿经过语法: export * from 'module'
- 导入 导入内容从新命名: import { a as b } from ''
- 将整个模块导入到一个变量,经过它来访问模块的导出部分
import * as validator from "./ZipCodeValidator";
let myValidator = new validator.ZipCodeValidator();
复制代码
- 默认导出
默认导出使用default关键字标记,一个模块只能有一个default导出。