一篇博客教你掌握 typescript

文章目录

一、TypeScript简介

  1. TypeScript是JavaScript的超集。
  2. 它对JS进行了扩展,向JS中引入了类型的概念,并添加了许多新的特性。
  3. TS代码需要通过编译器编译为JS,然后再交由JS解析器执行。
  4. TS完全兼容JS,换言之,任何的JS代码都可以直接当成JS使用。
  5. 相较于JS而言,TS拥有了静态类型、更加严格的语法、更强大的功能;TS可以在代码执行前就完成代码的检查,减小了运行时异常的出现的几率;TS代码可以编译为任意版本的JS代码,可有效解决不同JS运行环境的兼容问题;同样的功能,TS的代码量要大于JS,但由于TS的代码结构更加清晰,变量类型更加明确,在后期代码的维护中TS却远远胜于JS。

二、TypeScript 开发环境搭建

1. 下载并安装 Node.js
2. 使用npm全局安装typescript:进入命令行,输入:

cnpm install typescript -g

3. 检查是否安装成功:

tsc -v

4. 创建一个ts文件
5. 使用tsc对ts文件进行编译:
进入命令行,进入ts文件所在目录,执行命令:tsc xxx.ts
例如:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210114090848659.png)

在这里插入图片描述

三、基本类型

1. 类型声明
  • 类型声明是TS非常重要的一个特点,通过类型声明可以指定TS中变量(参数、形参)的类型

  • 指定类型后,当为变量赋值时,TS编译器会自动检查值是否符合类型声明,符合则赋值,否则报错

  • 简而言之,类型声明给变量设置了类型,使得变量只能存储某种类型的值

  • 语法:

let 变量: 类型;
let 变量: 类型 = 值;
function fn(参数: 类型, 参数: 类型): 类型{

}

// 声明一个变量a,同时指定它的类型为number
let a: number;

// a 的类型设置为了number,在以后的使用过程中a的值只能是数字
a = 10;
a = 33;
a = 'hello'; // 此行代码会报错,因为变量a的类型是number,不能赋值字符串

由下图可见,指定 a 的类型为 number 后,再为其赋值为 “hello” ,会显示报错。
在这里插入图片描述
下面代码指定传入两个参数,参数类型为 number,且返回值也为number,若不符合则会报错。

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

let result = sum(123, 456);

JS中的函数是不考虑参数的类型和个数的,如果多填入一个参数也不会报错。但是 typescript 会:
在这里插入图片描述

2. 自动类型判断

TS拥有自动的类型判断机制,当对变量的声明和赋值是同时进行的,TS编译器会自动判断变量的类型。如果你的变量的声明和赋值时同时进行的,可以省略掉类型声明。

// 如果变量的声明和赋值是同时进行的,TS可以自动对变量进行类型检测
let c = false;
c = true;
3. 类型

在这里插入图片描述
(1)number

let a: number = 6;

(2)boolean

let isDone: boolean = false;

(3)string

let color: string = "blue";
let name: string = 'K';
let sentence: string = `Hello, my name is ${name}`;
let sentence1: string = "Hello, my name is" + name;
//console.log(sentence)

(4)字面量

  • 可以直接使用字面量进行类型声明
let a: 10;
a = 10;
  • 可以使用 | 来连接多个类型(联合类型),确定变量的取值范围
let b: "male" | "female";
b = "male";
b = "female";
let c: boolean | string;
c = true;
c = 'hello';

(5)any 表示的是任意类型

  • 一个变量设置类型为any后相当于对该变量关闭了TS的类型检测。使用TS时,不建议使用any类型
let d: any;
let list: any[] = [1, true, "free"];
list[1] = 100;
console.log(list)

在这里插入图片描述

  • 声明变量如果不指定类型,则TS解析器会自动判断变量的类型为any (隐式的any)
let d;
d = 10;
d = 'hello';
d = true;

(6)unknown 表示未知类型的值

let e: unknown;
e = 10;
e = "hello";
e = true;

(7)any unknown 区别

  • any 类型的变量,可以赋值给任意变量
let d;
d = true;
let s:string;
s = d;  // d的类型是any,它可以赋值给任意变量
  • unknown类型的变量,不能直接赋值给其他变量。unknown 实际上就是一个类型安全的any
