【TypeScript】本篇文章带你速通TypeScript,了解TS与JS的关系,TS如何定义类型、接口、枚举...

【TypeScript】本篇文章带你速通TypeScript,了解TS与JS的关系,TS如何定义类型、接口、枚举...

1. TS是什么TS是包含了JS的内容的,或者说TS是在JS上做的改进

TypeScript 由微软开发,是基于JavaScript的一个扩展语言TypeSCript包含了JS的所有内容;TypeScript增加了:静态类型接口、泛型等很多现代开发特性,因此更适合大型项目的开发TypeScript需要编译为JavaScript,然后交给浏览器或其他JavaScript运行环境执行1.1 市场需求JS在诞生时的定位是浏览器脚本语言,用于在网页中浅入一些简单的逻辑,而且代码量很少

现如今的JS应用场景比以前丰富太多,代码量也比以前大很多。而当时JS就没有考虑倒如今的应用场景和代码量,逐渐出现了很多缺点;

1.1.1 JS的缺点不清不楚的数据类型

代码语言:javascript复制let s = "hello"

s() // 报错:TypeError: s is not a function 在代码量少的时候可以很清晰的看见这是一个字符串不是一个方法,会报错

而当代码量多了后,真的出现调用这种情况时如何定位?

有漏洞的逻辑

代码语言:javascript复制const str = Date.now() % 2 ? '奇数' : '偶数'

if(str!=='奇数'){

alert('hello')

}else if (str==='偶数'){

alert('world')

} 判断是否是偶数,其实else if内的代码块永远不会被执行

当命中第一个if时,else if就不会被执行了

那么,在这时 JS 并不会给出任何的逻辑上的提示

访问不存在的属性(普遍是null)

代码语言:javascript复制const obj = { width: 10, height: 15};

const area = obj.width * obj.heighth; 在JS里,如果出现调用一个不存在的属性,一样不会给出任何的提示

哪怕出现的是一个错误的、不可计算的结果

低级的拼写错误

代码语言:javascript复制const message = 'hello, world';

message.toUperCase();// 正确的方法名称:.toUpperCase(); 如果出现拼写错误,导致无法调用函数,JS一样不会给出任何提示

1.1.2 TS的优势 不清不楚的数据类型

在这里插入图片描述 有漏洞的逻辑

在这里插入图片描述 访问不存在的属性(普遍是null)

在这里插入图片描述 低级的拼写错误

在这里插入图片描述1.1.2.1 静态代码检查TS能够解决上述JS出现的问题,这源于TS使用了【静态代码检查】功能

在代码运行前进行检查,发现代码的错误或不合理性,减小运行时异常出现的机率,这种检查叫做【静态类型检查】,TS的核心就是【静态代码检查】,简单来说就是把运行时的错误前置但同样的,TS的代码量要大于JS,但由于TS的代码结构更加清晰,在**后期代码的维护中TS却远胜于JS**2. TS的编译2.1 命令行编译使用 tsc 命令 在使用 tsc 命令前,还需要安装ts环境

npm i typescript -g

代码语言:javascript复制tsc ts文件名使用后,会相同文件夹下编译生成一个js文件

ts文件代码语言:javascript复制var a = 10;

console.log("数字是:"+a)生成的js文件代码语言:javascript复制var a = 10;

console.log("数字是:" + a);2.2 自动化编译命令

说明

tsc --init

生成自动化配置文件

tsc --watch [ts文件]

监视某一个ts文件,当ts文件发生任何改动,都会实时生成JS

tyc --noEmitOnError – watch

当编译出错时不生成 .js 文件(不推荐,更建议修改tsconfig.json中的noEmitOnError配置)

