TypeScript入门笔记

这篇博客详细介绍了TypeScript的基础知识,包括安装、数据类型(如数字、字符串、数组、对象、联合类型等)、函数、类、接口、泛型和模块化。重点讲解了数据类型,如null、undefined、any、unknown、void、never和enum,并通过实例展示了如何使用。此外,还探讨了函数的定义、重载和箭头函数,以及类的继承、修饰符、静态属性和方法。最后,介绍了接口的定义、用途和泛型的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

TypeScript入门笔记

第一章 TypeScript简介

1.1 TypeScript简介

TypeScript 是由微软开发的一款开源的编程语言,TypeScript 是 Javascript 的超集,遵循最新的 ES6、ES5 规范,TypeScript 扩展了 JavaScript 的语法。TypeScript 更像后端 Java、C#这样的面向对象语言,可以让 JavaScript 开发大型企业项目。谷歌也在大力支持 Typescript 的推广,谷歌的 angular2.x+ 就是基于 Typescript 语法,最新的 Vue 、React 也可以集成 TypeScript。Nodejs 框架中的 Nestjs、midway 中用的就是 TypeScript 语法。

TypeScript = Type + JavaScript(为JS添加了类型系统)

1.2 TypeScript安装

安装步骤:
1.打开cmd命令
2.输入安装命令:npm i -g typescript 敲回车,来安装(可以添加版本号)
3.安装查看: tsc -v / tsc --version

1.3 TypeScript开发工具

开发工具使用:Visual Studio Code,已安装汉化插件

第二章 TypeScript数据类型

变量格式一:

let 变量名:变量类型 = 初始化值;

变量格式二:

let 变量名:变量类型 | undefined;
变量名= 变量值

2.1 数字类型

  • 除了支持十进制和十六进制字面量,TypeScript还支持ECMAScript 2015中引入的二进制和八进制字面量。
let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;
let binaryLiteral: number = 0b1010;
let octalLiteral: number = 0o744;

2.2 布尔类型

  • 布尔值 boolean true/false值
let isDone: boolean = false;

2.3 字符串类型

  • string 单引号(推荐)或双引号或``都可以
let name: string = "bob";
name = "smith";

2.4 数组类型

  • 数组; 开发中, 数组中的元素为同一类型
  • 语法1:类型[]
// 表示数值数组
let list: number[];
let list: Array<number>;

let list: number[] = [1, 2, 3];
  • 语法2:使用泛型写法,Array<元素类型>
// 表示字符串数组
let list: string[];
let list: Array<string>    

let list: Array<number> = ['a', 'b', 'c'];

扩展: 申明二维数组
let arr:number[][] = [
[1,2,3],[7,8,9]
]

2.5 对象类型

对象类型的基本使用
  • js中属于对象的太多,添加object后等于是没有添加类型限制,开发很少用
  • 示例1:
// {}也表示对象,表示变量o必须是一个对象类型,在其中可以指定属性类型
// 以下示例表示对象o中只能有指定的属性名称和类型,以及个数
// 在属性名后面加?,表示该属性可选
let o: {
	name: string, 
	age: number,
	sex?: string
};

o = {name: '孙悟空',age: 18} // ok
o = {name: '孙悟空'} // 报错,少了一个age属性
o = {name: '孙悟空',age: 18,sex: '男'} // ok
  • 示例2:
// 需求:在一个对象中,我只有一个属性是有要求的,其他的属性名称、类型、个数都未知
let o: {
	name: string, 
	[propertyName: string]: any
}
/*
* 以上代码,[propertyName: string] 表示属性名是string(对象的属性名都是字符串类型)
* [propertyName: string]: any 表示该对象中的属性是任意类型,
*						如果any是string,表示该对象中的属性都必须是string类型
*/
  • 实例3:
function getObj(obj: object):object {  
	// do something  
	return {    
		name:"卡卡西"  
	}
}

console.log(getObj({name:"佐助"}))
console.log(getObj(new String('字符串')))
对象类型中的函数写法

指定对象中, 函数的类型

1.写法一:sayHi(name:string):void

const user: {  
	name:string  
	sayHi(name:string):void
}  

user = {  
	name:'张三'  
	sayHi(name) {    
		console.log('你好,我叫' + name)  
	}
}

