当前位置: 首页 > news >正文

TypeScript 学习之路 - 基础篇

一、介绍

  1. 一种由微软开发的自由和开源的编程语言,简称 TS
  2. TypeScriptJavaScript 的超集,即包含 JavaScript 的所有元素,能运行 JavaScript 的代码,并扩展了 JavaScript 的语法。
  3. 相比于 JavaScript,它还增加了 静态类型模块接口类型注解 方面的功能,相对于 JavaScriptTypeScript 属于 强类型 语言,所以对于项目而言,会使代码更加规范,从而解决了大型项目代码的复杂性。 更易于大项目的开发
  4. TS 是不能被浏览器直接识别的,所以在编译的时候,TS 文件会先编译为 JS文件。

TypeScript 与 ES5、ES6+ 之间的关系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DSsLFo1F-1661916600107)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3da14c79cea44a74a92811e19323737d~tplv-k3u1fbpfcp-zoom-1.image)]

TypeScript 与 JavaScript 的区别

在这里插入图片描述

TypeScriptJavaScript
JavaScript的超集,用于解决大型项目的复杂性一种脚本语言,用于创建动态网页
能在编译期间发现错误并纠正错误只能在运行时发现错误
是强类型语言,支持静态类型和动态类型是弱类型语言,没有静态类型
最终是被编译成JavaScript代码,使得浏览器可以理解直接在浏览器使用
支持模块、泛型和接口不支持模块、泛型和接口

二、安装编译环境

安装并查看版本

// 安装
npm install -g typescript
// 或者
yarn global add typescript

// 查看版本
tsc -v  

创建配置文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F0z53UIz-1661916600108)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6d9b641b7d794fa1be770736a7ca26a6~tplv-k3u1fbpfcp-zoom-1.image)]

//  tsc --init

{ 
    "compilerOptions": { 
    /* Language and Environment */ 
    "target": "es6", 
    /* Modules */ 
    "rootDir": "./src", 
    /* Emit */ 
    "outDir": "./dist", 
    /* Type Checking */ 
    "strict": true, 
   } 
 }

创建一个ts文件

function greeter(person) {
    return "Hello, " + person;
}

let user = "Jane User";

document.body.innerHTML = greeter(user);

编译

tsc greeter.ts  // greeter.ts => greeter.js

三、数据类型

类型例子描述
number1 50 1.5任意数字
string‘hello world’ ‘你好’任意字符串
booleantrue false布尔值true或false
字面量其本身限制变量的值就是该字面量的值
any*任意类型
unknown*类型安全的any
void空值(undefined)没有值或undefined
never没有值不能是任何值
object{id:1, name:“pengyuyan”}任意的JS对象
array[1,2,3]任意js数组
tuple[4,5]元素,TS新增类型,固定长度数组
enumenum(A,B)枚举,TS中新增类型

基础类型

// number    string     boolean
var a: number = 1;  // 添加类型注释来显式指定变量的类型
var a2 = 2;  // // 不需要类型定义--'a2'推断为类型 'number'
let b: string = 'hello';  
//字符串模板
let b1:string=`${b}` // "hello"
const c: boolean = true;

// symbol
// bigint
let f: symbol = Symbol();  // Symbol是es6/es2015才出现的类型
let f1:symbol = Symbol();  // Symbol是es6/es2015才出现的类型
console.log(f === f1)  // false
let g: bigint = 10n   // bigint是es2020新增语法

null 和 undefined

默认情况下它们是所有类型的子类型,即可以赋值给任意类型

let a: string = 'hello'
a = null //right
a = undefined // right
// 这两个类型只有 自己 null 和 undefined 两个类型一旦赋值上,就不能在赋值给任何其他类型
let d: null = null;
let e: undefined = undefined;
let d: string = 'pengyuyan'  // error

当我们在 tsconfig.js 文件中设置 strictNullCheckstrue 时,就不能将 nullundefined 赋值给除 它们自身void 之外的任意类型了。