默认的tsconfig.json代码语言:javascript复制{

"compilerOptions": {

/* Visit https://aka.ms/tsconfig to read more about this file */

/* Projects */

// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */

// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */

// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */

// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */

// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */

// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */

/* Language and Environment */

"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */

// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */

// "jsx": "preserve", /* Specify what JSX code is generated. */

// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */

// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */

// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */

// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */

// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */

// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */

// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */

// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */

// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */

/* Modules */

"module": "commonjs", /* Specify what module code is generated. */

// "rootDir": "./", /* Specify the root folder within your source files. */

// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */

// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */

// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */

// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */

// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */

// "types": [], /* Specify type package names to be included without being referenced in a source file. */

// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */

// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */

// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */

// "rewriteRelativeImportExtensions": true, /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */

// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */

// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */

// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */

// "noUncheckedSideEffectImports": true, /* Check side effect imports. */

// "resolveJsonModule": true, /* Enable importing .json files. */

// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */

// "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */

/* JavaScript Support */

// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */

// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */

// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */

/* Emit */

// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */

// "declarationMap": true, /* Create sourcemaps for d.ts files. */

// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */

// "sourceMap": true, /* Create source map files for emitted JavaScript files. */

// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */

// "noEmit": true, /* Disable emitting files from a compilation. */

// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */

// "outDir": "./", /* Specify an output folder for all emitted files. */

// "removeComments": true, /* Disable emitting comments. */

// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */

// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */

// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */

// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */

// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */

// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */

// "newLine": "crlf", /* Set the newline character for emitting files. */

// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */

// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */

// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */

// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */

// "declarationDir": "./", /* Specify the output directory for generated declaration files. */

/* Interop Constraints */

// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */

// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */

// "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */

// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */

"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */

// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */

"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */

/* Type Checking */

"strict": true, /* Enable all strict type-checking options. */

// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */

// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */

// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */

// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */

// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */

// "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */

// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */

// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */

// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */

// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */

// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */

// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */

// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */

// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */

// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */

// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */

// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */

// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */

// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */

/* Completeness */

// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */

"skipLibCheck": true /* Skip type checking all .d.ts files. */

}

}3. 类型声明3.1 基本定义代码语言:javascript复制let a: string

let b: number

let c: boolean

a = 'hello'

b = 100

c = true

console.log(a,b,c)// hello 100 true限定函数的参数类型

代码语言:javascript复制function count(x:number,y:number){

return x+y

}

let result = count(1,2)

console.log(result)// 3限定函数的返回类型

代码语言:javascript复制function count(x:number,y:number):string{

return x+y+"数量"

}

let result = count(1,2)

console.log(result)字面量类型

代码语言:javascript复制let a: string

let b: 'test'

a = 'hello'

b = 'name' 当类型限定为一个字面量常量时,那么该变量只会是这个字面量常量值,不可发生改变

在这里插入图片描述3.2 类型推断TS会根据我们的代码,进行类型推导,例如下面代码中的变量d,只能存储数字

代码语言:javascript复制let d = -99

d = false // 报错请注意,类型推断不是万能的,面对复杂类型时推断容易出问题,所以尽量还是明确的编写类型声明

代码语言:javascript复制let d: number = -99

d = false // 报错4. 类型总览4.1 JS中的数据类型关键字

说明

string

字符串

number

数量

boolean

布尔

null

undefined

未定义

bigint

大整形

symbol

标记

object

对象

object类型中,还包含:Array、Function、Date等

4.2 TS中的数据类型JS有的数据类型,TS中都有新增了下述类型

关键字

说明

any

任意类型

unknown

未知

never

不存在值的类型

void

没有类型

tuple

数组

enum

枚举

type

类型

interface

接口

在JS中的内置构造函数:Number,String,Boolean,它们会用于创建对应的包装对象,在日程开发时很少使用,在TS中也是同理,所以TS中进行类型声明时,通常都是用小写的number、string、boolean

代码语言:javascript复制let a: string = 'a'; // TS更加推荐这种

let b = new String('b');// String是一个包装类