let e: unknown;
e = 'hello';
let s:string;
s = e;

由下图可见,会报错。
在这里插入图片描述
可以将 s = e,改成下面代码:

if(typeof e === "string"){
    s = e;
}

(8)类型断言:可以用来告诉解析器变量的实际类型

  • 语法:
    • 变量 as 类型
    • <类型>变量
s = e as string;
s = <string>e;

(9)void 表示没有任何类型,表示空,以函数为例,就表示没有返回值的函数

function fn(): void{}

但是返回值为 undefined 或 null 时,不会报错:
在这里插入图片描述
在这里插入图片描述
声明一个void类型的变量没有什么大用,因为你只能为它赋予undefined和null:

let unusable: void = undefined;

(10)never 表示永远不会返回结果

例如, never类型是那些总是会抛出异常根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型。

function fn2(): never{
    throw new Error('报错了!');
}

返回值为 undefined 或 null 时,会报错:
在这里插入图片描述

在这里插入图片描述

(11)object 表示一个js对象

let a: object;
a = {};
a = function () {
};

(12){} 用来指定对象中可以包含哪些属性

  • 语法:{属性名:属性值,属性名:属性值}
  • 在属性名后边加上?,表示属性是可选的,可写可不写
let b: {name: string, age?: number};
b = {name: 'Tom', age: 18};

(13)[propName: string]: any 表示任意类型的属性

let c: {name: string, [propName: string]: any};
c = {name: 'kk', age: 18, gender: '男'}

(14)设置函数结构的类型声明

语法:(形参:类型, 形参:类型 …) => 返回值

let d: (a: number ,b: number)=>number;
d = function (n1: number, n2: number): number{
    return 10;
}

(15)array

  • 数组的类型声明:
    • 类型[]
    • Array<类型>
// string[] 表示字符串数组
let e: string[];
e = ['a', 'b', 'c'];

// number[] 表示数值数值
let f: number[];

let g: Array<number>;
g = [1, 2, 3];

(16)tuple 元组,即固定长度的数组

语法:[类型, 类型, 类型…] 一般不会太长

元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。 比如,你可以定义一对值分别为 string 和 number 类型的元组。

let h: [string, number];
h = ['hello', 123];

(17)enum 枚举

enum是TypeScript的少数功能之一,它不是JavaScript的类型级扩展。使用枚举类型可以为一组数值赋予友好的名字。

下面代码中,有一个数字枚举,其中 Red 被初始化为 0,其他的成员从这0 开始自动递增。换句话说,Color.Red的值是 0,Green 是 1,Blue是2。

enum Color {Red, Green, Blue}
let c: Color = Color.Green;

在这里插入图片描述

所以默认情况下,是从0开始为元素编号。

也可以手动的指定成员的数值。 例如,改成从 1开始编号:

enum Color {Red = 1, Green, Blue}
let c: Color = Color.Green;

或者,全部都采用手动赋值:

enum Color {Red = 1, Green = 2, Blue = 4}
let c: Color = Color.Green;

枚举类型提供的一个便利是你可以由枚举的值得到它的名字。 例如,我们知道数值为2,但是不确定它映射到Color里的哪个名字,我们可以查找相应的名字:

enum Color {Red = 1, Green, Blue}
let colorName: string = Color[2];

console.log(colorName);  // 显示'Green',因为第一行代码里它的值是2

其他示例:

enum Gender{
    Male,
    Female
}

let i: {name: string, gender: Gender};
i = {
    name: 'Tom',
    gender: Gender.Male
}

(18)Null 和 Undefined

在TS里,undefined和null两者各自有自己的类型分别叫做undefined和null。 和 void相似,它们的本身的类型用处不是很大。

let u: undefined = undefined;
let n: null = null;

默认情况下null和undefined是所有类型的子类型,也就是说你可以把 null和undefined赋值给number类型的变量。

然而,当你指定了strictNullChecks标记,null和undefined只能赋值给void和它们自己。 这能避免很多常见的问题。

也许在某处你想传入一个 string 或 null 或 undefined,你可以使用联合类型string | null | undefined

(19)& 表示同时

let j: { name: string } & { age: number };
j = {name: 'Tom', age: 18};

(20)类型的别名