2.写法二: add(n1:number, n2:number) => number

const user: {  
	name:string  
	add(n1:number, n2:number) => number
}

user = { 
	name:'李四'  
	add: function(a, b){    
		return a+b  
	}
}

2.7 null 类型

  • 表示此处不应该有值, 没有值了
  • 在TS中, 可以给已有类型的引用数据类型变量, 重新赋值null
let n: null = null 

2.8 undefined类型

  • 表示此处应该有值, 但是现在没有值
  • 申明了一个变量, 但是未赋值, 这个变量就是undefined
  • 在TS中, 可以给已有类型的基本数据类型变量, 重新赋值undefined
let u:undefined = undefined

TS新增类型

2.9 联合类型

  • 把多个类型联合为一个类型 (表示取值可以为多种类型中的一种)
  • |隔开
// 表示入参param可以是number或者string类型
// 出参为string类型
function getSomeThing(param: number|string):string {    
	return param+''
}

getSomeThing(123)
getSomeThing("字符串")
type MyType = 1 | 2 | 3 | 4 | 5;

let a: MyType = 2;
let b: MyType = 4;
// 数组中,既可以有字符串,也可以有数字
let arr:(number|string)[]

arr = [123, '哈哈']a
rr = [66, 88, 99]

2.10 any类型

  • 任意类型(any可略) , 尽量不要使用any
  • 设置为该类型后等于对变量关闭了TS的类型检测, 直接让它们通过编译阶段的检查
  • 可以赋值给任意类型变量
// eg1:多次赋值均不报错
let a: any = 123
a = "str"a = true

// eg1:它可以赋值给其他任意类型,使其他类型也称为any类型
// 简单理解就是b是any类型,经过下面赋值,使a也成了any类型
let b:number = 123
b = a

2.11 unknown类型

  • 未知类型的值; 编码中,尽量使用unknown代替any
  • 和any的异同点:
    1.同:都是可以多次赋值不同类型的值
    2.异:any可以赋值给任意任意类型的值,使其也称为any的值,但是unknown不能直接赋值其他类型的值
  • 一般来说,这个类型并不是开发者手写的,是网络传来的,需要配和断言使用(在使用的时候需要明确这个变量的类型,可以多次指定类型)
type A = {name:string}
type B = {age:number}
// 模拟ajax传递过来的数据
let c: unknown = JSON.parse("{'name':"Tom"}") 

let var1 = (c as A).name
let  var2 = (c as B).age

2.12 void 类型

  • 空值 , 用于函数返回值 表示函数没有返回值(常用)
  • 实际编码中,其实可以return null或者return undefined,但是没有意义,应该是语法上的兼容而已
function fn(): void{     
	// do something     
	return; // 或者不写return
}

2.13 never 类型

  • 永不存在的值的类型
  • 开发中使用较少,一般用于抛出异常、无限循环的函数返回类型
  • 出现该类型的时候,注意检查代码是否有问题
  • 语法:
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {    
	throw new Error(message);
}

// 推断的返回值类型为never
function fail() {    
	return error("Something failed");
}

// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {    
	while (true) {
	}
}

2.14 元组类型

  • 固定长度的数组(元素类型可以不一致)
  • 结合数组理解, 最大的区别的是元组的长度固定, 且每个索引对应的元素类型固定
  • 对于值, 可以get, set, update, 注意变更的值只能是规定的类型, update可以用arr[0] = newValue, set可以用arr.push(newValue)
// 表示数组中只能有2个string的元素,长度不可变
let arr1: [string, string]

let arr2: [number, string] 

2.15 enum类型

  • 枚举; 默认枚举值有编号,类似数组索引,从0开始
enum Gender {     
	Male,     
	Female
}

let tom: Gender = Gender.Male
console.log(tom)  // 0
console.log(Gender.Male, Gender.Female) // 0 1
  • 特殊使用方式:
    如果枚举值是数字值, 可以用以下写法
enum Color {  
	Red = 6,  
	Green = 7,  
	Blue = 8
}

let c:string = Color[6]  // Red

2.16 typeof操作符

用来获取一个变量或对象的类型

interface Person {  
	name: string;  
	age: number;
}
const test: Person = { name: "Tom", age: 20 };
type Sys = typeof test; // type Sys = Person