let c: String = 'c';// 使用的包装类,不推荐;更加占用资源 原始类型 和 包装对象

原始对象:如 number、string、boolean

在JS中是简单的数据类型,它们在内存中占用空间少,处理速度快

包装对象:如 Number,String,Boolean

是复杂类型,在内存中占用更多的空间

自动装箱:JS在必要时会自动将原始类型包装成对象,以便调用方法或访问属性

5. 常用类型5.1 anyany 的含义是:任意类型,一旦将变量类型限制为any,那就意味着放弃了对改变了的类型检查代码语言:javascript复制let a: any

a = 100

a = "你好"

a = false

// 如果不加任何的类型限定,默认就是 【any】类型

let b

b = 100

b = "你好"

b = false 注意:any类型的变量,可以复制给任意类型的变量

代码语言:javascript复制let a: any

a = false

let c: string

c = a5.2 unknownunknown的含义是:未知类型可以将unknown理解为一个类型安全的any,适用于:不确定数据的具体类型

代码语言:javascript复制let a: unknown

a = 100

a = "你好"

a = false

let c: string

c = a // 警告,不能将类型“unknwon”分配给类型“string”不过也可以赋值,需要进行判断或者断言

判断

代码语言:javascript复制let a: unknown

a = 100

a = false

a = "你好"

let c: string

// 判断

if(typeof a === 'string'){

c = a

}断言

代码语言:javascript复制let a: unknown

a = 100

a = false

a = "你好"

let c: string

c = a as string // 断言

c = a // 断言调用函数时,也和any存在不同

代码语言:javascript复制let str1: string

str1 = 'hello'

str1.toUpperCase() // 无警告

let str2: any

str2 = 'hello'

str2.toUpperCase() // 无警告

let str3: unknown

str3 = 'hello'

str3.toUpperCase() // 警告:“str3”的类型为“未知”5.3 nevernever的含义是:任何值都不是(不能有值)几乎不用never去直接限制变量,因为没有意义:

代码语言:javascript复制let a: never

a = 1

a = true

a = undefined

a = nullnever一般是TypeScript主动推断出来的

代码语言:javascript复制let a: string

a = 'hello'

if(typeof a==='string'){

console.log(a.toLowerCase())

}else{

// 这里推断出来时 never,因为没有任何一个值会符合此处的逻辑

console.log(a)

}never也可用于限制函数的返回值

代码语言:javascript复制function throwError(str: string):never{

throw new Error("程序异常退出:"+str)

} never作为返回值,一般来说,就是在这个方法无法正常结束的时候才符合标准

5.4 voidvoid 通常用于函数返回值声明,含义:【函数不返回任何值,调用者也不应该依赖其返回值进行任何操作】

代码语言:javascript复制function logMessage(msg: string):void{

console.log(msg)

}

logMessage('hello'); 编码者没有编写return去制定函数的返回值,所以logMessage函数时没有显示返回值的,但会有一个隐式返回值,就是undefined;即:虽然函数返回类型为void,但也可以接收undefined,简单点来说:undefined 是 void 可以接收的一种 “空”

以下三种方式声明是没有问题的

代码语言:javascript复制function logMessage1(msg: string):void{

console.log(msg)

}

function logMessage2(msg: string):void{

console.log(msg)

return

}

function logMessage3(msg: string):void{

console.log(msg)

return undefined

}void函数返回值无法进行任何操作

代码语言:javascript复制////////////////////////////////void///////////////////////////////////

function logMessage4(msg: string):void{

console.log(msg)

}

let s1 = logMessage4("hello")

if(s1){ // 警告:无法测试 "void" 类型的表达式的真实性

console.log("logMessage4");

}

////////////////////////////////undefined///////////////////////////////////

function logMessage5(msg: string):undefined{

console.log(msg)

}

let s = logMessage5("hello")

if(s){

console.log("logMessage5");

} 理解void与undefined

