TypeScript的介绍

1.ts是由微软开发的开源变成语言(vscode和ts都是微软提供的,vs里面很多ts的适配,里面有很多ts的插件,让写法更佳舒适)

2.ts是js的超集(超集的理解:ts在js之上,包含js所有最新的语法特性,包含es6、es7所对应的写法)

【 es 3一个版本,es5一个版本 ,es 6一个版本,es2017,2018,2019都是es7版本】

3.ts是开发大型应用的基石(为什么要学ts?很多大型项目都是基于ts来开发的,比如angular,vscode,vue 3.0,react;越来越多的特性都偏向ts,大型应用基本都用ts语法做支持)

4.ts提供了更丰富的语法提示

5.ts在编译阶段能检查语法错误

1.先去官网安装node

2.npm i typescript

错误检查&ts的编译

(为什么需要编译?因为浏览器无法识别ts,所以需要将ts编译成js)

var a:string='123';
console.log(a);

执行tsc index.ts,将index.ts文件编译为index.js文件。

创建配置文件:tsc --init    , 配置完rootDir和outDir后,直接输入tsc编译

错误检查:

但是这段代码在js中却可以正确运行

js是动态类型,可以动态更改变量的类型

var a = '123';
a=123;
console.log(a);

ts是静态类型的(一旦定义完类型后就无法更改它的类型):

ts中的数据类型&&ts新增的语法特性

js:基本类型:boolean 、string、number、null、undefined、symbol

引用类型:object