在上面代码中,我们通过 typeof 操作符获取 test 变量的类型并赋值给 Sys 类型变量,之后我们就可以使用 Sem 类型:

const Vivo: Sys  = { name: "Lili", age: 3 }

也可以对嵌套对象执行相同的操作:

const kakaxi = {    
	name: "kakaxi",    
	age: 27,    
	address: {      
		province: '湖南',      
		city: '长沙'       
	}
}
type Kakaxi = typeof kakaxi;
/*	以下即为Kakaxi类型 
	type Kakaxi = {    
		name: string;    
		age: number;    
		address: {        
			province: string;        
			city: string;    
		};
	}
*/
此外, typeof 操作符除了可以获取对象的结构类型之外,它也可以用来获取函数对象的类型,比如
function toArray(x: number): Array<number> {  
	return [x];
}
type Func = typeof toArray; // -> (x: number) => number[]

TypeScript函数

3.1 函数定义

函数是由一连串的子程序(语句的集合)所组成的,可以被外部程序调用,向函数传递参数之后,函数可以返回一定的值。

通常情况下,TypeScript 代码是自上而下执行的,不过函数体内部的代码则不是这样。如果只是对函数进行了声明,其中的代码并不会执行,只有在调用函数时才会执行函数体内部的代码。

3.2 函数格式

  • 格式1:
function 函数名(参数列表):返回值类型{
	函数体...
	[return 返回值;]
}
  • 格式2:
let 函数名 = function (参数列表):返回值类型{
	函数体...
	[return 返回值;]
}

3.3 必选参数

必选参数:在调用函数的时候,必须要传入的参数,参数列表里边的参数默认就是必选参数,只要在声明的时候写了参数,在传递的时候,就必须传入参数,而且,实参与形参的数量与类型要一致。

function getInfo(name: string, age: number): string {
    return `${name} --- ${age}`;
}

console.log(getInfo("张三", 28)); // 正确
console.log(getInfo("张三")); // 错误
console.log(getInfo(28)); // 错误

3.4 可选参数

必选参数:为了解决在函数传参的时候,某些参数可以不用传递,我们就需要可选参数了。

function getInfo(name: string, age?: number): string {
    return `${name} --- ${age}`;
}

console.log(getInfo("张三", 28)); // 正确
console.log(getInfo("张三")); // 正确
console.log(getInfo(28)); // 错误

注意:可选参数必须配置到参数的最后面。

3.5 默认参数

默认参数:为了解决在函数传参的时候,某些参数可以不用传递,但是我们又需要该参数的值,这时候我们就需要给这个参数设定一个默认值也叫初始化值,就得用到默认参数了。

function getInfo(name: string, age: number = 20): string {
    return `${name} --- ${age}`;
}

console.log(getInfo("张三", 28)); // 正确
console.log(getInfo("张三")); // 正确
console.log(getInfo(28)); // 错误

注意:可选参数不能够进行初始化值的设定。

3.6剩余参数

剩余参数:在参数的类型确定而参数个数不确定的情况时,我们需要用到剩余参数,它使用 … 将接收到的参数传到一个指定类型的数组中。

function sum(...result: number[]): number {
    let sum = 0;
    for (let i = 0; i < result.length; i++) {
        sum += result[i];
    }
    return sum;
}
console.log(sum(1, 2, 3, 4, 5, 6));

注意:剩余参数必须配置到参数的最后面。

3.7 重载函数

重载指的是两个或者两个以上同名函数,但它们的参数不一样,这时会出现函数重载的情况。

TypeScript 中的重载是通过为同一个函数提供多个函数类型声明来实现函数重载的功能的。

//重载函数声明
function getInfo(name: string): string;
function getInfo(name: string, age: number): string;
//重载函数签名:就是把声明中出现的参数都写出来,如果可选,就使用可选参数,一个变量名可以使用多种类型用组合类型
function getInfo(name: string, age?: string | number): string {
    if (age) {

        return "我叫:" + name + ",年龄:" + age;
    } else {

        return "我叫:" + name;
    }
}

console.log(getInfo("zhangsan"));// 正确
console.log(getInfo("lisi", 20));// 正确
console.log(getInfo(123));// 错误

3.8箭头函数