void是一个广泛的概念,用来表达“空”,而undefined则是这种“空”的具体实现之一因此可以说undefined是void能接收的“空”状态的一种具体形式换句话说:void包含undefined,但void表达的语义超越了单纯的undefined,它是一种意图上的约定,而不仅仅是特定值的限制总结:

若函数返回类型是void那么:

从语法上讲,函数是可以返回undefined的从语义上讲,函数调用者不应关心函数返回的值,也不应依赖返回值进行任何操作,即使返回了undefined值5.5 object和Object 关于object和Object,实际开发中使用的相对较少,因为范围太大了

5.5.1 objectobject的含义是:所有非原始数据类型 都可以存储:对象、函数等

代码语言:javascript复制let a:object

a = {}

a={name:"张三"}

a=[1,2,3,4,5]

a=function(){}

a=new String("12")

class Person{}

a = new Person()

/////////////// 无法使用 ////////////////

a = 1

a = false

a = "hello"

a = null

a = undefined5.5.2 Object官方描述:所有可以调用Object方法的类型简单记忆:除了undefined和null的任何值由于限制的范围太大,所以实际开发中使用的频率极低代码语言:javascript复制let a:Object

a = {}

a={name:"张三"}

a=[1,2,3,4,5]

a=function(){}

a=new String("12")

class Person{}

a = new Person()

a = 1

a = false

a = "hello"

/////////////// 无法使用 ////////////////

a = null

a = undefined5.5.3 声明对象类型通用模式:

代码语言:javascript复制let person1: {name: string,age:number}

person1 = {name: "zhangsan",age: 18}

////////// 两种:带或不带 ? ///////////////

let person2: {name: string,age?:number}

person2 = {name: "zhangsan"}索引签名:

允许定义对象可以具有任意数量的属性,这些属性的键和类型是可变的,常用于:描述类型不确定的属性(具有动态属性的对象)

代码语言:javascript复制let person3: {

name: string,

age?: number,

// 索引签名

[key:string]:any

}

person3 = {name:"zhangsan",age:18,address:"湖南"}5.5.4 声明函数类型代码语言:javascript复制let count: (a:number,b:number) => string // 规定了函数的数据类型,参数类型是number,返回值类型是string类型

count = (x,y)=>{

return x+y+"字符串"

}TS 中的 => 在函数类型声明时表示函数类型,描述其参数类型和返回类型JS中的 => 是一种定义函数的语法,是具体的函数实现函数类型声明还可以使用:接口、自定义类型等方式3.5.5 声明数组类型代码语言:javascript复制 let arr1: string[] // 规定了类型:数组内的每一项必须是字符串

let arr2: Array

arr1 = ["a","b","c"]

arr2 = ['hello','world']上述代码中的Array属于泛型

5.6 tuple元组(Tuple)是一种特殊的数组类型,可以存储固定数量的元素,并且每个元素的类型是已知的且可以不同。

元组用于精确描述一组值的类型,? 表示可选元素

代码语言:javascript复制let arr1: [string,number]

let arr2: [number,boolean?]

let arr3: [number,...string[]]

arr1 = ["hello",1]

arr2 = [100,false]

arr2 = [20]

arr3 = [100,"hello","world"]

arr3 = [100]5.7 enum 枚举(enum)可以定义一组命名常量,它能增强代码的可读性,也让代码更好维护

如下代码的功能是:根据调用walk时传入的不同参数,执行不同的逻辑。

存在的问题是调用walk时传参时没有任何提示,编码者很容易写错字符串内容,并且用于判断逻辑的up、down、left、right时连续且相关的一组值,那么这个时候**使用枚举(enum)**就非常的适用

代码语言:javascript复制function walk(str:string){

if(str === 'up'){

console.log("上");

}else if(str === 'down'){

console.log("下");

}else if(str === 'right'){

console.log("右");

}else if(str === 'left'){

console.log("左");

}else{

console.log("未知");

}

}

walk("up")

walk("down")

walk("right")