//  "strictNullChecks": true 

let b: string = 'hello'
b = null // error,不能将类型“null”分配给类型'string'。

let c: string | null = 'hi'
c = null  // right
c = undefined // error,不能将类型'undefined'分配给类型'string | null'。
可选参数 (“strictNullChecks”: true)
//  "strictNullChecks": true 

function f(x: number, y?: number){
    return x + (y || 0)
}
f(1, 2) // 3
f(1) // 1
f(1, undefined) // 1
f(1, null) // error,类型“null”的参数不能赋给类型“number | undefined”的参数。
可选属性 (“strictNullChecks”: true)
//  "strictNullChecks": true 

interface PositionInterface{
    x: number
    y?: number
}

let p: PositionInterface = {x: 10}
p.y = 'abc' // error,不能将类型“"abc"”分配给类型“number | undefined”。

p.y = null // error,不能将类型“null”分配给类型“number | undefined”。

p.y = undefined // right

引用类型

array

TS 中要求数组中的每一项必须是 同一个数据类型
语法:
变量名: 数组中数据的类型[ ] = 数组值
变量名: Array<数组中数据的类型> = 数组值

const arr1: number[] = [1, 2, 3];
const arr2: Array<number> = [1, 2, 3];
const arr3: Array<string> = ['1', '2']
const arr4: Array<number> = [1, 2, '3'] // error 必须是同一个数据类型

//如果想要是数字类型或字符串类型,需要使用 |
const arr5: Array<number | string> = [1, 2, '3']

tuple(元祖)

  1. 元组中,允许一个数组中保存 多个类型 的数据。
  2. *注意:可以把 元祖 一个任意类型并且 长度有限 的数组
const arr5: [string, number] = ['1', 2];

object

// 方式一:
let obj:object;
// 或
let obj:{};

// object 表示一个js对象
let a :object;

a = {
  name:"pengyuyan",
  age:18
};

// 方式二
let b:{};
b = {
  name:"pengyuyan",
  age:18
}

// 定义对象时,需要定义出对象中有哪些属性,每一个属性的值是什么类型,指定的属性的个数,多一个属性也不行,少一个属性也不行
const obj: { age: number, name: string } = { age: 18, name: 'pengyuyan' };

// 如果想指定属性是可选的(可有可无)
const obj:{
  name:string,
  age?:number
}
obj = {
  name:"pengyuyan"
}

function

声明的函数在调用的时候,参数个数要和声明时候的参数个数保持一致

//没有返回值的函数可以用void声明
// 参数类型定义
const f1 = (name:string,id:number): void => {
  console.log("我是没有返回值的箭头函数");
};

function f2(name:string,id:number):void{
  console.log("我是没有返回值的普通函数");
}

//有返回值的箭头函数声明是这样的
// 返回类型注释
const f3 = (): string => {
  return "pengyuyan=>"
};

//有返回值的普通函数声明是这样的

function f4():string{
   return "pengyuyan"
}


//函数表达式的双向限定
//上述f1其实只对=右侧做了限制,对左侧并没有
//完善一点,可以这样 => 用来表示函数的定义,左输入类型,需要用括号括起来,右输出类型

const f5:(name:string,id:number)=>void = (name:string,id:number): void => {
  console.log("我是没有返回值的箭头函数");
};

// 函数的可选参数
// 注意可选参数要在确定参数后
function f6(name:string,id?:number):string{
   return "pengyuyan"
}

//函数参数默认值
function f7(name:string,id:number=1):string{
   return `${name}--${age}`
}
//此时可选参数不必一定在确定参数后,但是调用有问题
function f8(name:string,sex?:string,age:number=1):string{
   return `${name}--${age}--${sex}`
}
console.log(f8('pengyuyan','male',18))  // "pengyuyan--18--male"

//剩余参数
function f9(...arr:number[]):number[]{
  return arr
}
console.log(f9(1,2,3,4,5)) // [1,2,3,4,5]