type myType = 1 | 2 | 3 | 4 | 5;
let k: myType;
let l: myType;

k = 2;

四、编译选项

自动编译文件

编译文件时,使用 -w 指令后,TS编译器会自动监视文件的变化,并在文件发生变化时对文件进行重新编译。

tsc xxx.ts -w

自动编译整个项目

先在项目根目录下创建一个ts的配置文件 tsconfig.json,tsconfig.json是一个JSON文件,添加配置文件后,只需只需 tsc 命令即可完成对整个项目的编译。tsconfig.json 配置选项:

1. include:定义希望被编译文件所在的目录
  • 路径:

** 表示任意目录
*表示任意文件

示例:

"include":["src/**/*", "tests/**/*"]
2. exclude:定义不需要被编译的文件目录

默认值:[“node_modules”, “bower_components”, “jspm_packages”]

示例:

src下test目录下的文件都不会被编译

"exclude": ["./src/test/**/*"]
3. extends:定义被继承的配置文件

示例:

当前配置文件中会自动包含config目录下base.json中的所有配置信息。

"extends": "./configs/base"
4. files:指定被编译文件的列表,只有需要编译的文件少时才会用到

示例:

列表中的文件都会被TS编译器所编译

"files": [
  "core.ts",
  "sys.ts",
  "types.ts",
  "scanner.ts",
  "parser.ts",
  "utilities.ts",
  "binder.ts",
  "checker.ts",
  "tsc.ts"
]
5. compilerOptions:编译选项是配置文件中非常重要也比较复杂的配置选项,在compilerOptions中包含多个子选项,用来完成对编译的配置。
项目选项

(1)target:用来指定ts被编译为的ES的版本

  • 可选值:

ES3(默认)、ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext

  • 示例:如下设置,我们所编写的ts代码将会被编译为ES6版本的js代码
"compilerOptions": {
  "target": "ES6"
}

(2)module:指定要使用的模块化的规范

  • 可选值:

CommonJS、UMD、AMD、System、ES2020、ESNext、None

  • 示例:
"compilerOptions": {
  "module": "CommonJS"
}

(3)lib:用来指定项目中要使用的库

  • 可选值:

‘es5’, ‘es6’, ‘es2015’, ‘es7’, ‘es2016’, ‘es2017’, ‘es2018’, ‘es2019’, ‘es2020’, ‘esnext’, ‘dom’, ‘dom.iterable’, ‘webworker’, ‘webworker.importscripts’, ‘webworker.iterable’, ‘scripthost’, ‘es2015.core’, ‘es2015.collection’, ‘es2015.generator’, ‘es2015.iterable’, ‘es2015.promise’, ‘es2015.proxy’, ‘es2015.reflect’, ‘es2015.symbol’, ‘es2015.symbol.wellknown’, ‘es2016.array.include’, ‘es2017.object’, ‘es2017.sharedmemory’, ‘es2017.string’, ‘es2017.intl’, ‘es2017.typedarrays’, ‘es2018.asyncgenerator’, ‘es2018.asynciterable’, ‘es2018.intl’, ‘es2018.promise’, ‘es2018.regexp’, ‘es2019.array’, ‘es2019.object’, ‘es2019.string’, ‘es2019.symbol’, ‘es2020.bigint’, ‘es2020.promise’, ‘es2020.sharedmemory’, ‘es2020.string’, ‘es2020.symbol.wellknown’, ‘es2020.intl’, ‘esnext.array’, ‘esnext.symbol’, ‘esnext.asynciterable’, ‘esnext.intl’, ‘esnext.bigint’, ‘esnext.string’, ‘esnext.promise’, ‘esnext.weakref’

  • 示例:
"lib": ["es6", "dom"]

(4)outDir:用来指定编译后文件所在的目录

  • 示例:编译后的js文件将会生成到dist目录
"outDir": "./dist",

(5)outFile:将代码合并为一个文件

  • 设置outFile后,所有的全局作用域中的代码会合并到同一个js文件,如果module制定了None、System或AMD则会将模块一起合并到文件之中
  • 示例:
"outFile": "./dist/app.js"

(6)allowJs:是否对js文件编译,默认是false

  • 示例:
"allowJs": true,

(7)checkJs:否检查js代码是否符合语法规范,默认是false

  • 示例:
"checkJs": true,