walk("left")5.7.1 数字枚举数字枚举一种最常见的枚举类型,其成员的值会自动递增,且数字枚举还具备反向映射的特点

代码语言:javascript复制enum Direction{

UP,

DOWN,

LEFT,

RIGHT

}

console.log(Direction)

/*

{

"0": "UP",

"1": "DOWN",

"2": "LEFT",

"3": "RIGHT",

"UP": 0,

"DOWN": 1,

"LEFT": 2,

"RIGHT": 3

}

*/

console.log(Direction.UP);// 0

console.log(Direction[0]);// UP

// 报错代码:

Direction.UP = 1 // 枚举中的值是只读的使用数字枚举完成walk函数的逻辑,可以发现:代码更加直观易读,而且类型安全,同时更加易于维护

代码语言:javascript复制function walk(data:Direction){

if(data === Direction.UP){

console.log("上");

}else if(data === Direction.DOWN){

console.log("下");

}else if(data === Direction.RIGHT){

console.log("右");

}else if(data === Direction.LEFT){

console.log("左");

}else{

console.log("未知");

}

}

walk(Direction.UP)

walk(Direction.DOWN)

walk(Direction.RIGHT)

walk(Direction.LEFT)5.7.2 字符串枚举枚举成员的值是字符串

代码语言:javascript复制enum Direction1{

UP1 = "UP",

DOWN1 = "DOWN",

LEFT1 = "LEFT",

RIGHT1 = "RIGHT"

}

/*

{

"UP": "UP",

"DOWN": "DOWN",

"LEFT": "LEFT",

"RIGHT": "RIGHT"

}

*/

console.log(Direction1)

let dir: Direction1 = Direction1.UP1

console.log(dir) // 输出:“UP”5.7.3 常量枚举 官方描述:常量枚举是一种特殊枚举类型,它使用const关键字定义,在编译时会被内联,避免生成一些额外的代码。

何为编译时内联?所谓 “内联”,其实就是 TypeScript 在编译时,会将枚举成员引用替换为它们的实际值,而不是生成额外的枚举对象。这可以减少生成的JS代码量,并提高运行时性能

5.8 typetype 可以为任意类型创建别名,让代码更简介,可读性更强,同时能更方便地进行类型复用和扩展。

5.8.1 基本用法 类型别名使用type关键字定义,type后跟类型名称,例如下面代码中的num是类型别名

代码语言:javascript复制type num = number

let price: num

price = 1005.8.2 联合类型 联合类型是一种高级类型,它表示一个值可以是几种不同的类型之一

代码语言:javascript复制type Area = {

height: number;

width: number;

}

type Address = {

num: number;

cell: number;

room: string;

}

// 代表test类型,只能是Area类型或者Address类型其中一种

type test = Area | Address

// 代表House类型,必须包含Area和Address两种类型

type House = Area & Address

let x: House = {

height: 100,

width: 20,

num: 1,

cell: 123,

room: "008"

}特殊点:

使用类型声明限制函数返回值为 void 时,TypeScript 并不会严格要求函数返回空

代码语言:javascript复制type LogFunc = () => void

const f1:LogFunc = function(){

return 66 // ?void不是只能接受返回undefined吗,怎么这里返回number类型不报错

} WHY?为什么可以这样?

其实是为了确保 Array.prototype.forEach 方法其回调的返回类型是void 保证能够正常运行

6. 类的相关知识代码语言:javascript复制class Person{

name: string;

age: number;

// 基本构造函数

constructor(name: string,age: number){

this.name = name

this.age = age

}

speak(){

console.log(`我叫:${this.name},今年${this.age}岁`);

}

}

class Student extends Person{

grade: string;

constructor(name: string,age: number,grade: string){

super(name,age) // 继承父类,必须使用super()方法

this.grade = grade

}

study(){

console.log(`${this.name} 正在努力学习中...`);

}

}

const s = new Student("张三",15,"一年级")

s.speak() // 我叫:张三,今年15岁