特殊类型

any

可以访问它的任何属性,可以将它分配给赋予任意类型的值

let num: any = 666
let anyVal: any
anyVal = 888 // number
anyVal = 'hello' // string

let a;(隐式any) //声明变量不赋值,就是any 等效于let a:any = 10;(显示any)
a = 1
a = 'helloWorld'

let b = string //给 b 变量设置类型string
b = a; //a 是 any 类型,它可以赋值给任意变量 此时 b 的类型也被影响了

unknown

未知的类型TS中所有基础类型的父类型,所有基础类型都能赋值为 unknown类型

let a:unknown;
a = 10;
a = "helloWorld";
console.log(a)  // helloWorld
a.age // error

let b : string  = "pengyuyan" // b 类型: string
console.log(b = a); // error    a 是 unknown,  b 的类型不会被影响

unknown类型直接赋值给其他变量的方法
typeof 进行类型判断
let num1: unknown = 666;
if(typeof num1 === "number") {
  let num2 = num1
}

类型断言
let num1: unknown = 666;
let num2 = num1 as number);
// 或
let num3 = <number>num1;

any 和 unkown 的区别

unknown类型会更加严格:在对 unknown类型的值执行大多数操作之前,不能直接赋值给其他变量,必须将这个 unknown类型的变量断言为具体的类型,才可以继续使用。
而在对 any类型的值执行操作之前,会绕过类型检查,直接可用

let foo: any = 123;
console.log(foo.msg); // 符合TS的语法
let value1: unknown = foo;   // OK
let value2: any = foo;      // OK
let value3: string = foo;   // OK


let bar: unknown = 456; // OK 
console.log(bar.msg); // Error
let value4: unknown = bar;   // OK
let value5: any = bar;      // OK
let value6: string = bar;   // Error

因为bar是一个未知类型(任何类型的数据都可以赋给 unknown 类型),所以不能确定是否有msg属性。不能通过TS语法检测;而 unkown 类型的值也不能将值赋给 any 和 unkown 之外的类型变量

总结: any 和 unknown 都是顶级类型,但是 unknown 更加严格,不像 any 那样不做类型检查,反而 unknown 因为未知性质,不允许访问属性,不允许赋值给其他有明确类型的变量

never 类型

TS中使用 never类型来表示不应该存在的值的类型,例如:

  1. 一个抛出异常的函数
  2. 一个永远不会返回的函数的返回值类型

注意never 类型是任何类型的子类型,可以赋值给任意类型*。但是没有类型是 never类型的子类型,即使是 any类型也不能赋值给 never类型

const a:never;
a = 123 // error
a = (()=>{
   throw new Error('错误')
}) 
  const fn: ()=>never = () => {
      throw new Error('error')
  }
  const [n,setN] = React.useState<number>(1)
  const add: ()=>never = () => {
      while(true){ setN(i=>i+1) }
  }

Enum(枚举)

可以定义带名字的 常量

  1. 枚举的类型 只能stringnumber
  2. 定义的名称不能为 关键字
按枚举成员分类
数字枚举

*注意:

  1. 数字类型
  2. 如果有 默认值,会影响到后面的值
  3. 支持 反向映射
enum Direction {
    Up = 1, // 1
    Down, // 2
    Left, // 3
    Right // 4
}
enum Direction {
    Up, // 0
    Down = 3, // 3
    Left, // 4
    Right // 5
}
// 如上,我们定义了一个数字枚举, Up使用初始化为 1。 其余的成员会从 1开始自动增长。 
enum Direction {
    Up,  // 0
    Down, // 1
    Left, // 2
    Right // 3
}
// 当我们不在乎成员的值的时候,这种自增长的行为是很有用处的,但是要注意每个枚举成员的值都是不同的。
enum Days {Sun = 3, Mon = 1, Tue, Wed, Thu, Fri, Sat};
const date: { id: number, name: string, days: Days } = { id: 1, name: '周三', days: Days.Wed }
console.log(Days["Sun"] === 3); // true
console.log(Days["Wed"] === 3); // true
console.log(Days[3] === "Sun"); // false
console.log(Days[3] === "Wed"); // true