ts:数据类型:

  1. number
    let num: number = 6;
  2. string
    let str: string = '123';
  3. boolean
    let flag: boolean = false;
  4. any
    let obj:{ // 对象类型的注解
        str: string,
        toString: () => void
    } = {
        str: '124',
        toString: function () {
    console.log(obj);
    // 或这样写1
    // interface Obj {
    //    str: string;
    //    toString: () => void
    // let obj: Obj = {
    //     str: '123',
    //     toString:function () {
    //     }
    // 或这样写2
    // type Obj = {
    //    str: string;
    //    toString: () => void
    // let obj: Obj = {
    //     str: '123',
    //     toString:function () {
    //     }
    // }

    let obj:any = {
        str: '124',
        toString: function () {
    console.log(obj);

    表示任意数据类型。

    1)如果是对象的话,any不能提示原有的属性和方法

    2)如果是不同变量的话,可以是任意的数据类型

    3)未给初始值的变量类型为any (比如let a; 这里的a就是any类型,所以可以a='123'; a=123;不会报错)

  5. undefined ,
    let num: number = undefined;
    配置项中--strictNullChecks会严格检查null和undefined类型,赋值会赋不成功                      ( 想赋的话把此参数改成true,但是官网不建议这么赋值,想这样赋的话就用联合项 推荐写法:
    let num: number | undefined = undefined;
  6. null  ,null和undefined是所有类型的子类型。
  7. never,表示永不存在值的类型。当报错或死循环的时候用它。
    function error(message) {
        throw new Error(message);
    function fail() {
        return error('something failed');
    function infiniteLoop() {
        while (true) {
    }
  8. void  :表示没有类型,用在函数没有返回值的时候。
    function test(): void {
        console.log(1111);
    }
  9. 枚举
  10. 数组 :
    // 数组的注解;有3种表示方法
    // 1.类型[]
    let arr1: number[] = [1, 2, 3];
    // 2.Array<类型> Array<number>
    let arr2: Array<number> = [1, 2, 3];
    // 3.interface
    interface NumberArray {
      [index: number]: number;
    let list: NumberArray = [1, 2, 3, 4];
    // 类数组
    function test() {
      let args: IArguments = arguments;
    }

  11. 元祖

Object:非原始类型。

// 全局声明一个函数,规定这个函数的参数是对象或null,没有返回值
declare function create(o: object | null): void;
create({ prop: 0 }); // OK
create(null); // OK
create([]); // OK
create(function(){}); // OK
create({}); // OK
// 由此看出,这里的object就是非原始类型

进一步的区分:interface、 number[]、string[]、boolean[]

数组中泛型的写法: Array<number>、Array<string>、Array<boolean>

函数注解:

let test=function(a:number,b:number):number{
    return a+b;

开发者自己定义的ts变量类型就是类型注解

当我们没有指定类型的时候,ts会自动帮我们分析当前的变量类型。

(当类型推断能推断出正确的类型时,就不用类型注解,比如函数这种情况下

function add(a, b) {
  return a + b;
add(1, 2);

1.联合类型的公有属性是不会报错的;比如toString(),number和string类型都有这个方法就不会报错。

2.在赋值的时候就已经确定了数据的类型。不能更改类型了。

对对象的形状进行描述;

对类的一部分的行为的抽象;

interface Person {
  name: string;
  age: number;
let person: Person = {
  name: "lily",
  age: 18,

【interface定死了以后,它的属性不可多,也不可少

如果想要多或少属性怎么办呢?

;可以用可选属性?:

多;用任意属性[propName:string]:any

如果遇到id这种唯一不可变的属性,可以用readonly属性

ReadonlyArray<T>类型

let ro: ReadonlyArray<number> = [1,2,3,4];

readonly 还是 const?

当做变量用const,当做属性用readonly(主要判断属性是否可写)

函数类型接口

(之前是按这样的方式来注解函数,有1个问题:在注解函数的同时实现了这个函数,如果我只想要定义这个函数类型,没办法定义)

function mySearch1(source: string, subString: string): boolean {
  let result = source.search(subString);
  return result > -1;

函数表达式的方式太冗长

let mySearch: (source: string, subString: string) => boolean = function (
  source: string,
  subString: string
): boolean {
  let result = source.search(subString);
  return result > -1;

我们希望抽象出来一个参数是source和subString,返回值是boolean的函数类型

第一种(不常见):

type SearchFunc = (source: string, subString: string) => boolean;
let mySearch: SearchFunc = (source: string, subString: string): boolean => {
  let result = source.search(subString);
  return result > -1;

第二种(常见):

interface SearchFunc {
    (source: string, subString: string): boolean;
let mySearch: SearchFunc = (source: string, subString: string): boolean => {
  let result = source.search(subString);
  return result > -1;

 可索引类型接口(就是数组类型接口)

当索引是number时候,就可以描述一个数组:

interface numberArr {
  [index: number]: number;
let test: numberArr = {
  0: 1,
  1: 2,
let arr: numberArr = [1, 2, 3];

 注意:索引签名支持2种形式:字符串和数字。因为所有的number最终会转为字符串,当使用 number来索引时,JavaScript会将它转换成string然后再去索引对象。

 官网例子:

(1)为什么第一个索引签名是number会报错? 因为Animal父类的name是string类型

(2)那如果把第一个改成string又为什么会报错?因为两者重复。

(3)如果把第二个索引签名改成number类型为什么不报错?因为所有number最后都被会js转成string类型。

(4)如果number都会被转为string,那么回到第一个问题,为什么不能给第一个索引签名设置为number?因为string类型范围比number范围大,Animal是父类, 父类必须比子类范围要大,所以第一个必须是string,第二个必须是number

索引签名有点类似老大的意思,索引签名是个大范围,接口里面的属性必须得在这个范围内。

interface NumberDictionary {
  [index: string]: number | string;
  length: number; 
  name: string; 

索引签名也可以设置为只读:

类 类型接口

可以用接口来描述类吗?不完全可以,因为类有构造器。

对类的一部分的行为的抽象”的理解:

把类上 抽象的公共属性和方法,抽成一个接口。

想要解决这个报错问题,可以改配置项"noImplicitAny": false

interface Alarm {
  alert(): void;
interface Light {
  color: string;
  lightOn(): void;
  lightOff(): void;
class Door {}
class SecurityDoor extends Door implements Alarm {
  alert() {
    console.log("hi");
class Car implements Alarm, Light {
  color = "red";
  lightOn() {}
  lightOff() {}
  alert() {}

类和接口对比:

(1)抽象类中定义抽象方法要实现;
         接口中定义的属性方法都要实现;

(2)抽象类中的方法属性可以通过继承方式来拿到;
         接口的抽象方法需要实现;实现接口的话,接口所有方法都要实现;

(3)1个类可以实现多个接口;多个子类可以继承1个抽象的类

 用类 分别实现类的静态部分与实例部分

(类的静态部分和实例部分需要单独写)

通过接口直接实现类的构造函数是会报错的,因为constructor存在于类的静态部分,所以不在检查的范围内。

但是也有办法:

单独抽离1个构造函数的interface,用函数检查的方式单独检查函数的interface,然后返回一个new的实例

interface ClockInterface {
  currentTime: Date;
  getTime(h: number, m: number): void;
interface ClockConstructor {
  new (h: number, m: number): any;
  getTime1():void; // 相当于一个静态方法
class Clock implements ClockInterface {
  currentTime = new Date();
  getTime() {}
  constructor(h: number, m: number) {}
  static getTime1() { }
function createClock(Clock: ClockConstructor, h: number, m: number) {
  return new Clock(h, m);
let clock = createClock(Clock, 12, 12);

就是接口可以继承接口 或 类可以实现接口。

“接口可以继承接口”的理解:

接口是对象形状的描述,接口继承接口就相当于在原本基础上进行进一步的约束。

interface Shape {
    color: string;
interface Square extends Shape {
    sideLength: number;
let square = <Square>{};  // 这里接口继承接口,然后用断言的方式赋初始值
square.color = "blue";
square.sideLength = 10;

官方这里没有解释为什么这里要用类型断言:

如果let square:Square;这样写,报错提示:“在赋值前就使用了变量”;定义了square,但是没有初始值,但是一旦给初始值,就回去检查它类型,就会类型不符,所以用类型推断方式。

接口的混合类型

函数类型的interface,可以通过添加属性的方式来实现对象的interface

相当于函数类型interface+对象类型interface

interface Counter {
    (start: number): string;
    interval: number;
    reset(): void;
function getCounter(): Counter {
    let counter = <Counter>function (start: number) { };
    counter.interval = 123;
    counter.reset = function () { };
    return counter;
let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;

接口继承类

1.类可以实现接口:类可以抽象一部分功能,让接口实现

2.接口可以继承接口:接口相当于一个对象,继承一个对象,就是能在这个对象上面添加更对属性

3.接口可以继承类:类也是接口,接口可以继承接口,所以接口能继承类。

1.image重复,改成image1。

2.提示错误实现接口SelectableControl,因为接口继承Control接口:在Image里定义state,但是因为是私有成员,所以没法直接实现state

 接口和类的关系:

// 2种写法效果是一样的
class Point {
  x: number;
  y: number;
  constructor(x: number, y: number) {
    this.x = x;
    this.y = y;
interface PointerInterface {
  x: number;
  y: number;
interface Point3D extends Point {
  z: number;
interface Point3D extends PointerInterface {
  z: number;

虽然这种写法方式没有问题,但容易引起大家歧义,不建议大家用接口继承类。

函数有2种写法:函数声明和函数表达式。

函数声明的注解方式:

function test(a: number, b: number): number {
  return a + b;

函数表达式的注解方式:

let test1: (a: number, b: number) => number = (a, b) => {
  return a + b;
let test2: (a: number, b: number) => {} = (a, b) => {
  return { a, b };
console.log(test2(1, 2));

当参数少了的时候同interface可以设置可选参数

【可选参数注意事项】

(1)默认把可选参数放在后面,必选参数不能位于可选参数后。

function test(a: string, b?: string): string {
  return "" + a + b;
console.log(test("1", "2"));

(2)默认值和可选参数不能放一起。

当参数多了可以用剩余参数 ,...args,...args是个数组,必须放到最后面

// 语法
function test1(
  { first, second }: { first: number; second: number } = { first: 1, second: 2 }
  return first + second;
function test2({ first = 2 }: { first: number }) {
  return first;
// 解构赋值
// 变量和属性名一致时,对象可简写
// let {a:a,b:b,c:c}={a:1,b:2,c:3};
// 等价于
// let {a,b,c}={a:1,b:2,c:3};
// 不完全结构是值(右边)多了;结构失败是变量(左边)多了

关于this

this有4个规则:

(1)默认情况下this指向window。(函数的独立调用、立即执行函数、闭包中的this都指向window)

(2)隐式绑定,谁调用就指向谁。

(3)显示绑定,call、apply、bind绑定this指向

(4)new的this指向实例化后的对象

报错的this指向window,我们希望这里的this指向deck。

就可以这么写

noImplicitThis配置项

 控制当源文件中存在this的值是any的时候是否报错,noImplicitThis默认为false,即当源文件中存在this为any的情况也不报错,如果设置为true则会报错

函数的重载

ts的重载解决的只是表意问题,能够表意更清楚

function reverse(x: string): string;
function reverse(x: number): number;
function reverse(x: number | string) {
  if (typeof x === "string") {
    return x.split("").reverse().join("");
  } else {
    return Number(x.toString().split("").reverse().join(""));
console.log(reverse(123));

类的注解方式

class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    greet() {
        return "Hello, " + this.greeting;
let greeter = new Greeter("world");

继承中的super在constructor内部默认是构造函数;在这以外super指的是父类。

class Animal {
  name: string;
  constructor(theName: string) {
    this.name = theName;
  move(distanceInMeters: number = 0) {
    console.log(`${this.name} moved ${distanceInMeters}m.`);
class Snake extends Animal {
  constructor(name: string) {
    super(name);
  move(distanceInMeters = 5) {
    console.log("Slithering...");
    super.move(distanceInMeters);
let sam = new Snake("Sammy the Python");
sam.move();

类成员的修饰符

public:

(1)自身调用:

(2)子类调用:

(3)实例调用:

 private:

(1)只能自身调用

protected:(控制可访问否,上面都是)

(1)自身可以调用(2)子类可以调用

readonly:(控制可写否)

顺序:public readonly

不能修饰成员方法

参数属性可以方便地让我们在一个地方定义并初始化一个成员。

class Octopus1 { // 简写
  constructor(private theName: string) {}
class Octopus2 {
  private theName: string;
  constructor(theName: string) {
    this.theName = theName;

存取器(改变赋值和读取的行为)

1.成对出现,定义了getter一定也有setter,并且修饰同一属性

2.这里的赋值操作相当于调用了set方法,判断里用到了fullName属性,相当于调用了get方法。

静态属性用static来定义,通过类/构造函数来访问。如果是实例属性用this.来访问的。

abstract关键字来定义抽象类,抽象类能够作为其它派生类的基类使用。

特点:(1)无法创建实例

           (2)抽象类中的抽象方法一定要实现

abstract class Animal {
  abstract makeSound(): void; // 发声方式
  move(): void {
    console.log("roaming the earch...");
class Snack extends Animal {
  makeSound() {
    console.log("zzzzzzzz");
  move(): void {
    console.log("roaming the earch...");
class Cow extends Animal {
  makeSound() {
    console.log("mmmmmmmmmm");
  move(): void {
    console.log("roaming the earch...");

1.定义了一个类的时候,相当于定义了一个类型/构造函数

2.接口可以继承

TypeScript的介绍1.ts是由微软开发的开源变成语言(vscode和ts都是微软提供的,vs里面很多ts的适配,里面有很多ts的插件,让写法更佳舒适)2.ts是js的超集(超集的理解:ts在js之上,包含js所有最新的语法特性,包含es6、es7所对应的写法)3.ts是开发大型应用的基石(为什么要学ts?很多大型项目都是基于ts来开发的,比如vscode,vue 3.0,react;越来越多的特性都偏向ts,大型应用基本都用ts语法做支持)4.ts提供了更丰富的语法提示5.ts在
1、函数内部的变量名如果第一次出现,且出现在=面,即被视为定义一个局部变量,不管全局域中有没有用到该变量名,函数中使用的将是局部变量,例如: num = 100 def func(): num = 123 print(num) func()输出: 说明函数中定义的num是一个局部变量,会将全局变量覆盖。再例如: num = 100 def func(
func() 会出现local variable ‘x’ referenced before assignment的错误是因为全局变量与局部变量同名时,当你想在函数内部中修改外部变量的值,python首先会认为该变量是局部变量,函数内部没有定义局部变量a=value,而内部作用域想要改变外部作用域的值,就要用到global关键词。 a = 13 def func():
最近在练手typescript的过程中,遇到了两个小问题,虽然当时很不习惯,但解决问题后,也算是熟悉和加深了对typescript的理解。 一、显式赋值断言 let a: string; if (!a) a = 'aa'; console.log(a) 会出现错误提示:Variable ‘a’ is used before being assigned. 在赋值使用变量a。 let a!: string; //变量后加! if (!a) a = 'aa'; 编译一个ts文件,开发react后缀 .tsx 命令:tsc hello.ts 含义:将ts文件转成js文件,如果有ts语法错误,会报错,但是仍然会生成js文件,我们仍然可以使用这个js文件; 如果想要在报错的时候终止js的生成,可以在tsconfig.json中配置onEmiOnError即可 ts只会在编译时对类型进行检查,如果发现错误,编译时就会报错;(静态检查) 而js是再运行时,发现错误,会报错;(动态检查) 3. 数据类型
一篇文章,我们了解了TS的安装使用以及基础类型,本文接着学习类型推断以及变量声明的内容。TS的核心功能就是,我们需要给变量或方法添加类型注解来表明数据类型。当没有提供类型注解时,TS编译器会利用来推断类型。 如果由于缺乏声明而不能推断出类型,那么它的类型被视作默认的动态 类型。有些情况下,我们会比TS清楚更确切的类型,可以使用手动指定一个值的类型,即允许变量从一种类型更改为另一种类型。它没有运行时的影响,只是在起作用。类型断言有两种形式,第一种是语法:第二种是 语法:举个例子: 通过上面的例子可以知