箭头函数其实就是简化了函数当作参数传递时匿名函数的写法,具体可参考ES6新特性。

setTimeout(function () {
    console.log("匿名函数执行了...");
}, 1000);

setTimeout(() => {
    console.log("箭头函数执行了...");
}, 1000);

第四章 TypeScript 类

4.1 类的定义

class Person {
    name: string;//属性,前面省略了public关键词

    constructor(n: string) {//构造函数,实例化类的时候触发的方法
        this.name = n;//使用this关键字为当前类的name属性赋值
    }

    run(): void {//方法
        console.log(this.name+ "在跑步");
    }
}

var p = new Person("张三");
p.run();

4.2 类的继承

类的继承:在 TypeScript 中要想实现继承使用 extends 关键字,只要一旦实现了继承关系,那么子类中便拥有了父类的属性和方法,而在执行方法过程中,首先从子类开始找,如果有,就使用,如果没有,就去父类中找。类的继承只能单向继承。

  • 调用父类使用super
  • 子类继承父类的属性和方法
  • 子类可以改写父类的属性和方法
class Person {
    name: string;//父类属性,前面省略了public关键词

    constructor(n: string) {//构造函数,实例化父类的时候触发的方法
        this.name = n;//使用this关键字为当前类的name属性赋值
    }

    run(): void {//父类方法
        console.log(this.name + "在跑步");
    }
}

//中国人这个类继承了人这个类
class Chinese extends Person {
    age: number;//子类属性

    constructor(n: string, a: number) {//构造函数,实例化子类的时候触发的方法
        super(n);//使用super关键字调用父类中的构造方法
        this.age = a;//使用this关键字为当前类的age属性赋值
    }

    speak(): void {//子类方法
        super.run();//使用super关键字调用父类中的方法
        console.log(this.name + "说中文");
    }
}

var c = new Chinese("张三", 28);
c.speak();

只能单继承, 但是可以多级继承

class A {    
	name:string;    
	constructor(name:string){        
		this.name = name    
	}
}
class B extends A {    
	age:number;    
	constructor(age:number, name:string){        
		// 必须先用super调用父类构造器        
		super(name)        
		this.age = age    
	}
}
class C extends B {     
	sex:string;    
	constructor(sex:string, age:number, name:string){        
		super(age,name)        
		this.sex = sex    
	}
}
const instance = new C('张三', 18, '男')
console.log(instance)
// C { name: '男', age: 18, sex: '张三' }

4.3 修饰符

TypeScript 里面定义属性的时候给我们提供了 三种修饰符

  • public:公有类型,在当前类里面、子类、类外面都可以访问
  • protected:保护类型,在当前类里面、子类里面可以访问,在类外部没法访问
  • private:私有类型,在当前类里面可以访问,子类、类外部都没法访问
注意:如果属性不加修饰符,默认就是公有(public)。

4.4 静态属性

静态属性:被静态修饰符修饰的属性就是静态属性,静态属性可以通过类名直接调用。

class Person {
    name: string;//属性,前面省略了public关键词
    static sex: string = "男";//被静态修饰符static修饰的属性

    constructor(n: string) {//构造函数,实例化类的时候触发的方法
        this.name = n;
    }

    run(): void {//方法
        console.log(this.name+ "在跑步");
    }
}

console.log(Person.sex);

4.5 静态方法

静态方法:被静态修饰符修饰的方法就是静态方法,静态方法可以通过类名直接调用,但是在静态方法内部,不能直接调用当前类的非静态属性、非静态方法。

class Person {
    name: string;//属性,前面省略了public关键词
    static sex: string = "男";//被静态修饰符static修饰的属性

    constructor(n: string) {//构造函数,实例化类的时候触发的方法
        this.name = n;
    }

    run(): void {//方法
        console.log(this.name + "在跑步");
    }

    static print(): void {//被静态修饰符static修饰的方法
        // console.log('姓名:' + this.name);//错误
        console.log('性别:' + Person.sex);//正确
        // this.run();//错误
    }
}

Person.print();

4.6 抽象类

TypeScript 中的抽象类:它是提供其他类继承的基类,不能直接被实例化。

  • 开发不常用
  • 里面既可以有具体方法, 也可以有抽象方法
  • 既是对子类, 公共代码的封装; 也是对子类, 需要具体编码的方法的约束