// 如果未手动赋值的枚举项与手动赋值的重复了,TypeScript 是不会察觉到这一点的,但建议尽量避免
字符串枚举

在一个字符串枚举里,每个成员都必须用字符串字面量,或另外一个字符串枚举成员进行初始化
*注意:

  1. 必须要有 默认值
  2. 支持 反向映射
enum Direction {
    Up = "UP",
    Down = "DOWN",
    Left = "LEFT",
    Right = "RIGHT",
}
const a: Direction = Direction.Up  //a = UP
const b: Direction = Direction.Down   //b = DOWN
// 由于字符串枚举没有自增长的行为,字符串枚举可以很好的序列化。 
// 字符串枚举允许你提供一个运行时有意义的并且可读的值,独立于枚举成员的名字。
异构枚举 (不建议)

数字 枚举与 字符串 枚举 混用不建议

反向映射

除了创建一个以 属性名 做为对象成员的对象之外,数字枚举成员(字符串枚举成员没有反向映射)还具有了 反向映射从枚举值到枚举名字

enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};
 
console.log(Days["Sun"] === 0); // true
console.log(Days["Mon"] === 1); // true
console.log(Days["Tue"] === 2); // true
console.log(Days["Sat"] === 6); // true
 
console.log(Days[0] === "Sun"); // true
console.log(Days[1] === "Mon"); // true
console.log(Days[2] === "Tue"); // true
console.log(Days[6] === "Sat"); // true
按声明方式
普通枚举
enum Color {Red, Green, Blue = "blue".length};
// 值由计算所得变为计算所得项 如,"blue".length 就是一个计算所得项
enum Color {Red = "red".length, Green, Blue};
// 上述代码会报错,因为Red是计算项,而Green紧接其后却无法获取初始值.
// 根据官方定义,不带初始化器的枚举要么被放在第一的位置,要么被放在使用了数字常量或其它常量初始化了的枚举后面。
常量枚举 (通过const enum 定义的枚举)
const enum Directions {
    Up,
    Down,
    Left,
    Right
}
 
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
// var directions = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */];
外部枚举

用来描述 已经存在的枚举类型,当前环境中 已经存在的对象 的,这个对象可以存在 任意 的地方,但是一定是 已声明 的。
*注意:不支持 反向映射
参考:https://stackoverflow.com/questions/28818849/how-do-the-different-enum-variants-work-in-typescript

declare enum Enum {
    A = 1,
    B,
    C = 2
}
使用枚举
  1. 通过 枚举的属性 来访问 枚举成员
  2. 通过 枚举的名字 来访问 枚举类型
enum Response {
    No = 0,
    Yes = 1,
}

function respond(recipient: string, message: Response): void {
    // ...
}

respond("Princess Caroline", Response.Yes)
void
  1. 可以用来声明变量,但只能作用在 undefined 身上,null 也不行。只有 tsconfig.jsonstrictNullChecks 属性设置为 false 时,null 才能赋值给 void
  2. 一般用于当一个函数 没有返回值时,TS 会默认他的返回值是 void 类型
const a = ():void => {} // 等价于 const a = () => {}
const b = ():void => { return 1 }  // error
const c = ():void => { return '2' } // error
const d = ():void => { return true } // error
const e = ():void => { return  } // ok
const f = ():void => { return undefined } //ok 
const g:void = 1   // error
const h:void = undefined // error

其他类型

联合类型 |

由两个或多个其他类型组成的类型,表示可能是这些类 型中的任何一种的值。我们将这些类型中的每一种称为联合类型的成员。

function printId(id: number | string) { 
   console.log("Your ID is: " + id); 
}
printId(101); // ok
printId("202"); // ok
printId({ myID: 22342 });  // error