(8)removeComments:是否删除注释,默认值:false

  • 示例:
"removeComments": true,

(9)noEmit:不生成编译后的文件,默认值:false

  • 示例:
"noEmit": false,

(10)noEmitOnError:当有错误时不生成编译后的文件

  • 示例:
"noEmitOnError": true,
严格检查

(1)strict:所有严格检查的总开关

  • 示例:
"strict": true,

(2)alwaysStrict:用来设置编译后的文件是否使用严格模式,默认false

  • 示例:
"alwaysStrict": true,

(3)noImplicitAny:不允许隐式的any类型

  • 示例:
"noImplicitAny": true,

(4)noImplicitThis:不允许不明确类型的this

  • 示例:
"noImplicitThis": true,

(5)strictNullChecks:严格的检查空值

  • 示例:
"strictNullChecks": true

五、使用 webpack 打包 ts 代码

1. 初始化项目

进入项目根目录,执行下面的命令,创建package.json文件

npm init -y

2. 下载构建工具
  • 共安装了7个包
    • webpack:构建工具webpack
    • webpack-cli: webpack的命令行工具
    • webpack-dev-server: webpack的开发服务器
    • typescript: ts编译器
    • ts-loader: ts加载器,用于在webpack中编译ts文件
    • html-webpack-plugin:webpack中html插件,用来自动创建html文件
    • clean-webpack-plugin:webpack中的清除插件,每次构建都会先清除目录

npm i -D webpack webpack-cli webpack-dev-server typescript ts-loader html-webpack-plugin clean-webpack-plugin

3. 根目录下创建webpack的配置文件webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");

module.exports = {
   optimization:{
       minimize: false // 关闭代码压缩,可选
   },

   entry: "./src/index.ts",
   
   devtool: "inline-source-map",
   
   devServer: {
       contentBase: './dist'
   },

   output: {
       path: path.resolve(__dirname, "dist"),
       filename: "bundle.js",
       environment: {
           arrowFunction: false // 关闭webpack的箭头函数,可选
       }
   },
   
   // 用来设置引用模块
   resolve: {
       extensions: [".ts", ".js"]
   },
   
   module: {
       rules: [
           {
               test: /\.ts$/,
               use: {
                  loader: "ts-loader"     
               },
               exclude: /node_modules/
           }
       ]
   },

   plugins: [
       new CleanWebpackPlugin(),
       new HtmlWebpackPlugin({
           title:'TS测试'
       }),
   ],
   
}
4. 根目录下创建tsconfig.json,配置可以根据自己需要
{
   "compilerOptions": {
       "target": "ES2015",
       "module": "ES2015",
       "strict": true
   }
}
5. 修改package.json添加如下配置
"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1",
  "build": "webpack",
  "start": "webpack serve --open chrome.exe"
},
6. 在src下创建ts文件,并在命令行执行npm run build对代码进行编译,或者执行npm start来启动开发服务器。

六、Babel

除了webpack,开发中还经常需要结合babel来对代码进行转换以使其可以兼容到更多的浏览器。

1. 安装依赖包:
  • 共安装了4个包,分别是:
    • @babel/core:babel的核心工具
    • @babel/preset-env:babel的预定义环境
    • @babel-loader:babel在webpack中的加载器
    • core-js:core-js用来使老版本的浏览器支持新版ES语法

npm i -D @babel/core @babel/preset-env babel-loader core-js

2. 修改webpack.config.js配置文件

使用ts编译后的文件将会再次被babel处理,使得代码可以在大部分浏览器中直接使用,可以在配置选项的targets中指定要兼容的浏览器版本。

module: {
    // 指定要加载的规则
    rules: [
        {
            // test指定的是规则生效的文件
            test: /\.ts$/,
            // 要使用的loader
            use: [
                 // 配置babel
                 {
                     // 指定加载器
                     loader:"babel-loader",
                     // 设置babel
                     options: {
                         // 设置预定义的环境
                         presets:[
                             [
                                 // 指定环境的插件
                                 "@babel/preset-env",
                                 // 配置信息
                                 {
                                     // 要兼容的目标浏览器
                                     targets:{
                                         "chrome":"58",
                                         "ie":"11"
                                     },
                                     // 指定corejs的版本
                                     "corejs":"3",
                                     // 使用corejs的方式 "usage" 表示按需加载
                                     "useBuiltIns":"usage"
                                 }
                             ]
                         ]
                     }
                 },
                'ts-loader'
            ],
            // 要排除的文件
            exclude: /node-modules/
        }
    ]
},