用abstract关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并且必须在派生类(也就是其子类)中实现,abstract抽象方法只能放在抽象类里面。

我们常常使用抽象类和抽象方法用来定义标准。

//动物抽象类,所有动物都会跑(假设),但是吃的东西不一样,所以把吃的方法定义成抽象方法
abstract class Animal {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    abstract eat(): any;//抽象方法不包含具体实现并且必须在派生类中实现
    run() {
        console.log(this.name + "会跑")
    }
}

class Dog extends Animal {
    constructor(name: string) {
        super(name);
    }
    eat(): any {//抽象类的子类必须实现抽象类里面的抽象方法
        console.log(this.name + "吃骨头");
    }
}

var d: Dog = new Dog("小狼狗");
d.eat();

class Cat extends Animal {
    constructor(name: string) {
        super(name);
    }
    eat(): any {//抽象类的子类必须实现抽象类里面的抽象方法
        console.log(this.name + "吃老鼠");
    }
}

var c: Cat = new Cat("小花猫");
c.eat();

4.7 多态

  • 父类引用,指向子类对象
  • 不同类型的对象,针对相同的方法,产生了不同的行为
class Animal {    
	name:string    
	constructor(name:string){		
		this.name = name           
	}    
	run(distance:number) {        
		console.log(`${this,name}跑了${distance}米远的距离`)    
	}
}

class Dog extends Animal {    
	constructor(name:string) {        
		super(name)    
	}    
	// 重写run函数    
	run(distance:number) {        
		console.log(`${this,name}跑了${distance}米远的距离-----dog`)    	
	}
}

class Pig extends Animal {    
	constructor(name:string) {        
		super(name)    
	}    
	// 重写run函数    
	run(distance:number) {        
		console.log(`${this,name}跑了${distance}米远的距离======pig`)    
	}
}

const ani:Animal = new Animal('动物')
ani.run()

const dog:Animal = new Dog('旺财')
dog.run()

const pig:Animal = new Pig('佩奇')
pig.run()

// 使用多态
const dog1:Animal = new Dog('小狗')
dog1.run()
const pig1:Animal = new Dog('小猪')
pig1.run()

第五章 TypeScript接口

5.1 接口的定义

在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面,接口起到一种限制和规范的作用。接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它只规定这批类里必须提供某些方法,提供这些方法的类就可以满足实际需要。 typescrip中的接口类似于java,同时还增加了更灵活的接口类型,包括属性、函数、可索引和类等。

5.2 接口的用途

接口的用途就是对行为和动作进行规范和约束,跟抽象类有点像,但是,接口中不能有方法体,只允许有方法定义。

5.3 属性类型接口

//对传入对象的属性约束,以下这个是一个属性接口
interface FullName {
    firstName: string;
    secondName: string;
}

function printName(name: FullName) {
    console.log(name.firstName + "--" + name.secondName);
}

//传入的参数必须包含firstName、secondName
var obj = {
    age: 20,
    firstName: '张',
    secondName: '三'
};
printName(obj);//正确
// printName("1213");//错误

5.4 函数类型接口

//加密的函数类型接口
interface encrypt {
    (key: string, value: string): string;
}

var md5: encrypt = function (key: string, value: string): string {
    //模拟操作
    return key + "----" + value;
}
console.log(md5("name", "zhangsan"));

var sha1: encrypt = function (key: string, value: string): string {
    //模拟操作
    return key + "====" + value;
}
console.log(sha1("name", "lisi"));

5.5 可索引型接口

可索引接口就是对数组、对象的约束,不常用。

//可索引接口,对数组的约束
interface UserArr {
    [index: number]: string
}
var arr1: UserArr = ["aaa", "bbb"];
console.log(arr1[0]);

//可索引接口,对对象的约束
interface UserObj {
    [index: string]: string
}
var arr2: UserObj = { name: '张三', age: '21' };
console.log(arr2);

5.6 类类型接口

类类型接口就是对类的约束,它和抽象类抽象有点相似。

interface Animal {
    name: string;
    eat(str: string): void;
}

class Dog implements Animal {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    eat() {
        console.log(this.name + "吃大骨头");
    }
}

var d = new Dog("小狼狗");
d.eat();