在联合类型中,unknown 类型会吸收 任何 类型。联合类型中有 unknown,那么最终得到的都是 unknown 类型

type a = unknown | null;       // unknown
type b = unknown | undefined;  // unknown
type c = unknown | string;     // unknown
type d = unknown | number[];   // unknown

// 如果至少一种组成类型是 any,联合类型会相当于 any
type e = unknown | any;  // any   
基础类型联合
let a: string | number;
a = 1; //ok 
a= "a"//ok
对象类型联合

只能访问联合中 所有共同成员

interface Women{
  age: number,
  sex: string,
  cry(): void
}
interface Man{
  age: number,
  sex: string,
}
declare function People(): Women | Man;
let people = People();
people.age = 18; // ok
people.cry();// error 非共同成员

交叉类型 &

多种类型的集合。每种类型都可以赋值给 unknown 类型,所以在交叉类型中包含 unknown 不会改变结果

type u1 = unknown & null;       // null
type u2 = unknown & undefined;  // undefined
type u3 = unknown & string;     // string
type u4 = unknown & number[];   // number[]
type u5 = unknown & any;        // any
interface People {
  age: number
}
interface Man{
  sex: string
}
const pengyuyan = (man: People & Man) => {
  console.log(man.age) // 18
  console.log(man.sex) // male
}
pengyuyan({age: 18,sex: 'male'})
同名基础属性合并
type obj = { a: string, c: number }
type obj2 = { b: number, c: string }
type allObj = obj & obj2

const Info: allObj = {
  a: 'hello world',
  b: 7,
  // c 的类型既可以是 string 类型又可以是 number 类型。很明显这种类型是不存在的,所以混入后 c 的类型为 never
  c: 1, // Type 'number' is not assignable to type 'never'   c: never
  c: 'hello', // Type 'string' is not assignable to type 'never'   c: never
}
同名非基础属性合并
interface obj3 { a: number }
interface obj4 { b: string }

interface A {
  x: obj3
}
interface B {
  x: obj4
}
type obj5 = A & B

const Info: obj5 = {
  x: {
  a: 1,
  b: 'hello'
  }
}
console.log(Info) // { x: { "a": 1, "b": "hello" }}

四、interface 和 type 的区别

interface 只能声明 函数/对象

interface obj1 {
	a: number
  b: string
}

interface fn1 {
	() => void
}

type 除了能声明 对象函数,还可以为基础类型声明别名

type a = number | string

五、Class(类)

基本方法

在基本方法中有:静态属性静态方法成员属性成员方法构造器getset 方法

// 类定义方式如下
class obj{
    // 类作用域
    static myName: string = "pengyuyan"  // 静态属性
    name1:string = "男"
    engine:string
    engine3!:string //*在成员属性中,如果不给默认值,并且不使用是会报错的 。不设置默认值的时候加 !  就不会报错 engine3!:string
    // 构造函数
    constructor(engine:string) {
        this.engine = engine
    }
    // 静态方法
    static staticFn = ()=>{
        return '静态方法'
    }
    // 成员方法
    fn2 = () =>{
        return '成员方法'
    }
    // get方法
    get engine2(){
        return this.engine
    }
    // set方法
    set engine2(engine2){
        this.engine = engine2
    }
}
const setObj = new obj('hello')
console.log(obj.myName) //  "pengyuyan"
console.log(obj.staticFn()) // "静态方法"
console.log(setObj.fn2()) // "成员方法"
console.log(setObj.engine2)  // "hello"
console.log(setObj.engine)  // "hello"
// *set方法和get方法时的错误提示:
// error TS1056: Accessors are only available when targeting ECMAScript 5 and higher
// 解决方法:需要编译到 es5 及更高版本时可用