s.study() // 张三 正在努力学习中..

console.log(s);

/**

{

"name": "张三",

"age": 15,

"grade": "一年级"

}

*/

console.log(s.grade);// 一年级6.1 属性修饰符修饰符

含义

具体规则

public

公开的

可以被:类内部、子类、类外部访问

protected

受保护的

可以被:类内部、子类访问

private

私有的

可以被:类内部访问

readonly

只读属性

属性无法修改

6.1.1 public 修饰符代码语言:javascript复制class Person{

public name: string;

age: number;

// 基本构造函数

constructor(name: string,age: number){

this.name = name

this.age = age

}

speak(){

console.log(`我叫:${this.name},今年${this.age}岁`);

}

}

const p1 = new Person("张三",18)

// 类的外部,可以访问public修饰的属性

console.log(p1.name)6.1.2 属性简写模式:代码语言:javascript复制class Person {

name: string;

age: number;

constructor(name: string, age: number) {

this.name = name

this.age = age

}

}

////////////// 简写后 /////////////

class Person1 {

constructor(

public name: string,

public age: number

) {

}

}6.1.3 protected 修饰符代码语言:javascript复制class Person {

constructor(protected name: string,protected age: number) {}

protected getDetails(){

return `我叫:${this.name},年龄是:${this.age}`

}

introduce(){

console.log(this.getDetails);

}

}

const p1 = new Person("tom",18)

p1.introduce()

// 无法访问,因为这些属性都是受保护的(protected)

// p1.name

// p1.age

// p1.getDetails子类是否可以调用?

代码语言:javascript复制class Person {

constructor(protected name: string,protected age: number) {}

protected getDetails(){

return `我叫:${this.name},年龄是:${this.age}`

}

introduce(){

console.log(this.getDetails);

}

}

class Student extends Person{

study(){

this.introduce()

console.log(`${this.name}正在努力学习`);

}

}

const s1 = new Student("cat",10)

s1.study() 回答是不可以

6.1.4 private 修饰符代码语言:javascript复制class Person {

constructor(

protected name: string,

public age: number,

private IDCard: string

) {}

private getPrivateInfo(){

return `身份证号码为:${this.IDCard}`

}

getInfo(){

return `我叫:${this.name},今年刚满${this.name}岁`

}

getFullInfo(){

return this.getInfo+","+this.getPrivateInfo()

}

}

const p1 = new Person("tom",18,"1231231233441")

// p1.name // 无法访问 protected

// p1.age // 可访问

// p1.IDCard // 无法访问 private

console.log(p1.getInfo());

console.log(p1.getFullInfo());

// p1.getPrivateInfo(); // 无法使用 private6.1.5 readonly 修饰符说白了就是只读代码语言:javascript复制class Person {

constructor(

protected readonly name: string,

public readonly age: number,

private IDCard: string

) {}

}6.2 abstract 抽象类概述:

抽象类是一种无法被实例化的类,专门用来定义类的结构和行为,类中可以写抽象方法,也可以写具体实现,抽象类主要用来为其派生类提供一个基础结构,要求其派生类必须实现其中的抽象方法简记:

抽象类不能实例化,其意义是可以被继承,抽象类里可以有普通方法,也可以有抽象方法代码语言:javascript复制abstract class Animal{

constructor(

public name:string,

public age:number,

public type: string

){}

abstract shout(): string

do(){

console.log(`一只叫做${this.name}的${this.type}开始发出:${this.shout()}的声音`);

}

}

class Cat extends Animal{

constructor(

name:string,

age:number,

){ super(name,age,"猫") }

shout(): string {

return "喵~~";

}

}

const c1 = new Cat("蛋黄",3)

c1.do()什么时候使用抽象类?

定义通用接口:为一组相关的类定义通用的行为(方法或属性)时提供基础实现:在抽象类中提供某些方法或为其提供基础实现,这样派生类就可以继承这些实现确保关键实现:强制派生类实现一些关键行为共享代码和逻辑:当多个类需要共享部分代码时,抽象类可以避免代码重复6.3 interface 接口interface是一种定义结构的方式,主要作用是为:类、对象、函数等规定一种规范,这样可以确保代码的一致性和类型安全