class Cat implements Animal {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    eat(food: string) {
        console.log(this.name + "吃" + food);
    }
}

var c = new Cat("小花猫");
c.eat("大老鼠");

5.7 接口的继承

接口可以多继承

interface A {    
	id: number
}
interface B {    
	code: string
}
interface C extends A,B {    
	isFlag: boolean
}

const test:C = {    
	id:200,    
	code:'凌凌漆',    
	isFlag:false
}

console.log(test)
// { id: 200, code: '凌凌漆', isFlag: false }

第六章 TypeScript泛型

6.1 基本概念

泛型就是解决 类、接口、方法的复用性,以及对不特定数据类型的支持

  • 函数名称后加<>, 一般使用符号 T 占位, T代表具体的类型
  • 入参、出参的类型一般具有关联性
function identity<K>(...arg: T[]): T[] {    
	return [...arg]
}
console.log(identity(1,2,3))

第七章 TypeScript模块化

7.1 模块化

模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。

7.1.1 模块化的好处

  • 防止命名冲突
  • 代码复用
  • 高维护性

7.1.2 模块化的产品

CommonJS => NodeJS、Browserify

AMD => requireJS

CMD => seaJS

7.1.3、模块化的语法

模块功能主要由两个命令构成:export 和 import。

  • export 命令用于规定模块的对外接口
  • import 命令用于输入其它模块提供的功能

7.1.4 模块化的暴露

model/m1.ts 分别暴露

export let school = "华北理工大学";

export function study() {
    console.log("我们要学习!");
}

model/m2.ts 统一暴露

let school = "华北理工大学";

function findJob() {
    console.log("我们要找工作!");
}

export {school, findJob};

model/m3.ts 默认暴露

export default {
    school: "华北理工大学",
    change: function () {
        console.log("我们要改变自己!");
    }
}

7.1.5 模块化的导入

hello.ts

// 引入 m1.js 模块内容
import * as m1 from "./model/m1";
// 引入 m2.js 模块内容
import * as m2 from "./model/m2";
// 引入 m3.js 模块内容
import * as m3 from "./model/m3";

m1.study();
m2.findJob();
m3.default.change();

7.1.6 解构赋值形式

hello.ts

// 引入 m1.js 模块内容
import {school, study} from "./model/m1";
// 引入 m2.js 模块内容
import {school as s, findJob} from "./model/m2";
// 引入 m3.js 模块内容
import {default as m3} from "./model/m3";

console.log(school);
study();

console.log(s);
findJob();

console.log(m3);
m3.change();

注意:针对默认暴露还可以直接 import m3 from “./model/m3”

7.2 命名空间

命名空间:在代码量较大的情况下,为了避免各种变量命名相冲突,可将相似功能的函数、类、接口等放置到命名空间内,同Java的包、.Net的命名空间一样,TypeScript的命名空间可以将代码包裹起来,只对外暴露需要在外部访问的对象,命名空间内的对象通过export关键字对外暴露。

命名空间和模块的区别:

  • 命名空间:内部模块,主要用于组织代码,避免命名冲突。
  • 模块:ts的外部模块的简称,侧重代码的复用,一个模块里可能会有多个命名空间。
namespace A {
    interface Animal {
        name: string;
        eat(): void;
    }
    export class Dog implements Animal {
        name: string;
        constructor(theName: string) {
            this.name = theName;
        }
        eat(): void {
            console.log(`${this.name} 吃狗粮。`);
        }
    }
    export class Cat implements Animal {
        name: string;
        constructor(theName: string) {
            this.name = theName;
        }
        eat(): void {
            console.log(`${this.name} 吃猫粮。`);
        }
    }
}

namespace B {
    interface Animal {
        name: string;
        eat(): void;
    }
    export class Dog implements Animal {
        name: string;
        constructor(theName: string) {
            this.name = theName;
        }
        eat(): void {
            console.log(`${this.name} 吃狗粮。`);
        }
    }
    export class Cat implements Animal {
        name: string;
        constructor(theName: string) {
            this.name = theName;
        }
        eat(): void {
            console.log(`${this.name} 吃猫粮。`);
        }
    }
}

var ac = new A.Cat("小花");
ac.eat();

var bc = new B.Cat("小花");
bc.eat();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值