TypeScript语言

本文深入探讨了TypeScript和Flow这两种流行的JavaScript静态类型检查工具。介绍了它们如何通过增强类型系统来提升代码质量和开发效率,包括类型注解、类型推断、接口、泛型等关键特性。

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

一 TypeScript简述

TypeScript是一门基于JavaScript之上的编程语言,重点解决了JavaScript语言自有的类型系统的不足。通过使用TypeScript就可以大大地提高代码的可靠程度,当然也会有其它的技术解决方案。

二 强类型与弱类型

从类型安全角度来说,编程语言分为强类型和弱类型。
强类型:语言层面限制函数的实际参数必须与形参类型相同。
若类型:语言层面不会限制实参的类型。
由于并不是某个权威机构的定义,细节区分并不是十分清晰,大致的区分就是:强类型有更强的类型约束,弱类型几乎没有什么约束。比较清晰的解释就是:强类型中不允许任意的隐式类型转换,而弱类型语言中则允许任意的数据类型转换。
变量类型允许随时改变的特点,不应该是强弱类型的区别。
JavaScript是一门弱类型的语言。

三 类型系统

从类型检查角度来说,编程语言分为静态类型语言和动态类型语言。
静态类型:一个变量声明时他的类型就是明确的,在声明之后类型就不允许再被修改了。
动态类型:变量在运行阶段才能明确类型,并且可以随时变化数据类型。
JavaScript就是标准的动态语言。

四 JavaScript类型系统特征

JavaScript是一门弱类型且动态类型的语言,本身的类型系统也是非常薄弱的,或者说根本就没有类型系统。也就确实了类型系统的可靠性 - 不靠谱。
早期的JavaScript应用根本不会太复杂,一眼就能看到头的代码段里,类型系统就会显得很多余,并且JavaScript不需要编译直接运行,没有编译时类型检查这一环节。
现在JavaScript程序越来越复杂,这种优势也就变成了短板。

五 弱类型的问题

弱类型语言在去应对大规模应用开发时可能出现很多问题,尽管可以通过开发人员的约定来规避问题,但是很难做到开发的时候所有人百分百遵守,这也就造成了隐患,简单举例:

	const obj = {}
	
	obj.foo()  // 编写时无法知道某一属性是否不存在,只有程序调用时才会发现
	
	setTimeout(() => {
	  foo.foo()  // 如果这一方法在某个条件下才调用,这种问题就很难测出来。成为了程序中的一个隐患
	}, 1000000)
	// 而强类型的语言在编写时就会报错,提高了程序的稳定性
	function sum (a, b){
	  return a + b
	}
	
	console.log(sum(100, 100))
	console.log(sum(100, '100'))  
	// 函数sum的功能变成了字符串拼接,类型不确定造成的典型问题
	const obj = {}
	
	obj[true] = "100"
	
	console.log(obj['true'])    
	// 布尔值true变成了字符串'true'

六 强类型的优势

1、错误可以更早暴露出来
2、代码更智能、编码更准确:例如编辑器的智能提示,可以提高开发效率和代码质量。但有时候代码提示会失效。

	function render (element) {  
	// 假如我们声明的这个函数要接受一个dom元素作为参数
	  element.      
	  // 代码输入到这里的时候,编辑器并不会帮我们把我们可能用到的代码提示显示出来,
	  //原因就是编辑器此时根本不可能知道我们想做什么,也不知道element之后会接受的一个dom元素做参数
	}

3、重构更安全可靠
4、开发时可以减少不必要的类型判断

七 Flow

1、Flow概述

JavaScript的静态类型检查器,可以弥补JavaScript弱类型的一些弊端,是一个非常成熟的技术方案。在代码中添加一些类型注解的方式来标记代码中每个变量应该是什么类型,flow通过这个注解来检查代码当中是否存在类型使用当中的异常。Flow只是一个小工具,学习和使用起来特别简单。

	function sum (a:number, b:number){  
	// 这种冒号后跟上类型的用法叫做类型注解
	  return a + b
	}
	
	console.log(sum(100, 2))
	console.log(sum('100', 2))   
	// Flow可以检测出来数据类型引起的异常
	
	// 通过Babel编译,这些类型注解会被去除,所以在运行时不会有任何影响