七、什么是面向对象

面向对象简而言之就是程序之中所有的操作都需要通过对象来完成。

在程序中所有的对象都被分成了两个部分:数据和功能,以人为例,人的姓名、性别、年龄、身高、体重等属于数据,人可以说话、走路、吃饭、睡觉这些属于人的功能。数据在对象中被成为属性,而功能就被称为方法。所以简而言之,在程序中一切皆是对象。

八、类(class)

1. 使用class关键字定义类
class Person{

}
  • 对象中主要包含了两个部分:属性、方法
2. 定义属性:
  • 直接定义的属性是实例属性,需要通过对象的实例去访问:

const per = new Person();
per.name

class Person{
	name = 'kk';
	age = 18;
}
const per = new Person();
console.log(per);
console.log(per.name, per.age);

在这里插入图片描述

  • 使用static开头的属性是静态属性(类属性),可以直接通过类去访问

Person.age

class Person{
	name = 'kk';
	static age = 18;
}
console.log(Person.age);

在这里插入图片描述

  • readonly开头的属性表示一个只读的属性,无法修改
3. 定义方法
class Person{
	sayHello(){
	    console.log('Hello 大家好!');
	}
}
const per = new Person();
per.sayHello();

在这里插入图片描述

4. constructor 构造函数,在对象创建时调用
  • 在实例方法中,this就表示当前当前的实例,在构造函数中当前对象就是当前新建的那个对象,可以通过this向新建的对象中添加属性。
  • 在方法中可以通过this来表示当前调用方法的对象。
class Dog{
    name: string;
    age: number;

    // constructor 被称为构造函数
    //  构造函数会在对象创建时调用
    constructor(name: string, age: number) {
        // 在实例方法中,this就表示当前当前的实例
        // 在构造函数中当前对象就是当前新建的那个对象
        // 可以通过this向新建的对象中添加属性
        this.name = name;
        this.age = age;
    }

    bark(){
        console.log('汪汪汪!');
        // 在方法中可以通过this来表示当前调用方法的对象
        console.log(this.name);
    }
}

const dog = new Dog('小黑', 4);
const dog2 = new Dog('小白', 2);

console.log(dog);
console.log(dog2);

dog2.bark();

在这里插入图片描述

5. extends 继承
  • Dog extends Animal
  • 此时,Animal被称为父类,Dog被称为子类
  • 使用继承后,子类将会拥有父类所有的方法和属性
  • 通过继承可以将多个类中共有的代码写在一个父类中,这样只需要写一次即可让所有的子类都同时拥有父类中的属性和方法
  • 如果希望在子类中添加一些父类中没有的属性或方法直接加就行
    * 如果在子类中添加了和父类相同的方法,则子类方法会覆盖掉父类的方法,这种子类覆盖掉父类方法的形式,我们称为方法重写
(function (){
    // 定义一个Animal类
    class Animal{
        name: string;
        age: number;

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

        sayHello(){
            console.log('动物在叫~');
        }
    }

    // 定义一个表示狗的类
    // 使Dog类继承Animal类
    class Dog extends Animal{

        run(){
            console.log(`${this.name}在跑~~~`);
        }

        sayHello() {
            console.log('汪汪汪汪!');
        }

    }

    // 定义一个表示猫的类
    // 使Cat类继承Animal类
    class Cat extends Animal{
        sayHello() {
            console.log('喵喵喵喵!');
        }
    }

    const dog = new Dog('旺财', 5);
    const cat = new Cat('咪咪', 3);
    console.log(dog);
    dog.sayHello();
    dog.run();
    console.log(cat);
    cat.sayHello();
})();

在这里插入图片描述

6. super 关键字
  • 如果在子类中写了构造函数,在子类构造函数中必须对父类的构造函数进行调用
  • 在类的方法中 super就表示当前类的父类