但要注意interface只能定义格式,不能包含任何实现!

代码语言:javascript复制interface IPerson{

name: string,

age: number,

number(n:number):void

}

class Person implements IPerson{

constructor(

public name: string,

public age: number,

){}

number(n: number): void {

console.log(`测试:${n}`);

}

}

const p = new Person("张三",18)

p.number(12)同时,在TS中接口还可以当作对象使用

代码语言:javascript复制const p1: IPerson = {

name: "张三",

age: 18,

number: function (n: number): void {

console.log(`测试:${n}`);

}

}与其他语言不一样,TS里,接口名是可以重复的

官方叫做接口合并,意思是,相同接口名的接口都必须实现对应的属性

代码语言:javascript复制interface IPerson{

name: string,

age: number,

number(n:number):void

}

interface IPerson{

grender: string

}什么时候使用接口:

定义对象的格式:描述数据模型、API响应格式、配置对象…类的规范:规定一个类需要实现哪些属性和方法自动合并:一般用于扩展第三方库的类型6.3.1 interface 与 type 的区别相同点:interface 和 type 都可以用于定义对象结构,两者在许多场景中是可以互换的。不同点: interface:更专注于定义对象和类的结构,支持继承、合并type:可以定义类型别名、联合类型、交叉类型,但不支持继承和自动合并6.3.2 interface 与 抽象类 的区别相同点:都用于定义一个类的格式不相同: 接口:只能描述结构,不能有任何实现代码,一个类可以实现多个接口抽象类:既可以包含抽象方法,也可以包含具体方法,一个类只能继承一个抽象类7. 泛型泛型允许我们在定义函数、类或接口时,使用类型参数来表示未指定的类型,这些参数在具体使用时,才被制定具体的类型,泛型能让同一段代码适用于多种类型,同时仍然保持类型的安全性

代码语言:javascript复制const f = (a:T,b:U)=>{

console.log(a,b);

}

// 使用泛型,指定传入方法内的类型

f(1,"zhangsan")

f(1,22)泛型类:

代码语言:javascript复制class Person{

constructor(

public name: string,

public age: number,

public extraInfo: T

){}

speak(){

console.log(`我叫:${this.name}今年${this.age}岁了`);

console.log(this.extraInfo);

}

}

const p1 = new Person("tom",30,100)

type JobInfo = {

title: string,

company: string,

}

const p2 = new Person("tom",30,{title:"程序员",company:"华为"})在实例化对象时,定义了什么泛型类,就必须传入对应的类型数据

8. 类型声明文件类型声明文件时 TS 中的一种特殊文件,通常以.d.ts作为扩展名。

它的主要作用是为现有的JS代码提供类型信息,使得TS能够在使用这些JS库或模块时进行类型检查和提示

index.html代码语言:javascript复制

Document

index.ts代码语言:javascript复制import {add,mul} from './demo.js'

console.log(add(1,2));

console.log(mul(1,2));demo.js代码语言:javascript复制export function add(a,b){

return a+b;

}

export function mul(a,b){

return a*b;

}demo.d.ts 【类型声明文件】代码语言:javascript复制declare function add(a:number,b:number):number

declare function mul(a:number,b:number):number

export{add,mul};

相关推荐

膀 书法字典
base365

膀 书法字典

📅 08-19 👁️ 7802
韩国队悬了?世界杯前三周,孙兴慜眼眶骨折将接受手术
365娱乐游戏是什么

韩国队悬了?世界杯前三周,孙兴慜眼眶骨折将接受手术

📅 12-03 👁️ 8996
欧路词典|英汉-汉英词典 燧是什么意思
你们的365还进得去吗

欧路词典|英汉-汉英词典 燧是什么意思

📅 08-05 👁️ 1428