2、Flow快速上手

	yarn add flow-bin (模块名叫:flow-bin)
	
	yarn flow init (初始化一个 .flowconfig 文件)
	
	yarn flow (启动flow服务,第一次启动时会比较慢。会自动检测当前目录下文件开头带有 // @flow 注释的文件
	
	yarn flow stop (完成之后再输入此命令可以结束后台flow任务)
	
	vs code 首选项 -> 设置 -> 搜索JavaScript validate设置后 可以去掉对JavaScript的语法校验

3、Flow编译移除注解

符合Flow语法的代码无法直接运行,需要在运行前移除注释和类型注解。
第一种方法是利用flow官方提供的flow-remove-types模块 yarn add flow-remove-types --dev (安装模块)
yarn flow-remove-types . -d dist (.表示当前目录, -d后面的dist目录表示输出目录)
第二种方法是利用babel工具 yarn add @babel/core @babel/cli @babel/preset-flow --dev (安装模块, @babel/core是核心模块, @babel/cli是命令行工具,使得使用命令行操作babel成为可能, @babel/preset-flow是包含了转换flow类型注解的插件)
使用时先在项目中新建.babelrc文件,内容如下

{
  "presets": ["@babel/preset-flow"]
}

然后在命令行输入 yarn babel src -d dist (将src目录下的js文件中的flow注解全部移除掉,输出在dist目录下)
用两种方法均可,自由选择

4、Flow开发工具插件

Flow Language Support是VS Code中的flow插件,使用时,保存文件将会触发校验。所以使用时不是即时校验,会感觉有些迟钝.
https://flow.org/en/docs/editors 是官网上对各种浏览器的插件支持情况

5、Flow类型判断

除了类型注解方式标记成员变量数据类型,flow还可以自动推断数据类型。但还是推荐开发过程中明确写明数据注解

	function square(n){
	  return n * n    // 乘法运算只适合数字,所以flow会默认给square函数参数做校验
	}
	
	square('100')

6、Flow原始类型

	const a: string = 'aff'
	const b: number = Infinity // NaN, 100
	const c: boolean = true // false
	const d: null = null
	const e: void = undefined  // 需要标记void
	const f: symbol = Symbol()

7、Flow数组类型

	const arr1: Array<number> = [1, 2, 4]  // 全是数字的数组
	const arr2: number[] = [1, 2, 4] // 全是数字的数组
	
	const foo: [string, number] = ['foo', 100]  // 固定长度固定类型的数组,这种数组格式也叫元组,多见于函数返回值

8、Flow对象类型

	const obj1: {foo: string, bar: number} = {foo: 'string', bar: 100 }
	const obj2: {foo2?: string, bar: number} = {bar: 100}   // ? 问号表示可有可无
	const obj3 = {}
	obj3.key1 = 'value1'   // 这种方式可以不受类型限制
	obj3.key2 = 100        // 这种方式可以不受类型限制
	
	const obj4 = {[string]: string}  // 表示还可以新添加无数个属性值,但是必须都是字符串格式
	obj4.key = 100          //  所以此处会报错

9、Flow函数类型

	function foo(callback: (string, number) => void){
	  callback('string', 100)
	}
	
	// 然后foo函数调用时就必须遵守以上规则

10、Flow特殊类型

	// 字面量类型, 限制某个变量必须是某个固定值
	
	const a: 'foo' = 'foo' 
	// 常配合联合类型来使用
	const type: 'success' | 'warning' | 'danger' = 'danger'   // 只能是几种可能中的一种
	
	const b: string | number = 'string' 
	
	type StringOrNumber = string | number // 声明一个自定义变量类型
	const b: StringOrNumber = 'string'    // 可以复用
	
	const gender: ?number = 0        //问号表示除此类型之外还可以存null或undefined,也被称为maybe类型

11、Flow Mixed 与 Any

	// mixed表示联合类型,代表所有数据类型,
	// 在函数内不可以出现隐式类型转换
	// 不明确数据类型是什么就不可以使用某一数据类型特有的方法
	function passMixed(value: mixed){
	  value.substr(1)     // 报错
	  value + 100         // 报错
	}

	passMixed('string')  
	passMixed(100)     //传入各种数据值均可
	
	// any表示传入所有数据类型均可,在函数内也可以出现隐式类型转换
	function passAny (value: any){
	  value.substr(1)     // 不报错
	  value + 100         // 不报错
	}
	
	passAny('string')
	passAny('100')      // 传入各种数据类型值均可
	
	// mixed仍是强类型, any是弱类型

12、Flow类型小结

此处并未完全解释flow支持的所有类型,如果遇到了没见过的类型,查文档。
https://flow.org/en/docs/types/
https://www.saltycrane.com/cheat-sheets/flow-type/latest/

13、Flow 运行环境API

JavaScript必须运行在某个特定环境,例如浏览器和node。一定会有很多环境提供的API和对象,浏览器环境提供的api也会有各种类型限制。
运行环境api返回值也会有类型限制:

	const element: HTMLElement | null = document.getElementById('app')

不同环境API对应的声明:
https://github.com/facebook/flow/blob/master/lib/core.js
https://github.com/facebook/flow/blob/master/lib/dom.js
https://github.com/facebook/flow/blob/master/lib/bom.js
https://github.com/facebook/flow/blob/master/lib/cssom.js
https://github.com/facebook/flow/blob/master/lib/node.js

八 TypeScript概述

TypeScript是一门基于JavaScript基础之上的编程语言,很多时候称为JavaScript的超集或拓展集。TypeScript包含JavaScript之外增加了类型系统,并且更好地实现了JavaScript新特性,最终会编译成为原始地JavaScript代码。功能更强大,生态更健全、更完善,相较于JavaScript更适合大型项目。微软地vs code编辑器中使用TypeScript会很流畅。
缺点一:语言本身多了很多概念,提高了学习成本。好在TypeScript属于渐进式,可以暂时先按照JavaScript语法开发
缺点二:项目初期,TypeScript会增加一些成本:例如编写变量声明。所以更适合大型项目。

1、TypeScript快速上手

想要使用TypeScript需要先安装模块

	yarn add typescript --save-dev

开发过程中vs code会自动校验TypeScript语法,编译编写完的index.ts文件,然后目录下将出现一个同名文件index.js :yarn tsc index.ts

2、TypeScript配置文件

TypeScript不但可以编译某个文件,还可以编译整个项目工程。

	yarn tsc  -- init 

这条命令会生成tsconfig.json文件,里面的json数据只有一个compilerOptions属性,里面包含的就是编译器对应的配置选项,但是绝大部分配置都被注释掉了。target属性表示编译后的JavaScript目标标准,module属性表示编译后的代码采用何种方式来进行模块化。outDir属性表示输出目录,rootDir属性表示需要被编译的文件目录,sourceMap属性表示开启源代码映射,strict属性表示严格模式

yarn tsc index.ts 这种方式并不会遵从tsconfig.json文件中的配置项,只有编译整个项目的时候tsconfig.json文件中的配置项才会生效。

3、TypeScript原始类型

tsconfig.json文件中

	const a: string = 'foobar'
	const b: number = 100 // NaN Infinity
	const c: boolean = true // false
	
	const d: string = null   // 非严格模式下或者strictNullChecks为false的模式下 string、number、boolean三种数据类型允许为null或者undefined
	
	const e: void = null
	const f: null = null
	const g: undefined = undefined
	
	const h: symbol = Symbol()  // 报错 只要在配置文件中的target属性设置成 es2015 就好了。

4、TypeScript标准库声明

因为Symbol类型是es6才有的数据类型,所以编译成es5就会报错,类似的还有promise类型。如果执意需要编译成es5,则在tsconfig.json文件中的lib属性数组当中添加相应模块,如 [“es2015”, “DOM”]。标准库就是内置对象所使用的声明的文件,使用内置对象就必须引入相对应的标准库,否则TypeScript就找不到内置对象相对应的类型,就会报错了。

5、TypeScript中文错误信息

TypeScript本身就支持多语言显示,英文版的vs code会默认显示英文版的错误信息,只需要在编译的时候执行 yarn tsc --locale zh-CN 多出了 --locale zh-CN 的信息,绝大部分报错信息就会报中文错误。而在VS Code当中的英文报错,可以在 首选项 -> settings 里面搜索 typescript local, 改成 zh-CN 即可。在实际开发中,我们有时候会需要根据报错提示去网上搜索,但是中文的报错很难搜索到有用的结果,所以建议还是不要设置成中文

6、TypeScript作用域问题

如果有两个将会同时编译的ts文件当中同时声明了一个同名变量,那么就会报错。

	// 假设有另一个将会同时变异的 ts 文件当中声明了 const a = 123 那么下面这一行就会报错
	
	// const a = 123    // 报错
	
	(function(){       // 这样可以解决同名变量冲突问题
	  const a = 123
	})()
	
	// 或者利用模块化的方式解决,因为模块化有专门的模块化作用域
	
	const a = 123
	export {}      // 这行代码的意思并不是返回了一个空对象,而是一个typescript语法而已

7、TypeScript Object类型

TypeScript 中的 Object 类型并不是单指对象类型,而是泛指各种非原始类型,包含对象、数组、函数

	export {}   // 这行代码可以确保跟其他示例没有成员冲突
	
	const foo1: object = function(){}
	const foo2: object = [123]
	const foo3: object = {number: 123}  // 这三种数据声明都不会报错,但是接受其它原始值则会发生错误
	
	// 如果想声明一个纯粹的对象类型数据,可以使用类似对象字面量的语法
	const obj: {foo:number, bar: string} = {foo: 123, bar: 'string'}  // 这样声明会严格限制对象的属性结构
	
	// 在typescript中限制对象类型,更专业的方式是使用接口,后面详细介绍

8、TypeScript数组类型

两种类型注解写法

	const arr1: Array<number> = [1, 2, 3]
	
	const arr2: number[] = [1, 2, 3]
	
	// ---------------
	function sum(...args: number[]){  // 类型注解限制让开发过程减少了判断条件
	  return args.reduce((prev, current) => prev + current, 0)
	}
	sum(1, 2, 3, 'foo')  // 这里会报错,保证了程序的可靠性

9、TypeScript元组类型

元组是一个特殊类型,明确了数组长度和每个成员类型的数据类型。可以使用类似数组字面量的方式去定义元组类型。

	export {}  // 确保变量成员无冲突
	
	
	const tuple: [number, string] = [123, 'foo']   // 常用于函数返回值
	
	// 还有 Object.entries() 方法的返回值每一项都是一个元组

10、TypeScript枚举类型

我们在应用开发过程中,经常会用到某几个值去代表某种状态。例如这里有个表示文章的对象,其中的状态status值想用0、1、2来代表诸如“草稿”、“已发布”等状态。但是时间久了我们就会忘记status这些值是什么含义,甚至会混进除了0、1、2以外的值。这种情况下使用枚举类型最合适,枚举类型有两个特点:1、给一组数值起上更好理解的名字。2、不会超出范围。

枚举类型在编译结束后并不会被移除,而是会生成一个双向的键值对对象,目的是可以动态根据枚举值还可以获取枚举名称。如果不需要这一过程,也可以使用常亮枚举,只需要在enum关键词前添加const即可,编译时就不会生成双向的键值对对象。

	export {}  // 确保变量成员无冲突
	
	// enum PostStatus {
	//   Draft= 0,
	//   Unpublished = 1,
	//   Published = 2
	// }
	
	// 如果我们不给枚举值赋值,它会自动从0开始累加
	// enum PostStatus {
	//   Draft,
	//   Unpublished,
	//   Published
	// }
	
	// 如果我们不给枚举值赋值一个数字,接下来的其它枚举值会在此基础上做一个自增长
	// enum PostStatus {
	//   Draft = 6,
	//   Unpublished,
	//   Published
	// }
	
	// 枚举值可以是字符串,但是由于字符串无法自增长,所以需要给每个枚举值赋值
	enum PostStatus {
	  Draft= 'aaa',
	  Unpublished = 'bbb',
	  Published = 'ccc'
	}
	
	const post = {
	  title: 'Hello TypeScript',
	  content: 'TypeScript is a typed superset of JavaScript.',
	  // status: 1   // 2 // 0
	  status: PostStatus.Draft
	}

11、TypeScript函数类型

函数的类型约束就是约束函数参数和函数返回值。

	// 两种方式
	
	function func1(a: number, b?: number ): string{  // 问号表示可选
	  return `func1`
	}
	
	function func2(a: number, b: number = 10 ): string{  // 给参数一个默认值也可以实现可选效果
	  return `func2`
	}
	
	function func3(a: number, ...rest: number[]): string{  // 任意参数写法
	  return `func3`
	}
	
	
	// 函数表达式的类型限制方式
	// 约束函数返回值的类型,使用类似箭头函数的方式去表示参数可以接受一个什么样的函数
	const func4: (a: number, b:number) => string = function(a: number, b:number): string{
	  return 'funct4'
	}

12、TypeScript任意类型

任意类型any主要用于兼容老代码环境。任意类型any不会触发ts语法检查,可以赋值任意类型数据且过程中可修改数据类型。 数据安全问题依旧存在,不要轻易使用。

	export {}  // 确保变量成员无冲突
	
	// 任意类型any不会触发ts语法检查,可以赋值任意类型数据且过程中可修改数据类型。
	//  数据安全问题依旧存在,不要轻易使用
	function stringify (value: any){
	  return JSON.stringify(value)
	}
	
	stringify('string')
	stringify(100)
	stringify(true)
	
	let foo: any = 'string'
	
	foo = 100
	foo.bar()

13、TypeScript隐式类型推断

在TypeScript当中,如果没有通过类型注解去标记某个变量的类型,TypeScript会根据我们的使用情况,去推断一个变量的数据类型。

	export {}  // 确保变量成员无冲突
	
	let age = 18  // 被推断是number类型
	
	age = 'string'  // 不可以赋值其它类型的数据,所以此处会报错
	
	let foo       // 此处由于未赋值,被推断成为了any类型
	
	foo = 100
	foo = 'string'
	
	// 建议为每个变量添加明确的数据类型,以便让代码中的数据类型限制更准确

14、TypeScript类型断言

在某些特殊情况下,TypeScript并不能推断出某个变量的具体类型。

	export {}  // 确保变量成员无冲突
	
	// 假定这个nums 来自一个明确的接口
	const nums: Array<number> = [110, 120, 119, 112]
	
	const res = nums.find(i => i > 0)
	
	const square = res * res
	
	// TypeScript并不知道数组nums里一定会有符合条件的数据,但是开发者知道结果res一定是数字而不会是undefined
	// 类型断言就是告诉TypeScript某一个变量一定是某个数据类型
	// 类型断言的两种方式,注意这并不是类型转换
	const num1 = res as number  // 更推荐使用
	const num2 = <number>res  // JSX 下不能使用

15、TypeScript接口 Interface

限制普通对象数据类型内的数据结构。

	export {}  // 确保变量成员无冲突
	
	interface Post{
	// 多个成员变量之间是支持逗号分隔的,但是更规范的应该用分号,这个分号和JavaScript中的分号一样,是可以省略不写的
	// 编译后的代码里是不会存在任何跟接口相关的代码,说明编译结束后这部分代码就被移除了。
	  title: string      
	  content: string
	}
	
	function printPost (post: Post) {  // 要求传入参数要有title属性和content属性
	  console.log(post.title)
	  console.log(post.content)
	}
	
	printPost({       // 传入参数值如果符合条件就不会报错
	  title: 'oTitle',
	  content: 'content text'
	})

接口还可以定义某个属性是否一定存在、是否只读,还可以定义任意属性名的属性值。

	export {}  // 确保变量成员无冲突
	
	// ----------------------
	
	interface Post{
	  title: string      
	  content: string
	  subtitle?: string  // 问号表示可有可无
	  readonly summary: string  // readonly表示只读,该属性不可修改
	}
	
	const hello: Post = {
	  title: 'Hello TypeScript',
	  content: 'A javascript superset',
	  summary: 'A javascript'
	}
	
	// hello.summary = 'cc'  
	// 只读成员重新赋值就会报错
	
	interface Cache {
	  [prop: string]: string      // 其中的prop并不是固定写法,可以随意起名
	}
	
	const cache: Cache = {}
	cache.foo = 'value1'
	cache.bar = 'value2'

16、TypeScript类的基本使用

Classes,描述一类具体事务的抽象特征。首先TypeScript可以实现JavaScript中的所有关于类的功能,

	export {}  // 确保变量成员无冲突
	
	class Person {
	  name: string   // = 'init name'
	  age: number    // = init age
	  
	  constructor(name: string, age: number){
	    this.name = name
	    this.age = age
	  }
	
	  sayHi(msg: string){
	    console.log(`I am ${this.name}, ${msg}.`)
	  }
	}

public 表示公开,缺省值就是public、private 表示私有属性、protected表示受保护的,和private相比,受保护的成员可以被子类集成

	export {}  // 确保变量成员无冲突
	
	class Person {
	  public name: string   // 默认public,可以不写
	  private age: number    // private 表示私有属性
	  protected gender: boolean  // protected 意为受保护的,允许在子类中访问的成员
	  
	  constructor(name: string, age: number){
	    this.name = name
	    this.age = age
	    this.gender = true
	  }
	
	  sayHi(msg: string){
	    console.log(`I am ${this.name}, ${msg}.`)
	    console.log(this.age)
	  }
	}
	
	class Student extends Person {
	  // 构造函数一旦被设置为私有属性,则当前类就不可以通过new操作符新建对象了,需要配个一个静态方法去操作
	  private constructor (name: string, age: number){  
	    super(name, age)
	    console.log(this.gender)    // 继承父类的时候,gender属性是可以访问到的
	  }
	  static create(name: string, age: number){
	    return new Student(name, age)
	  }
	}
	
	const tom = new Person('Tom', 18)
	console.log(tom.name)
	
	// 访问tom.age属性就会报错,因为age是私有属性,只可以在类的内部使用
	// console.log(tom.age)  
	
	// 访问tom.gender属性会报错
	// console.log(tom.gender)
	
	const jack = Student.create('jack', 18)

17、TypeScript类与接口

相比于类,接口的概念会更抽象一些。

	export {}  // 确保变量成员无冲突
	
	interface EatAndRun{
	  eat(food: string): void       // 函数签名的方式来约束这两个方法的类型
	  run(distance: number): void
	}
	
	// implements 实现接口EatAndRun中的所有方法,如果实现有缺失就会报错
	class Person implements EatAndRun{   
	  eat(food: string): void{
	    console.log(`优雅进餐:${food}.`)
	  }
	  run (distance: number){
	    console.log(`直立行走:${distance}.`)
	  }
	}
	
	class Animal implements EatAndRun{
	  eat(food: string): void{
	    console.log(`咕噜咕噜的吃:${food}.`)
	  }
	  run (distance: number){
	    console.log(`爬行:${distance}.`)
	  }
	}

就算一个开发人员对JavaScript非常精通,但是没有对其它语言中的思想有了解的话,他也同样很难设计出高级的好产品。所以我们的视野应该放宽一点。
在Java中的思想是建议每个接口尽可能的简单和细化,所以我们的代码按照这种思想也可以改为:(代码设计更合理一些)

export {}  // 确保变量成员无冲突

interface Eat{
  eat(food: string): void
}
interface Run{
  run(distance: number): void
}

// implements 实现接口EatAndRun中的所有方法,如果实现有缺失就会报错
class Person implements Eat, Run{   
  eat(food: string): void{
    console.log(`优雅进餐:${food}.`)
  }
  run (distance: number){
    console.log(`直立行走:${distance}.`)
  }
}

class Animal implements Eat, Run{
  eat(food: string): void{
    console.log(`咕噜咕噜的吃:${food}.`)
  }
  run (distance: number){
    console.log(`爬行:${distance}.`)
  }
}

就算一个开发人员对JavaScript非常精通,但是没有对其它语言中的思想有了解的话,他也同样很难设计出高级的好产品。所以我们的视野应该放宽一点。
在Java中的思想是建议每个接口尽可能的简单和细化,所以我们的代码按照这种思想也可以改为:(代码设计更合理一些)

	export {}  // 确保变量成员无冲突
	
	interface Eat{
	  eat(food: string): void
	}
	interface Run{
	  run(distance: number): void
	}
	
	// implements 实现接口EatAndRun中的所有方法,如果实现有缺失就会报错
	class Person implements Eat, Run{   
	  eat(food: string): void{
	    console.log(`优雅进餐:${food}.`)
	  }
	  run (distance: number){
	    console.log(`直立行走:${distance}.`)
	  }
	}
	
	class Animal implements Eat, Run{
	  eat(food: string): void{
	    console.log(`咕噜咕噜的吃:${food}.`)
	  }
	  run (distance: number){
	    console.log(`爬行:${distance}.`)
	  }
	}

18、TypeScript抽象类

抽象类在某种程度上说和接口有点类似,他也可以约束子类中必须有某些成员。不同于接口的是:抽象类可以包含某些具体的实现,而接口只能有成员的抽象限制不包含任何具体实现。

	export {}  // 确保变量成员无冲突
	
	// 定义成抽象类后就只能被集成而不能通过new操作符来新建实例对象了
	
	abstract class Animal{  // abstract 关键字
	  eat(food: string): void{
	    console.log(`咕噜咕噜的吃:${food}`)
	  }
	  // abstract 还可以定义抽象方法, 不需要方法体,需要子类去实现
	  abstract run(distance: number): void 
	} 
	
	class Dog extends Animal {
	  run(distance: number): void {
	    console.log(`四脚爬行:${distance}`)
	  }
	}
	
	const d = new Dog()
	d.eat('肉')
	d.run(100)

19、TypeScript泛型

泛型(Generics)就是指我们在定义函数、接口或者类的时候并未指定具体类型,调用时再传递一个类型。这样可以极大程度的复用代码。
总结来说,泛型就是我们在定义时不能明确的类型,变成一个参数,在使用时再传递这样一个类型参数。

	export {}  // 确保变量成员无冲突
	
	function createNumberArray (length: number, value: number): number[]{
	  const arr = Array<number>(length).fill(value)             
	  // 这里的Array就是一个泛型类,期初并不知道里面会存放什么类型数据,默认是any
	  // 调用时传入具体类型
	  return arr
	}
	
	function createStringArray (length: number, value: string): string[]{
	  const arr = Array<string>(length).fill(value)
	  return arr
	}
	
	let result = createNumberArray(3, 100)
	// res => [100, 100, 100]
	
	let result2 = createStringArray(3, '100')
	// res => ['100', '100', '100']
	
	
	function createArray<T> (length: number, value: T): T[]{
	  const arr = Array<T>(length).fill(value)
	  return arr
	}
	const res = createArray<string>(3, 'aaa')   
	// 调用时的这个string就被作为参数传给了createArray函数的参数<T>

20、TypeScript类型声明

实际开发中难免会用到第三方的npm模块,而这些模块不一定都是TypeScript编写的,这样就没有了强类型的体验。详细语法查文档

	import { camelCase } from 'lodash'
	
	declare function camelCase (input: string): string
	// declare操作符给camelCase声明了类型
	
	const res = camelCase('hello typed')
	
	export {}  // 确保变量成员无冲突

声明:以上内容均为学习笔记,如涉及侵权,请联系我删帖。如需转载,请注明文章出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不甜的糖果

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值