tsc 项目名称  -t es5
tsc Class(类).ts  -t es5
// 类定义方式如下
var obj = /** @class */ (function () {
    // 构造函数
    function obj(engine) {
        // 成员属性
        this.name1 = "男";
        // 成员方法
        this.fn2 = function () {
            return '成员方法';
        };
        this.engine = engine;
    }
    Object.defineProperty(obj.prototype, "engine2", {
        // get方法
        get: function () {
            return this.engine;
        },
        // set方法
        set: function (engine2) {
            this.engine = engine2;
        },
        enumerable: false,
        configurable: true
    });
    // 类作用域
    obj.myName = "pengyuyan"; // 静态属性
    // 静态方法
    obj.staticFn = function () {
        return '静态方法';
    };
    return obj;
}());
var setObj = new obj('hello');
console.log(obj.myName); //  "pengyuyan"
console.log(obj.staticFn()); // "静态方法"
console.log(setObj.fn2()); // "成员方法"
console.log(setObj.engine2); // "hello"
console.log(setObj.engine); // "hello"

只读属性 readonly

  1. 只能在 构造函数中初始化,并且在TS中,只允许将 interfacetypeclass上的属性标识为 readonly
  2. readonly实际上只是在 编译阶段进行代码检查
  3. readonly修饰的词只能在 constructor阶段修改,其他时刻不允许修改
class Person {
    public readonly name:string;  // 字符串 只读
    name2:string

    constructor(name:string){
        this.name = name
        this.name2 = name
    }
    setName(name:string) {
        this.name = name // Cannot assign to 'name' because it is a read-only property.
        this.name2 = name; // ok
    }
}
const name3 = new Person('pengyuyan')
console.log(name3)     // Person: {"name": "pengyuyan", "name2": "pengyuyan"}
console.log(name3.name2)  // pengyuyan
console.log(name3.name)  // pengyuyan

继承 extends

  1. 继承之后,子类会拥有父类的一切属性和方法
  2. 子类也可以自己定义一些方法,如 **getTel() **方法
  3. 子类也可以写与父类相同的方法,这样执行方法的时候会执行子类的方法,叫做方法重写( Child子类中重写了sayName方法)
// 父类
class Person {
  name: string
  age: number

  constructor(name: string, age:number){
    this.name = name
    this.age = age
  }

  getName(){
    console.log(`name是:${this.name}`)
    return this.name
  }

  setName(name: string){
    console.log(`设置name为:${name}`)
    this.name = name
  }
  sayName(){
    console.log(`哈哈哈,我是${this.name}`)
  }
 }

// 子类
class Child extends Person {
  tel: number
  // 如果在子类中写了构造函数,就必须调用父类的构造函数
  constructor(name: string, age: number, tel:number){
   super(name, age)  // super用在子类中,表示当前的父类
      this.tel = tel
   }
  // 子类也可以自己定义一些方法
  getTel(){
    return this.tel
  }
  sayName(){
    // 类的方法中super就表示父类,可以通过super.(父类的方法)调用父类的方法
    super.sayName() 
    console.log("Child")
}
}

let res = new Child("pengyuyan", 18 , 133123456789)
res.setName('pengyuyan') // 设置name为:pengyuyan
console.log(res) // Child {."name": "pengyuyan", "age": 18, "tel": 133123456789 }
console.log(res.age) // 18
console.log(res.getTel()) // 133123456789
res.sayName()
res.getName()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qAZwCqZA-1661916600109)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/feff259796cb47029929efa7841c5e26~tplv-k3u1fbpfcp-zoom-1.image)]