(function () {
    class Animal {
        name: string;

        constructor(name: string) {
            this.name = name;
        }

        sayHello() {
            console.log('动物在叫~');
        }
    }

    class Dog extends Animal{

        age: number;

        constructor(name: string, age: number) {
            // 如果在子类中写了构造函数,在子类构造函数中必须对父类的构造函数进行调用
            super(name); // 调用父类的构造函数
            this.age = age;
        }

        sayHello() {
            // 在类的方法中 super就表示当前类的父类
            super.sayHello();

            console.log('汪汪汪汪!');
        }

    }

    const dog = new Dog('旺财', 3);
    dog.sayHello();
})();

在这里插入图片描述

7. abstract 抽象类
  • 以abstract开头的类是抽象类,抽象类和其他类区别不大,只是不能用来创建对象,抽象类就是专门用来被继承的类。
  • 抽象类中可以添加抽象方法,抽象方法只能定义在抽象类中,子类必须对抽象方法进行重写
(function () {
    abstract class Animal {
        name: string;

        constructor(name: string) {
            this.name = name;
        }

        // 定义一个抽象方法
        // 抽象方法使用 abstract开头,没有方法体
        // 抽象方法只能定义在抽象类中,子类必须对抽象方法进行重写
        abstract sayHello():void;
    }

    class Dog extends Animal{
        sayHello() {
            console.log('汪汪汪汪!');
        }
    }

    class Cat extends Animal{
        sayHello() {
            console.log('喵喵喵喵!');
        }
    }

    const dog = new Dog('旺财');
    dog.sayHello();
})();

在这里插入图片描述

8. interface 接口
  • 接口用来定义一个类结构,用来定义一个类中应该包含哪些属性和方法,同时接口也可以当成类型声明去使用。
interface myInterface {
    name: string;
    age: number;
    gender: string;
}
const obj: myInterface = {
    name: 'sss',
    age: 111,
    gender: '男'
};
  • 接口可以在定义类的时候去限制类的结构,接口中的所有的属性都不能有实际的值,接口只定义对象的结构,而不考虑实际值,在接口中所有的方法都是抽象方法。
interface myInter{
    name: string;

    sayHello():void;
}
  • 定义类时,可以使类去实现一个接口,实现接口就是使类满足接口的要求。
interface myInter{
    name: string;
    sayHello():void;
}
class MyClass implements myInter{
    name: string;

    constructor(name: string) {
        this.name = name;
    }

    sayHello(){
        console.log('大家好~~');
    }
}
9. TS可以在属性前添加属性的修饰符
  • public 修饰的属性可以在任意位置访问(修改) 默认值
  • private 私有属性,私有属性只能在类内部进行访问(修改),通过在类中添加方法使得私有属性可以被外部访问
  • protected 受保护的属性,只能在当前类和当前类的子类中访问(修改)
10. getter方法用来读取属性,setter方法用来设置属性,它们被称为属性的存取器
(function (){
    // 定义一个表示人的类
    class Person{
        private _name: string;
        private _age: number;

        constructor(name: string, age: number) {
            this._name = name;
            this._age = age;
        }
        // TS中设置getter方法的方式
        get name(){
            return this._name;
        }

        set name(value){
            this._name = value;
        }

        get age(){
            return this._age;
        }

        set age(value){
            if(value >= 0){
                this._age = value
            }
        }
    }

    const per = new Person('xx', 18);

    per.name = 'kk';
    per.age = -33;

    console.log(per);
})();

在这里插入图片描述

11. 泛型
  • 在定义函数或是类时,如果遇到类型不明确就可以使用泛型
function fn<T>(a: T): T{
    return a;
}

let result = fn(10); // 不指定泛型,TS可以自动对类型进行推断
let result2 = fn<string>('hello'); // 指定泛型
  • 泛型可以同时指定多个
function fn2<T, K>(a: T, b: K):T{
    console.log(b);
    return a;
}
fn2<number, string>(123, 'hello');
  • T extends Inter 表示泛型T必须是Inter实现类(子类)
interface Inter{
    length: number;
}

// T extends Inter 表示泛型T必须是Inter实现类(子类)
function fn3<T extends Inter>(a: T): number{
    return a.length;
}
class MyClass<T>{
    name: T;
    constructor(name: T) {
        this.name = name;
    }
}

const mc = new MyClass<string>('王五');

整理这篇博客自己都快写废了o(╥﹏╥)o

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值