修饰符

  1. public:类中、子类内的任何地方、外部 **都能调用 **
  2. protected:类中、子类内的任何地方都能调用,但 外部不能调用
  3. private:类中可以调用,子类内的任何地方、外部 均不可调用
    class Person {
      public name: string   // 类中、子类内的任何地方、外部 都能调用  
      protected age: number  // 类中、子类内的任何地方都能调用,但外部不能调用 
      private tel: number   // 类中可以调用,子类内的任何地方、外部都不可调用

      constructor(name: string, age:number, tel: number){
        this.name = name
        this.age = age
        this.tel = tel
      }
    }

    class Child extends Person {
      constructor(name: string, age: number, tel: number) {
        super(name, age, tel);
      }

      getName(){
        console.log(`我的name是${this.name},年龄${this.age}`) // "我的name是pengyuyan,年龄18" 
        console.log(`电话是${this.tel}`) // 类中可以调用,子类内的任何地方、外部都不可调用
        console.log(`年龄是${this.age}`)  // 类中可以调用  "年龄是18"   
      }
    }


    const res = new Child('pengyuyan', 18, 133123456789)
    console.log(res.name) // Domesy
    console.log(res.age) // 类中、子类内的任何地方都能调用,但外部不能调用 
    console.log(res.tel) // 类中可以调用,子类内的任何地方、外部都不可调用
    res.getName()

重写和重载

重写

继承父类之后重写父类的方法

class Person{
  setName(name: string){
    return `我的名字是${name}`
  }
}

class Child extends Person{
  setName(name: string){
    return `我的名字是${name}`
  }
}

const newInfo = new Child()
console.log(newInfo.setName('pengyuyan')) // "我的名字是pengyuyan" 

重载

class double{
  setNum(num: string);
  setNum(num: number);
  setNum(num:string | number){
    if(typeof num === 'string'){
      console.log(num + num)
    }else{
      console.log(num*2)
   }
  };
}

const res = new double()
res.setNum('1') // "11" 
res.setNum(1) // 2

abstract

abstrac 关键字来声明一个 抽象类,抽象类中的方法声明的方法叫做 抽象方法。抽象类 不能被直接实例化,只能 被子类继承,而且需要重新实现抽象类中的抽象方法。abstract 还可以修饰属性和存取器(getset

    abstract class Person {
      constructor(public str: string){}
      // 抽象类中的方法也必须是抽象方法
      abstract numMethod(id: number) :void;
    }

    class Child extends Person {
      constructor(str: string) {
        super(str);
        this.str = str
      }
      // 抽象类中的函数
      numMethod(id: number): void {
        console.log(`str 是${this.str},id 是${id}`);
      }
    }

    let a = new Person("pengyuyan") // Cannot create an instance of an abstract class
    let b = new Child("pengyuyan");

    b.numMethod(7) // str 是pengyuyan,id 是7

六、断言

类型断言

可以手动指定一个值的类型,不需要ts 去判断。
*注意:在tsx中必须使用 **值 as 类型 **的语法。

// 值 as 类型   
let str: any = 'pengyuyan';
let num: number = (str as string).length;

// <类型>值
let str2:any = 'pengyuyan'
let num2: number = (<string>str2).length; // 会报错 react

将任何一个类型断言为 any ( 不能滥用 as any)

let obj:object = {};
obj.num = 1;   // error  obj并没有num属性,所以就需要将 obj 断言为any
// 改为
(obj as any).num = 1;  
// *注意:不能滥用as any

将any断言为一个具体的类型

let obj:object = {};
function fn1(key: string): any {
    return (obj as any).name = key;
}
// fn1()方法执行以后返回的是any类型

interface Animal  {
    name:string;
    fn2():void;
}
let a = fn1("pengyuyan") as Animal;
// 将其断言为Animal类型

将一个联合类型断言为其中一个类型

注意:类型断言只是欺骗编译器,让编译器可以编译通过,但是如果强制类型转换,在执行*的过程中会报错

interface obj1 {
    name: string;
    fn1(): void;
}
interface obj2 {
    name: string;
    fn2(): void;
}

function isObj(obj3: obj1 | obj2):string {
    return obj3.name   // 只能访问联合属性中共有的属性和方法
    
    // 断言,强制类型转换会报错
     return (typeof (obj3 as obj2).fn2) === 'function')
}

const obj4:obj1 = {
    name:"obj1",
    fn1(){
        console.log("fn1xxxxx");
    }
}
function fn3(animal:obj1|obj2){
    (animal as obj2).fn2();
}
fn3(obj4);  // animal.fn2 is not a function 

将一个父类断言为更加具体的子类

//类有继承关系
class Father extends Error {  //抽象的父类 Error,这样这个函数就能接受 Error 或它的子类作为参数了
  num1: number = 1;  
}

class Child extends Error {
  num2: number = 2;  
}

function fnType (error: Error) {
// 父类 Error 中没有 num1 属性,所以需要使用类型断言获取 
  if (typeof (error as Father).num1 === 'number') {
    return true;      
  }  
  return false;
}

非空断言

let myName:string = 'pengyuyan'
console.log(myName.trim())  // 为undefined时候报错
// 改为
console.log(myName!.trim())

欢迎留言指正

学习资源:TypeScript 入门教程 一篇让你完全够用TS的指南
学习的代码整理好会同步到 gitlab

相关文章:

  • 将路径中的“\\”换成“/”的方法
  • (一)Dubbo快速入门、介绍、使用
  • java-多线程,一个线程执行完毕,其他线程跳出运算-利用线程组ThreadGroup(子线程中执行当前线程组的interrupt方法)
  • 三分钟读懂什么是动作捕捉
  • Android—Surface,ViewRootImpl.relayoutWindow
  • <C++>详解string类
  • (一) springboot详细介绍
  • (一)UDP基本编程步骤
  • (附源码)spring boot公选课在线选课系统 毕业设计 142011
  • 新作文杂志新作文杂志社新作文编辑部2022年第8期目录
  • d的nan讨论4
  • Python 运算符和表达式
  • 【LeetCode】2022 8月 每日一题
  • AcWing-1-递归实现指数型枚举
  • 易基因|文献科普:DNA甲基化测序揭示DNMT3a在调控T细胞同种异体反应中的关键作用
  • JS 中的深拷贝与浅拷贝
  • [LeetCode] Wiggle Sort
  • 【vuex入门系列02】mutation接收单个参数和多个参数
  • 10个确保微服务与容器安全的最佳实践
  • 2019年如何成为全栈工程师?
  • JS+CSS实现数字滚动
  • JS进阶 - JS 、JS-Web-API与DOM、BOM
  • Less 日常用法
  • mysql 5.6 原生Online DDL解析
  • mysql中InnoDB引擎中页的概念
  • Node + FFmpeg 实现Canvas动画导出视频
  • Python 反序列化安全问题(二)
  • ReactNativeweexDeviceOne对比
  • Spring声明式事务管理之一:五大属性分析
  • swift基础之_对象 实例方法 对象方法。
  • UMLCHINA 首席专家潘加宇鼎力推荐
  • 第十八天-企业应用架构模式-基本模式
  • 分布式事物理论与实践
  • 聊聊directory traversal attack
  • 如何利用MongoDB打造TOP榜小程序
  • 三栏布局总结
  • 删除表内多余的重复数据
  • 深度学习入门:10门免费线上课程推荐
  • 使用putty远程连接linux
  • 一个完整Java Web项目背后的密码
  • gunicorn工作原理
  • 如何正确理解,内页权重高于首页?
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • !!【OpenCV学习】计算两幅图像的重叠区域
  • #QT(TCP网络编程-服务端)
  • #单片机(TB6600驱动42步进电机)
  • (k8s中)docker netty OOM问题记录
  • (NO.00004)iOS实现打砖块游戏(九):游戏中小球与反弹棒的碰撞
  • (八)c52学习之旅-中断实验
  • (八十八)VFL语言初步 - 实现布局
  • (附源码)spring boot儿童教育管理系统 毕业设计 281442
  • (附源码)小程序 交通违法举报系统 毕业设计 242045
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理 第13章 项目资源管理(七)
  • (十) 初识 Docker file
  • (学习日记)2024.04.04:UCOSIII第三十二节:计数信号量实验